source: trunk/minix/commands/de/de.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

File size: 23.8 KB
Line 
1/****************************************************************/
2/* */
3/* de.c */
4/* */
5/* Main loop of the "Disk editor". */
6/* */
7/****************************************************************/
8/* origination 1989-Jan-15 Terrence W. Holm */
9/****************************************************************/
10
11
12#include <minix/config.h>
13#include <sys/types.h>
14#include <sys/dir.h>
15#include <sys/stat.h>
16#include <sys/wait.h>
17#include <ctype.h>
18#include <errno.h>
19#undef ERROR /* arrgghh, errno.h has this pollution */
20#include <fcntl.h>
21#include <limits.h>
22#include <signal.h>
23#include <stdarg.h>
24#include <stdlib.h>
25#include <string.h>
26#include <unistd.h>
27
28#include <minix/const.h>
29#include <minix/type.h>
30#include "../../servers/fs/const.h"
31#include "../../servers/fs/type.h"
32#include "../../servers/fs/inode.h"
33
34#include "de.h"
35
36static char copyright[] = "de (c) Terrence W. Holm 1989";
37
38
39_PROTOTYPE(void Push , (de_state *s ));
40_PROTOTYPE(int Get_Base , (int *base ));
41_PROTOTYPE(int Get_Filename , (de_state *s ));
42_PROTOTYPE(int Get_Count , (char *units , unsigned long *result ));
43_PROTOTYPE(void Exec_Shell , (void));
44_PROTOTYPE(void Sigint , (int));
45
46
47
48/****************************************************************/
49/* */
50/* main() */
51/* */
52/* Initialize. Handle the "-r" recovery option if */
53/* specified, else enter the main processing loop. */
54/* */
55/****************************************************************/
56
57
58void main( argc, argv )
59 int argc;
60 char *argv[];
61
62 {
63 static de_state s; /* it is safer not to put it on the stack
64 * and some things probably now rely on zero
65 * initialization
66 */
67 char *command_name = argv[0];
68 int recover = 0;
69
70
71 s.device_mode = O_RDONLY;
72
73
74 /* Parse arguments */
75
76 if ( argc == 3 && strcmp( argv[1], "-r" ) == 0 )
77 {
78 recover = 1;
79 --argc;
80 ++argv;
81 }
82 else if ( argc == 3 && strcmp( argv[1], "-w" ) == 0 )
83 {
84 s.device_mode = O_RDWR;
85 --argc;
86 ++argv;
87 }
88
89 if ( argc != 2 || *argv[1] == '-' )
90 {
91 fprintf( stderr, "Usage: %s [-w] /dev/device\n", command_name );
92 fprintf( stderr, " %s -r lost_file_name\n", command_name );
93 exit( 1 );
94 }
95
96
97 /* Set the effective id to the real id. This eliminates */
98 /* any increase in privilege done by a set-uid bit on the */
99 /* executable file. We want to be "root" for recovering */
100 /* files, because we must be able to read the device. */
101 /* However, in normal usage, de(1) should not let just */
102 /* anyone look at a file system, thus we drop the privilege. */
103 /* */
104 /* NOTE: There is a security hole when using "-r" with a */
105 /* set-uid de(1). Do not use set-uid root if there is any */
106 /* way to externally access your Minix system. */
107
108 if ( ! recover )
109 {
110 setuid( getuid() );
111 setgid( getgid() );
112 }
113
114
115 /* Set terminal characteristics, and ^C interrupt handler */
116
117 Save_Term();
118
119 if ( signal( SIGINT, SIG_IGN ) != SIG_IGN )
120 {
121 signal( SIGINT, Sigint );
122 signal( SIGQUIT, Sigint );
123 }
124
125 Set_Term();
126
127 if ( ! Init_Termcap() )
128 Error( "Requires a termcap entry" );
129
130
131
132 /* Get the device file name. If recovering, also open an output file. */
133
134 if ( recover )
135 {
136 char *dir_name;
137 char *file_name;
138 struct stat device_stat;
139 struct stat tmp_stat;
140
141 /* Split the path name into a directory and a file name. */
142
143 if ( strlen(argv[1]) > MAX_STRING )
144 Error( "Path name too long" );
145
146 if ( ! Path_Dir_File( argv[1], &dir_name, &file_name ) )
147 Error( "Recover aborted" );
148
149 /* Find the device holding the directory. */
150
151 if ( (s.device_name = File_Device( dir_name )) == NULL )
152 Error( "Recover aborted" );
153
154
155 /* The output file will be in /tmp with the same file name. */
156
157 strcpy( s.file_name, TMP );
158 strcat( s.file_name, "/" );
159 strcat( s.file_name, file_name );
160
161
162 /* Make sure /tmp is not on the same device as the file we */
163 /* are trying to recover (we don't want to use up the free */
164 /* i-node and blocks before we get a chance to recover them). */
165
166 if ( stat( s.device_name, &device_stat ) == -1 )
167 Error( "Can not stat(2) device %s", s.device_name );
168
169 if ( stat( TMP, &tmp_stat ) == -1 )
170 Error( "Can not stat(2) directory %s", TMP );
171
172 if ( device_stat.st_rdev == tmp_stat.st_dev )
173 Error( "Will not recover files on the same device as %s", TMP );
174
175 if ( access( s.file_name, F_OK ) == 0 )
176 Error( "Will not overwrite file %s", s.file_name );
177
178
179 /* Open the output file. */
180
181 if ( (s.file_f = fopen( s.file_name, "w" )) == NULL )
182 Error( "Can not open file %s", s.file_name );
183
184 /* Don't let anyone else look at the recovered file */
185
186 chmod( s.file_name, 0700 );
187
188 /* If running as root then change the owner of the */
189 /* restored file. If not running as root then the */
190 /* chown(2) will fail. */
191
192 chown( s.file_name, getuid(), getgid() );
193 }
194 else
195 {
196 s.device_name = argv[1];
197 s.file_name[ 0 ] = '\0';
198 }
199
200
201 /* Open the device file. */
202
203 {
204 struct stat device_stat;
205 off_t size;
206
207 if ( stat( s.device_name, &device_stat ) == -1 )
208 Error( "Can not find file %s", s.device_name );
209
210 if ( (device_stat.st_mode & S_IFMT) != S_IFBLK &&
211 (device_stat.st_mode & S_IFMT) != S_IFREG )
212 Error( "Can only edit block special or regular files" );
213
214
215 if ( (s.device_d = open( s.device_name, s.device_mode )) == -1 )
216 Error( "Can not open %s", s.device_name );
217
218 if ( (size = lseek( s.device_d, 0L, SEEK_END )) == -1 )
219 Error( "Error seeking %s", s.device_name );
220
221 if ( size % K != 0 )
222 {
223 Warning( "Device size is not a multiple of 1024" );
224 Warning( "The (partial) last block will not be accessible" );
225 }
226 }
227
228
229 /* Initialize the rest of the state record */
230
231 s.mode = WORD;
232 s.output_base = 10;
233 s.search_string[ 0 ] = '\0';
234
235 {
236 int i;
237
238 for ( i = 0; i < MAX_PREV; ++i )
239 {
240 s.prev_addr[ i ] = 0L;
241 s.prev_mode[ i ] = WORD;
242 }
243 }
244
245
246 sync();
247
248 Read_Super_Block( &s );
249
250 Read_Bit_Maps( &s );
251
252 s.address = 0L;
253
254
255
256 /* Recover mode basically performs an 'x' and an 'X' */
257
258 if ( recover )
259 {
260 ino_t inode = Find_Deleted_Entry( &s, argv[1] );
261 off_t size;
262
263 if ( inode == 0 )
264 {
265 unlink( s.file_name );
266 Error( "Recover aborted" );
267 }
268
269 s.address = ( (long) s.first_data - s.inode_blocks ) * K
270 + (long) (inode - 1) * s.inode_size;
271
272 Read_Block( &s, s.buffer );
273
274
275 /* Have found the lost i-node, now extract the blocks. */
276
277 if ( (size = Recover_Blocks( &s )) == -1L )
278 {
279 unlink( s.file_name );
280 Error( "Recover aborted" );
281 }
282
283 Reset_Term();
284
285 printf( "Recovered %ld bytes, written to file %s\n", size, s.file_name );
286
287 exit( 0 );
288 }
289
290
291 /* Enter the main loop, first time redraw the screen */
292 {
293 int rc = REDRAW;
294
295
296 do
297 {
298 if ( rc == REDRAW )
299 {
300 Read_Block( &s, s.buffer );
301 Draw_Screen( &s );
302 s.last_addr = s.address;
303 Draw_Pointers( &s );
304 }
305
306 else if ( rc == REDRAW_POINTERS )
307 {
308 s.offset = (unsigned) (s.address & ~ K_MASK);
309 Draw_Pointers( &s );
310 }
311
312 else if ( rc == ERROR )
313 {
314 Erase_Prompt();
315 putchar( BELL );
316 }
317 } while ( (rc = Process( &s, Arrow_Esc(Get_Char()) )) != EOF );
318 }
319
320
321 /* If there is an open output file that was never written to */
322 /* then remove its directory entry. This occurs when no 'w' */
323 /* or 'W' command occurred between a 'c' command and exiting */
324 /* the program. */
325
326 if ( s.file_name[0] != '\0' && ! s.file_written )
327 unlink( s.file_name );
328
329
330 Reset_Term(); /* Restore terminal characteristics */
331
332 exit( 0 );
333 }
334
335
336
337/****************************************************************/
338/* */
339/* Get_Base( base ) */
340/* */
341/* Get a new base value. */
342/* Returns REDRAW or ERROR. */
343/* */
344/****************************************************************/
345
346
347
348int Get_Base( base )
349 int *base;
350 {
351 switch ( Get_Char() )
352 {
353 case 'h' : *base = 16;
354 break;
355
356 case 'd' : *base = 10;
357 break;
358
359 case 'o' : *base = 8;
360 break;
361
362 case 'b' : *base = 2;
363 break;
364
365 default : return( ERROR );
366 }
367
368 return( REDRAW );
369 }
370
371
372
373/****************************************************************/
374/* */
375/* Process( state, input_char ) */
376/* */
377/* Determine the function requested by the */
378/* input character. Returns OK, REDRAW, */
379/* REDRAW_POINTERS, ERROR or EOF. */
380/* */
381/****************************************************************/
382
383
384int Process( s, c )
385 de_state *s;
386 int c;
387
388 {
389 switch ( c )
390 {
391 case 'b' : /* Back up one block */
392 case ESC_PGUP :
393
394 if ( s->address == 0 )
395 return( ERROR );
396
397 s->address = (s->address - K) & K_MASK;
398
399 return( REDRAW );
400
401
402 case 'B' : /* Back up to home */
403 case ESC_HOME :
404
405 if ( s->address == 0 )
406 return( OK );
407
408 Push( s );
409
410 s->address = 0L;
411
412 return( REDRAW );
413
414
415 case 'c' : /* Change file name */
416
417 {
418 int rc = Get_Filename( s );
419
420 return( rc == OK ? REDRAW : rc );
421 }
422
423
424 case 'd' : /* Down */
425 case ESC_DOWN :
426
427 {
428 s->last_addr = s->address;
429
430 switch ( s->mode )
431 {
432 case WORD : s->address += 2;
433
434 if ( (s->address & PAGE_MASK) == 0 )
435 return( REDRAW );
436
437 return( REDRAW_POINTERS );
438
439 case BLOCK : s->address += 64;
440
441 if ( (s->last_addr & K_MASK) !=
442 (s->address & K_MASK) )
443 return( REDRAW );
444
445 return( REDRAW_POINTERS );
446
447 case MAP : s->address += 256;
448
449 return( REDRAW );
450
451 default : Error( "Internal fault (mode)" );
452 }
453 }
454
455
456 case 'f' : /* Forward one block */
457 case ' ' :
458 case ESC_PGDN :
459
460 if ( s->block == s->device_size - 1 )
461 return( ERROR );
462
463 s->address = (s->address + K) & K_MASK;
464
465 return( REDRAW );
466
467
468 case 'F' : /* Forward to end */
469 case ESC_END :
470
471 {
472 off_t last_block = ( (long) s->device_size - 1 ) * K;
473
474 if ( s->address == last_block )
475 return( OK );
476
477 Push( s );
478
479 s->address = last_block;
480
481 return( REDRAW );
482 }
483
484
485 case 'g' : /* Goto block */
486
487 {
488 unsigned long block;
489
490 if ( Get_Count( "Block?", &block ) )
491 {
492 if ( block >= s->zones )
493 {
494 Warning( "Block number too large" );
495 return( REDRAW );
496 }
497
498 Push( s );
499
500 s->address = (off_t) block * K;
501
502 return( REDRAW );
503 }
504 else
505 return( ERROR );
506 }
507
508
509 case 'G' : /* Goto block indirect */
510
511 {
512 unsigned block = *( (word_t *) &s->buffer[ s->offset ] );
513
514 if ( s->mode != WORD )
515 {
516 Warning( "Must be in visual mode \"word\"" );
517 return( REDRAW );
518 }
519
520 if ( block >= s->zones )
521 {
522 Warning( "Block number too large" );
523 return( REDRAW );
524 }
525
526 Push( s );
527
528 s->mode = BLOCK;
529 s->address = (long) block * K;
530
531 return( REDRAW );
532 }
533
534
535 case 'h' : /* Help */
536 case '?' :
537
538 Draw_Help_Screen( s );
539
540 Wait_For_Key();
541
542 return( REDRAW );
543
544
545 case 'i' : /* Goto i-node */
546
547 {
548 unsigned long inode;
549
550 if ( Get_Count( "I-node?", &inode ) )
551 {
552 if ( inode < 1 || inode > s->inodes )
553 {
554 Warning( "Illegal i-node number" );
555 return( REDRAW );
556 }
557
558 Push( s );
559
560 s->mode = WORD;
561 s->address = (off_t) (s->first_data - s->inode_blocks) * K
562 + (off_t) (inode - 1) * s->inode_size;
563
564 return( REDRAW );
565 }
566 else
567 return( ERROR );
568 }
569
570
571 case 'I' : /* Filename to i-node */
572
573 {
574 ino_t inode;
575 char *filename;
576
577 Draw_Prompt( "File name?" );
578
579 filename = Get_Line();
580
581 if ( filename == NULL || filename[0] == '\0' )
582 return( ERROR );
583
584 inode = Find_Inode( s, filename );
585
586 if ( inode )
587 {
588 Push( s );
589
590 s->mode = WORD;
591 s->address = ( (long) s->first_data - s->inode_blocks ) * K
592 + (long) (inode - 1) * s->inode_size;
593 }
594
595 return( REDRAW );
596 }
597
598
599 case 'l' : /* Left */
600 case ESC_LEFT :
601
602 {
603 s->last_addr = s->address;
604
605 switch ( s->mode )
606 {
607 case WORD : s->address = s->address - 32;
608
609 return( REDRAW );
610
611 case BLOCK : s->address -= 1;
612
613 if ( (s->last_addr & K_MASK) !=
614 (s->address & K_MASK) )
615 return( REDRAW );
616
617 return( REDRAW_POINTERS );
618
619 case MAP : s->address -= 4;
620
621 if ( (s->last_addr & ~ MAP_MASK) !=
622 (s->address & ~ MAP_MASK) )
623 return( REDRAW );
624
625 return( REDRAW_POINTERS );
626
627 default : Error( "Internal fault (mode)" );
628 }
629 }
630
631
632 case 'm' : /* Invoke a Minix shell */
633
634 Reset_Term();
635
636 Exec_Shell();
637
638 Set_Term();
639
640 return( REDRAW );
641
642
643 case 'n' : /* Search for next */
644
645 {
646 off_t addr;
647
648 if ( s->search_string[0] == '\0' )
649 {
650 Warning( "No search string defined" );
651 return( REDRAW );
652 }
653
654 Draw_Prompt( "Searching..." );
655
656 if ( (addr = Search( s, s->search_string )) == -1L )
657 {
658 Warning( "Search string not found" );
659
660 Wait_For_Key();
661
662 return( REDRAW );
663 }
664
665 Push( s );
666 s->address = addr;
667
668 return( REDRAW );
669 }
670
671
672 case 'o' : /* Set output base */
673
674 Draw_Prompt( "Output base?" );
675
676 return( Get_Base( &s->output_base ) );
677
678
679 case 'p' : /* Previous address */
680
681 {
682 int i;
683
684 s->address = s->prev_addr[ 0 ];
685 s->mode = s->prev_mode[ 0 ];
686
687 for ( i = 0; i < MAX_PREV - 1; ++i )
688 {
689 s->prev_addr[ i ] = s->prev_addr[ i + 1 ];
690 s->prev_mode[ i ] = s->prev_mode[ i + 1 ];
691 }
692
693 return( REDRAW );
694 }
695
696
697 case 'q' : /* Quit */
698 case EOF :
699 case CTRL_D :
700
701 return( EOF );
702
703
704 case 'r' : /* Right */
705 case ESC_RIGHT :
706
707 {
708 s->last_addr = s->address;
709
710 switch ( s->mode )
711 {
712 case WORD : s->address += 32;
713
714 return( REDRAW );
715
716 case BLOCK : s->address += 1;
717
718 if ( (s->last_addr & K_MASK) !=
719 (s->address & K_MASK) )
720 return( REDRAW );
721
722 return( REDRAW_POINTERS );
723
724 case MAP : s->address += 4;
725
726 if ( (s->last_addr & ~ MAP_MASK) !=
727 (s->address & ~ MAP_MASK) )
728 return( REDRAW );
729
730 return( REDRAW_POINTERS );
731
732 default : Error( "Internal fault (mode)" );
733 }
734 }
735
736 case 's' : /* Store word */
737
738 {
739 unsigned long word;
740
741 if ( s->mode != WORD )
742 {
743 Warning( "Must be in visual mode \"word\"" );
744 return( REDRAW );
745 }
746
747 if ( s->device_mode == O_RDONLY )
748 {
749 Warning( "Use -w option to open device for writing" );
750 return( REDRAW );
751 }
752
753 if ( Get_Count( "Store word?", &word ) )
754 {
755 if ( word != (word_t) word )
756 {
757 Warning( "Word is more than 16 bits" );
758 return( REDRAW );
759 }
760 Write_Word( s, (word_t) word );
761
762 return( REDRAW );
763 }
764 else
765 return( ERROR );
766 }
767
768
769 case 'u' : /* Up */
770 case ESC_UP :
771
772 {
773 s->last_addr = s->address;
774
775 switch ( s->mode )
776 {
777 case WORD : s->address -= 2;
778
779 if ( (s->last_addr & PAGE_MASK) == 0 )
780 return( REDRAW );
781
782 return( REDRAW_POINTERS );
783
784 case BLOCK : s->address -= 64;
785
786 if ( (s->last_addr & K_MASK) !=
787 (s->address & K_MASK) )
788 return( REDRAW );
789
790 return( REDRAW_POINTERS );
791
792 case MAP : s->address -= 256;
793
794 return( REDRAW );
795
796 default : Error( "Internal fault (mode)" );
797 }
798 }
799
800
801 case 'v' : /* Visual mode */
802
803 Draw_Prompt( "Visual mode?" );
804
805 switch ( Get_Char() )
806 {
807 case 'w' : s->mode = WORD;
808 break;
809
810 case 'b' : s->mode = BLOCK;
811 break;
812
813 case 'm' : {
814 /* Assume user knows if map mode is possible
815 char *tty = ttyname( 0 );
816
817 if ( tty == NULL ||
818 strcmp( tty, "/dev/tty0" ) != 0 )
819 Warning( "Must be at console" );
820 else
821 */
822 s->mode = MAP;
823
824 break;
825 }
826
827 default : return( ERROR );
828 }
829
830 return( REDRAW );
831
832
833 case 'w' : /* Write ASCII block */
834
835 if ( s->file_name[0] == '\0' )
836 {
837 int rc = Get_Filename( s );
838
839 if ( rc != OK )
840 return( rc );
841 }
842
843 /* We have a successfully opened file */
844
845 /* Eliminate non-ASCII characters */
846 {
847 int i;
848 char buf[ K ];
849 char *from = s->buffer;
850 char *to = buf;
851
852 for ( i = 0; i < K; ++i, ++from )
853 {
854 *to = *from & 0x7f;
855
856 if ( *to != '\0' && *to != '\177' )
857 ++to;
858 }
859
860 if ( fwrite( buf, 1, (int)(to - buf), s->file_f ) != to - buf )
861 Warning( "Problem writing out buffer" );
862
863 s->file_written = 1;
864
865 return( REDRAW );
866 }
867
868
869 case 'W' : /* Write block exactly */
870
871 if ( s->file_name[0] == '\0' )
872 {
873 int rc = Get_Filename( s );
874
875 if ( rc != OK )
876 return( rc );
877 }
878
879 /* We have a successfully opened file */
880
881 if ( fwrite( s->buffer, 1, K, s->file_f ) != K )
882 Warning( "Problem writing out buffer" );
883
884 s->file_written = 1;
885
886 return( REDRAW );
887
888
889 case 'x' : /* eXtract lost entry */
890
891 {
892 ino_t inode;
893 char *filename;
894
895 Draw_Prompt( "Lost file name?" );
896
897 filename = Get_Line();
898
899 if ( filename == NULL || filename[0] == '\0' )
900 return( ERROR );
901
902 inode = Find_Deleted_Entry( s, filename );
903
904 if ( inode )
905 {
906 Push( s );
907
908 s->mode = WORD;
909 s->address = ( (long) s->first_data - s->inode_blocks ) * K
910 + (long) (inode - 1) * s->inode_size;
911 }
912
913 return( REDRAW );
914 }
915
916
917 case 'X' : /* eXtract lost blocks */
918
919 {
920 int rc;
921
922 if ( s->mode != WORD )
923 {
924 Warning( "Must be in visual mode \"word\"" );
925 return( REDRAW );
926 }
927
928
929 /* Force a new output file name. */
930
931 if ( (rc = Get_Filename( s )) != OK )
932 return( rc );
933
934
935 Draw_Strings( s );
936
937 Erase_Prompt();
938 Draw_Prompt( "Recovering..." );
939
940 if ( Recover_Blocks( s ) == -1L )
941 unlink( s->file_name );
942
943 /* Force closure of output file. */
944
945 fclose( s->file_f );
946 s->file_name[ 0 ] = '\0';
947
948 return( REDRAW );
949 }
950
951
952 case '/' : /* Search */
953 case ESC_PLUS :
954
955 {
956 off_t addr;
957 char *string;
958
959 Draw_Prompt( "Search string?" );
960
961 string = Get_Line();
962
963 if ( string == NULL )
964 return( ERROR );
965
966 if ( string[0] != '\0' )
967 {
968 strcpy( s->search_string, string );
969 Draw_Strings( s );
970 }
971
972 else if ( s->search_string[0] == '\0' )
973 {
974 Warning( "No search string defined" );
975 return( REDRAW );
976 }
977
978 Erase_Prompt();
979 Draw_Prompt( "Searching..." );
980
981 if ( (addr = Search( s, s->search_string )) == -1L )
982 {
983 Warning( "Search string not found" );
984
985 Wait_For_Key();
986
987 return( REDRAW );
988 }
989
990 Push( s );
991
992 s->mode = BLOCK;
993 s->address = addr;
994
995 return( REDRAW );
996 }
997
998
999 default:
1000 return( ERROR );
1001 }
1002 }
1003
1004
1005
1006
1007
1008
1009/****************************************************************/
1010/* */
1011/* Push( state ) */
1012/* */
1013/* Push current address and mode, used by the */
1014/* commands B, F, g, G, i, I, n, x and /. This */
1015/* information is popped by the 'p' command. */
1016/* */
1017/****************************************************************/
1018
1019
1020void Push( s )
1021 de_state *s;
1022
1023 {
1024 int i;
1025
1026 for ( i = MAX_PREV - 1; i > 0; --i )
1027 {
1028 s->prev_addr[ i ] = s->prev_addr[ i - 1 ];
1029 s->prev_mode[ i ] = s->prev_mode[ i - 1 ];
1030 }
1031
1032 s->prev_addr[ 0 ] = s->address;
1033 s->prev_mode[ 0 ] = s->mode;
1034 }
1035
1036
1037
1038
1039
1040
1041/****************************************************************/
1042/* */
1043/* Get_Filename( state ) */
1044/* */
1045/* Read and check a filename. */
1046/* */
1047/****************************************************************/
1048
1049
1050int Get_Filename( s )
1051 de_state *s;
1052
1053 {
1054 char *filename;
1055 char *name;
1056 FILE *f;
1057
1058 Draw_Prompt( "File name?" );
1059
1060 filename = Get_Line();
1061
1062 if ( filename == NULL || filename[0] == '\0' )
1063 return( ERROR );
1064
1065
1066 for ( name = filename; *name != '\0'; ++name )
1067 if ( ! isgraph( *name ) )
1068 {
1069 Warning( "File name contains non-graphic characters" );
1070 return( REDRAW );
1071 }
1072
1073
1074 if ( access( filename, F_OK ) == 0 )
1075 {
1076 Warning( "Will not overwrite file %s", filename );
1077 return( REDRAW );
1078 }
1079
1080 if ( (f = fopen( filename, "w" )) == NULL )
1081 {
1082 Warning( "Can not open file %s", filename );
1083 return( REDRAW );
1084 }
1085
1086 /* If there is already an open output file then */
1087 /* close it. If it was never written to then */
1088 /* remove its directory entry. */
1089
1090 if ( s->file_name[0] != '\0' )
1091 {
1092 if ( ! s->file_written )
1093 unlink( s->file_name );
1094
1095 fclose( s->file_f );
1096 }
1097
1098 strcpy( s->file_name, filename );
1099 s->file_f = f;
1100 s->file_written = 0;
1101
1102 return( OK );
1103 }
1104
1105
1106
1107
1108
1109
1110/****************************************************************/
1111/* */
1112/* Get_Count() */
1113/* */
1114/* Read and check a number. Returns non-zero */
1115/* if successful. */
1116/* */
1117/****************************************************************/
1118
1119
1120int Get_Count( units, result )
1121 char *units;
1122 unsigned long *result;
1123
1124 {
1125 char *number;
1126
1127 Draw_Prompt( units );
1128
1129 number = Get_Line();
1130
1131 if ( number == NULL || number[0] == '\0' )
1132 return( 0 );
1133
1134 errno = 0;
1135 *result = strtoul( number, (char **) NULL, 0 );
1136 return( errno == 0 );
1137 }
1138
1139
1140
1141
1142
1143
1144/****************************************************************/
1145/* */
1146/* In_Use( bit, map ) */
1147/* */
1148/* Is the bit set in the map? */
1149/* */
1150/****************************************************************/
1151
1152
1153int In_Use( bit, map )
1154 bit_t bit;
1155 bitchunk_t *map;
1156
1157 {
1158 return( map[ (int) (bit / (CHAR_BIT * sizeof (bitchunk_t))) ] &
1159 (1 << ((unsigned) bit % (CHAR_BIT * sizeof (bitchunk_t)))) );
1160 }
1161
1162
1163
1164
1165
1166
1167/****************************************************************/
1168/* */
1169/* Find_Inode( state, filename ) */
1170/* */
1171/* Find the i-node for the given file name. */
1172/* */
1173/****************************************************************/
1174
1175
1176ino_t Find_Inode( s, filename )
1177 de_state *s;
1178 char *filename;
1179
1180 {
1181 struct stat device_stat;
1182 struct stat file_stat;
1183 ino_t inode;
1184
1185
1186 if ( fstat( s->device_d, &device_stat ) == -1 )
1187 Error( "Can not fstat(2) file system device" );
1188
1189#ifdef S_IFLNK
1190 if ( lstat( filename, &file_stat ) == -1 )
1191#else
1192 if ( stat( filename, &file_stat ) == -1 )
1193#endif
1194 {
1195 Warning( "Can not find file %s", filename );
1196 return( 0 );
1197 }
1198
1199 if ( device_stat.st_rdev != file_stat.st_dev )
1200 {
1201 Warning( "File is not on device %s", s->device_name );
1202 return( 0 );
1203 }
1204
1205
1206 inode = file_stat.st_ino;
1207
1208 if ( inode < 1 || inode > s->inodes )
1209 {
1210 Warning( "Illegal i-node number" );
1211 return( 0 );
1212 }
1213
1214 return( inode );
1215 }
1216
1217
1218
1219
1220
1221
1222/****************************************************************/
1223/* */
1224/* Exec_Shell() */
1225/* */
1226/* Fork off a sub-process to exec() the shell. */
1227/* */
1228/****************************************************************/
1229
1230
1231void Exec_Shell()
1232
1233 {
1234 int pid = fork();
1235
1236 if ( pid == -1 )
1237 return;
1238
1239
1240 if ( pid == 0 )
1241 {
1242 /* The child process */
1243
1244 extern char **environ;
1245 char *shell = getenv( "SHELL" );
1246
1247 if ( shell == NULL )
1248 shell = "/bin/sh";
1249
1250 execle( shell, shell, (char *) 0, environ );
1251
1252 perror( shell );
1253 exit( 127 );
1254 }
1255
1256
1257 /* The parent process: ignore signals, wait for sub-process */
1258
1259 signal( SIGINT, SIG_IGN );
1260 signal( SIGQUIT, SIG_IGN );
1261
1262 {
1263 int status;
1264 int w;
1265
1266 while ( (w=wait(&status)) != pid && w != -1 );
1267 }
1268
1269 signal( SIGINT, Sigint );
1270 signal( SIGQUIT, Sigint );
1271
1272 return;
1273 }
1274
1275
1276
1277
1278
1279
1280/****************************************************************/
1281/* */
1282/* Sigint() */
1283/* */
1284/* Terminate the program on an interrupt (^C) */
1285/* or quit (^\) signal. */
1286/* */
1287/****************************************************************/
1288
1289
1290void Sigint(n)
1291int n;
1292 {
1293 Reset_Term(); /* Restore terminal characteristics */
1294
1295 putchar( '\n' );
1296
1297 exit( 1 );
1298 }
1299
1300
1301
1302
1303
1304
1305/****************************************************************/
1306/* */
1307/* Error( text, ... ) */
1308/* */
1309/* Print an error message on stderr. */
1310/* */
1311/****************************************************************/
1312
1313
1314#if __STDC__
1315void Error( const char *text, ... )
1316#else
1317void Error( text )
1318 char *text;
1319#endif
1320
1321 {
1322 va_list argp;
1323
1324 Reset_Term();
1325
1326 fprintf( stderr, "\nde: " );
1327 va_start( argp, text );
1328 vfprintf( stderr, text, argp );
1329 va_end( argp );
1330 if ( errno != 0 )
1331 fprintf( stderr, ": %s", strerror( errno ) );
1332 fprintf( stderr, "\n" );
1333
1334 exit( 1 );
1335 }
Note: See TracBrowser for help on using the repository browser.