|
|
1.1 root 1: /* @(#)fsdb.c 1.4 */
2:
3: /* fsdb - file system debugger */
4:
5: /* usage: fsdb [options] special
6: * options:
7: * -? display usage
8: * -o override some error conditions
9: * -p"string" set prompt to string
10: * -w open for write
11: */
12:
13: #include <sys/param.h>
14: #include <signal.h>
15: #include <sys/fs.h>
16: #include <sys/inode.h>
17: #include <sys/dir.h>
18: #include <sys/file.h>
19: #include <stdio.h>
20: #include <setjmp.h>
21:
22: /*
23: * Never changing defines.
24: */
25: #define OCTAL 8 /* octal base */
26: #define DECIMAL 10 /* decimal base */
27: #define HEX 16 /* hexadecimal base */
28:
29: /*
30: * Adjustable defines.
31: */
32: #define NBUF 10 /* number of cache buffers */
33: #define PROMPTSIZE 80 /* size of user definable prompt */
34: #define MAXFILES 40000 /* max number of files ls can handle */
35: #define FIRST_DEPTH 10 /* default depth for find and ls */
36: #define SECOND_DEPTH 100 /* second try at depth (maximum) */
37: #define INPUTBUFFER 1040 /* size of input buffer */
38: #define BYTESPERLINE 16 /* bytes per line of /dxo output */
39: #define NREG 36 /* number of save registers */
40:
41: /*
42: * Values dependent on sizes of structs and such.
43: */
44: #define NUMB 3 /* these three are arbitrary, */
45: #define BLOCK 5 /* but must be different from */
46: #define FRAGMENT 7 /* the rest (hence odd). */
47: #define BITSPERCHAR 8 /* couldn't find it anywhere */
48: #define CHAR (sizeof (char))
49: #define SHORT (sizeof (short))
50: #define LONG (sizeof (long))
51: #define INODE (sizeof (struct dinode))
52: #define DIRECTORY (sizeof (struct direct))
53: #define CGRP (sizeof (struct cg))
54: #define SB (sizeof (struct fs))
55: #define BLKSIZE (fs->fs_bsize) /* for clarity */
56: #define FRGSIZE (fs->fs_fsize)
57: #define BLKSHIFT (fs->fs_bshift)
58: #define FRGSHIFT (fs->fs_fshift)
59:
60: /*
61: * Messy macros that would otherwise clutter up such glamorous code.
62: */
63: #define itob(i) ((itod(fs, (i)) << FRGSHIFT) + itoo(fs, (i)) * INODE)
64: #define min(x, y) ((x) < (y) ? (x) : (y))
65: #define STRINGSIZE(d) ((long)d->d_reclen - \
66: ((long)&d->d_name[0] - (long)&d->d_ino))
67: #define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\
68: (((c) >= 'A')&&((c) <= 'Z')))
69: #define digit(c) (((c) >= '0') && ((c) <= '9'))
70: #define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F'))
71: #define hexletter(c) (((c) >= 'a') && ((c) <= 'f'))
72: #define octaldigit(c) (((c) >= '0') && ((c) <= '7'))
73: #define uppertolower(c) ((c) - 'A' + 'a')
74: #define hextodigit(c) ((c) - 'a' + 10)
75: #define numtodigit(c) ((c) - '0')
76: #define loword(X) (((ushort *)&X)[1])
77: #define lobyte(X) (((unsigned char *)&X)[1])
78:
79: /*
80: * buffer cache structure.
81: */
82: struct buf {
83: struct buf *fwd;
84: struct buf *back;
85: char *blkaddr;
86: short valid;
87: long blkno;
88: } buf[NBUF], bhdr;
89:
90: /*
91: * used to hold save registers (see '<' and '>').
92: */
93: struct save_registers {
94: long sv_addr;
95: long sv_value;
96: long sv_objsz;
97: } regs[NREG];
98:
99: /*
100: * cd, find, and ls use this to hold filenames. Each filename is broken
101: * up by a slash. In other words, /usr/src/adm would have a len field
102: * of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
103: * src, and adm components of the pathname.
104: */
105: struct filenames {
106: long ino; /* inode */
107: long len; /* number of components */
108: char flag; /* flag if using SECOND_DEPTH allocator */
109: char find; /* flag if found by find */
110: char **fname; /* hold components of pathname */
111: } *filenames, *top;
112:
113: struct fs filesystem, *fs; /* super block */
114:
115: /*
116: * Global data.
117: */
118: char *input_path[MAXPATHLEN];
119: char *stack_path[MAXPATHLEN];
120: char *current_path[MAXPATHLEN];
121: char input_buffer[INPUTBUFFER];
122: char *prompt;
123: char *buffers;
124: char scratch[64];
125: char BASE[] = "o u x";
126: char PROMPT[PROMPTSIZE] = "> ";
127: char laststyle = '/';
128: char lastpo = 'x';
129: short input_pointer;
130: short current_pathp;
131: short stack_pathp;
132: short input_pathp;
133: short cmp_level;
134: short nfiles;
135: short type = NUMB;
136: short dirslot;
137: short fd;
138: short c_count;
139: short error;
140: short paren;
141: short trapped;
142: short doing_cd;
143: short doing_find;
144: short find_by_name;
145: short find_by_inode;
146: short long_list;
147: short recursive;
148: short objsz = SHORT;
149: short override = 0;
150: short wrtflag;
151: short base = HEX;
152: short acting_on_inode;
153: short acting_on_directory;
154: short should_print = 1;
155: short clear;
156: short star;
157: long addr;
158: long bod_addr;
159: long value;
160: long erraddr;
161: long errcur_bytes;
162: long errino;
163: long errinum;
164: long cur_cgrp;
165: long cur_ino;
166: long cur_inum;
167: long cur_dir;
168: long cur_block;
169: long cur_bytes;
170: long find_ino;
171: long filesize;
172: long blocksize;
173: long stringsize;
174: long count = 1;
175: long commands;
176: long read_requests;
177: long actual_disk_reads;
178: jmp_buf env;
179:
180: extern char *malloc(), *calloc();
181: char getachar();
182: char *getblk(), *fmtentry();
183: int err();
184: long get(), bmap(), expr(), term(), getnumb();
185: unsigned long *print_check();
186:
187: /*
188: * main - lines are read up to the unprotected ('\') newline and
189: * held in an input buffer. Characters may be read from the
190: * input buffer using getachar() and unread using ungetachar().
191: * Reading the whole line ahead allows the use of debuggers
192: * which would otherwise be impossible since the debugger
193: * and fsdb could not share stdin.
194: */
195:
196: main(argc,argv)
197: short argc;
198: char **argv;
199: {
200:
201: register char c, *cptr;
202: register short i, j, *iptr;
203: register struct direct *dirp;
204: register struct buf *bp;
205: struct filenames *fn;
206: char *progname;
207: short colon, mode;
208: long temp;
209: unsigned block;
210: int ffcmp();
211:
212: setbuf(stdin, NULL);
213:
214: progname = argv[0];
215: prompt = &PROMPT[0];
216: /*
217: * Parse options.
218: */
219: while (argc>1 && argv[1][0] == '-') {
220: if (strcmp("-?", argv[1]) == 0)
221: goto usage;
222: if (strcmp("-o", argv[1]) == 0) {
223: printf("error checking off\n");
224: override = 1;
225: argc--; argv++;
226: continue;
227: }
228: if (strncmp("-p", argv[1],2) == 0) {
229: prompt = &argv[1][2];
230: argc--; argv++;
231: continue;
232: }
233: if (strcmp("-w", argv[1]) == 0) {
234: wrtflag = 2; /* suitable for open */
235: argc--; argv++;
236: continue;
237: }
238: }
239: if (argc!=2) {
240: usage:
241: printf("usage: %s [options] special\n", progname);
242: printf("options:\n");
243: printf("\t-? display usage\n");
244: printf("\t-o override some error conditions\n");
245: printf("\t-p\"string\" set prompt to string\n");
246: printf("\t-w open for write\n");
247: exit(1);
248: }
249: /*
250: * Attempt to open the special file.
251: */
252: if ((fd = open(argv[1],wrtflag)) < 0) {
253: perror(argv[1]);
254: exit(1);
255: }
256: /*
257: * Read in the super block and validate (not too picky).
258: */
259: if (lseek(fd, SBLOCK * DEV_BSIZE, 0) == -1) {
260: perror(argv[1]);
261: exit(1);
262: }
263: if (read(fd, &filesystem, sizeof filesystem) != sizeof filesystem) {
264: printf("%s: cannot read superblock\n", argv[1]);
265: exit(1);
266: }
267: fs = &filesystem;
268: if (fs->fs_magic != FS_MAGIC) {
269: printf("%s: Bad magic number in file system\n", argv[1]);
270: exit(1);
271: }
272: printf("fsdb of %s %s -- last mounted on %s\n",
273: argv[1], wrtflag ? "(Opened for write)" : "(Read only)",
274: &fs->fs_fsmnt[0]);
275: /*
276: * Malloc buffers and set up cache.
277: */
278: buffers = malloc(NBUF * BLKSIZE);
279: bhdr.fwd = bhdr.back = &bhdr;
280: for (i=0; i<NBUF; i++) {
281: bp = &buf[i];
282: bp->blkaddr = buffers + (i * BLKSIZE);
283: bp->valid = 0;
284: insert(bp);
285: }
286: /*
287: * Malloc filenames structure. The space for the actual filenames
288: * is allocated as it needs it.
289: */
290: filenames = (struct filenames *)calloc(MAXFILES,
291: sizeof (struct filenames));
292: if (filenames == NULL) {
293: printf("out of memory\n");
294: exit(1);
295: }
296:
297: fn = filenames;
298:
299: restore_inode(2);
300: /*
301: * Malloc a few filenames (needed by pwd for example).
302: */
303: for (i = 0; i < MAXPATHLEN; i++) {
304: input_path[i] = calloc(1, MAXNAMLEN);
305: stack_path[i] = calloc(1, MAXNAMLEN);
306: current_path[i] = calloc(1, MAXNAMLEN);
307: if (current_path[i] == NULL) {
308: printf("out of memory\n");
309: exit(1);
310: }
311: }
312: current_pathp = -1;
313:
314: signal(2,err);
315: setjmp(env);
316:
317: getnextinput();
318: /*
319: * Main loop and case statement. If an error condition occurs
320: * initialization and recovery is attempted.
321: */
322: for (;;) {
323: if (error) {
324: freemem(filenames, nfiles);
325: nfiles = 0;
326: c_count = 0;
327: count = 1;
328: star = 0;
329: error = 0;
330: paren = 0;
331: acting_on_inode = 0;
332: acting_on_directory = 0;
333: should_print = 1;
334: addr = erraddr;
335: cur_ino = errino;
336: cur_inum = errinum;
337: cur_bytes = errcur_bytes;
338: printf("?\n");
339: getnextinput();
340: if (error)
341: continue;
342: }
343: c_count++;
344:
345: switch (c = getachar()) {
346:
347: case '\n': /* command end */
348: freemem(filenames, nfiles);
349: nfiles = 0;
350: if (should_print && laststyle == '=') {
351: ungetachar(c);
352: goto calc;
353: }
354: if (c_count == 1) {
355: clear = 0;
356: should_print = 1;
357: erraddr = addr;
358: errino = cur_ino;
359: errinum = cur_inum;
360: errcur_bytes = cur_bytes;
361: switch (objsz) {
362: case DIRECTORY:
363: if ((addr =
364: getdirslot(dirslot+1)) == 0)
365: should_print = 0;
366: if (error) {
367: ungetachar(c);
368: continue;
369: }
370: break;
371: case INODE:
372: cur_inum++;
373: addr = itob(cur_inum);
374: if (!icheck(addr)) {
375: cur_inum--;
376: should_print = 0;
377: }
378: break;
379: case CGRP:
380: case SB:
381: cur_cgrp++;
382: if ((addr=cgrp_check(cur_cgrp)) == 0) {
383: cur_cgrp--;
384: continue;
385: }
386: break;
387: default:
388: addr += objsz;
389: cur_bytes += objsz;
390: if (valid_addr() == 0)
391: continue;
392: }
393: }
394: if (type == NUMB)
395: trapped = 0;
396: if (should_print)
397: switch (objsz) {
398: case DIRECTORY:
399: fprnt('?', 'd');
400: break;
401: case INODE:
402: fprnt('?', 'i');
403: if (!error)
404: cur_ino = addr;
405: break;
406: case CGRP:
407: fprnt('?', 'c');
408: break;
409: case SB:
410: fprnt('?', 's');
411: break;
412: case CHAR:
413: case SHORT:
414: case LONG:
415: fprnt(laststyle, lastpo);
416: }
417: if (error) {
418: ungetachar(c);
419: continue;
420: }
421: c_count = colon = acting_on_inode = 0;
422: acting_on_directory = 0;
423: should_print = 1;
424: getnextinput();
425: if (error)
426: continue;
427: erraddr = addr;
428: errino = cur_ino;
429: errinum = cur_inum;
430: errcur_bytes = cur_bytes;
431: continue;
432:
433: case '(': /* numeric expression or unknown command */
434: default:
435: colon = 0;
436: if (digit(c) || c == '(') {
437: ungetachar(c);
438: addr = expr();
439: type = NUMB;
440: value = addr;
441: continue;
442: }
443: printf("unknown command or bad syntax\n");
444: error++;
445: continue;
446:
447: case '?': /* general print facilities */
448: case '/':
449: fprnt(c, getachar());
450: continue;
451:
452: case ';': /* command separator and . */
453: case '\t':
454: case ' ':
455: case '.':
456: continue;
457:
458: case ':': /* command indicator */
459: colon++;
460: commands++;
461: should_print = 0;
462: stringsize = 0;
463: trapped = 0;
464: continue;
465:
466: case ',': /* count indicator */
467: colon = star = 0;
468: if ((c = getachar()) == '*') {
469: star = 1;
470: count = BLKSIZE;
471: } else {
472: ungetachar(c);
473: count = expr();
474: if (error)
475: continue;
476: if (!count)
477: count = 1;
478: }
479: clear = 0;
480: continue;
481:
482: case '+': /* address addition */
483: colon = 0;
484: c = getachar();
485: ungetachar(c);
486: if (c == '\n')
487: temp = 1;
488: else {
489: temp = expr();
490: if (error)
491: continue;
492: }
493: erraddr = addr;
494: errcur_bytes = cur_bytes;
495: switch (objsz) {
496: case DIRECTORY:
497: addr = getdirslot(dirslot + temp);
498: if (error)
499: continue;
500: break;
501: case INODE:
502: cur_inum += temp;
503: addr = itob(cur_inum);
504: if (!icheck(addr)) {
505: cur_inum -= temp;
506: continue;
507: }
508: break;
509: case CGRP:
510: case SB:
511: cur_cgrp += temp;
512: if ((addr = cgrp_check(cur_cgrp)) == 0) {
513: cur_cgrp -= temp;
514: continue;
515: }
516: break;
517: default:
518: laststyle = '/';
519: addr += temp * objsz;
520: cur_bytes += temp * objsz;
521: if (valid_addr() == 0)
522: continue;
523: }
524: value = get(objsz);
525: continue;
526:
527: case '-': /* address subtraction */
528: colon = 0;
529: c = getachar();
530: ungetachar(c);
531: if (c == '\n')
532: temp = 1;
533: else {
534: temp = expr();
535: if (error)
536: continue;
537: }
538: erraddr = addr;
539: errcur_bytes = cur_bytes;
540: switch (objsz) {
541: case DIRECTORY:
542: addr = getdirslot(dirslot - temp);
543: if (error)
544: continue;
545: break;
546: case INODE:
547: cur_inum -= temp;
548: addr = itob(cur_inum);
549: if (!icheck(addr)) {
550: cur_inum += temp;
551: continue;
552: }
553: break;
554: case CGRP:
555: case SB:
556: cur_cgrp -= temp;
557: if ((addr = cgrp_check(cur_cgrp)) == 0) {
558: cur_cgrp += temp;
559: continue;
560: }
561: break;
562: default:
563: laststyle = '/';
564: addr -= temp * objsz;
565: cur_bytes -= temp * objsz;
566: if (valid_addr() == 0)
567: continue;
568: }
569: value = get(objsz);
570: continue;
571:
572: case '*': /* address multiplication */
573: colon = 0;
574: temp = expr();
575: if (error)
576: continue;
577: if (objsz != INODE && objsz != DIRECTORY)
578: laststyle = '/';
579: addr *= temp;
580: value = get(objsz);
581: continue;
582:
583: case '%': /* address division */
584: colon = 0;
585: temp = expr();
586: if (error)
587: continue;
588: if (!temp) {
589: printf("divide by zero\n");
590: error++;
591: continue;
592: }
593: if (objsz != INODE && objsz != DIRECTORY)
594: laststyle = '/';
595: addr /= temp;
596: value = get(objsz);
597: continue;
598:
599: case '=': { /* assignment operation */
600: short tbase = base;
601:
602: calc:
603: c = getachar();
604: if (c == '\n') {
605: ungetachar(c);
606: c = lastpo;
607: if (acting_on_inode == 1) {
608: if (c != 'o' && c != 'd' && c != 'x' &&
609: c != 'O' && c != 'D' && c != 'X') {
610: switch (objsz) {
611: case LONG:
612: c = lastpo = 'X';
613: break;
614: case SHORT:
615: c = lastpo = 'x';
616: break;
617: case CHAR:
618: c = lastpo = 'c';
619: }
620: }
621: } else {
622: if (acting_on_inode == 2)
623: c = lastpo = 't';
624: }
625: } else if (acting_on_inode)
626: lastpo = c;
627: should_print = star = 0;
628: count = 1;
629: erraddr = addr;
630: errcur_bytes = cur_bytes;
631: switch (c) {
632: case '"': /* character string */
633: if (type == NUMB) {
634: blocksize = BLKSIZE;
635: filesize = BLKSIZE * 2;
636: cur_bytes = blkoff(fs, addr);
637: if (objsz==DIRECTORY || objsz==INODE)
638: lastpo = 'X';
639: }
640: puta();
641: continue;
642: case '+': /* =+ operator */
643: temp = expr();
644: value = get(objsz);
645: if (!error)
646: put(value+temp,objsz);
647: continue;
648: case '-': /* =- operator */
649: temp = expr();
650: value = get(objsz);
651: if (!error)
652: put(value-temp,objsz);
653: continue;
654: case 'b':
655: case 'c':
656: if (objsz == CGRP)
657: fprnt('?', c);
658: else
659: fprnt('/', c);
660: continue;
661: case 'i':
662: addr = cur_ino;
663: fprnt('?', 'i');
664: continue;
665: case 's':
666: fprnt('?', 's');
667: continue;
668: case 't':
669: case 'T':
670: laststyle = '=';
671: printf("\t\t");
672: printf("%s", ctime(&value));
673: continue;
674: case 'o':
675: base = OCTAL;
676: goto otx;
677: case 'd':
678: if (objsz == DIRECTORY) {
679: addr = cur_dir;
680: fprnt('?', 'd');
681: continue;
682: }
683: base = DECIMAL;
684: goto otx;
685: case 'x':
686: base = HEX;
687: otx:
688: laststyle = '=';
689: printf("\t\t");
690: if (acting_on_inode)
691: print(value & 0177777L, 12, -8, 0);
692: else
693: print(addr & 0177777L, 12, -8, 0);
694: printf("\n");
695: base = tbase;
696: continue;
697: case 'O':
698: base = OCTAL;
699: goto OTX;
700: case 'D':
701: base = DECIMAL;
702: goto OTX;
703: case 'X':
704: base = HEX;
705: OTX:
706: laststyle = '=';
707: printf("\t\t");
708: if (acting_on_inode)
709: print(value, 12, -8, 0);
710: else
711: print(addr, 12, -8, 0);
712: printf("\n");
713: base = tbase;
714: continue;
715: default: /* regular assignment */
716: ungetachar(c);
717: value = expr();
718: if (error)
719: printf("syntax error\n");
720: else
721: put(value,objsz);
722: continue;
723: }
724: }
725:
726: case '>': /* save current address */
727: colon = 0;
728: should_print = 0;
729: c = getachar();
730: if (!letter(c) && !digit(c)) {
731: printf("invalid register specification, ");
732: printf("must be letter or digit\n");
733: error++;
734: continue;
735: }
736: if (letter(c)) {
737: if (c < 'a')
738: c = uppertolower(c);
739: c = hextodigit(c);
740: } else
741: c = numtodigit(c);
742: regs[c].sv_addr = addr;
743: regs[c].sv_value = value;
744: regs[c].sv_objsz = objsz;
745: continue;
746:
747: case '<': /* restore saved address */
748: colon = 0;
749: should_print = 0;
750: c = getachar();
751: if (!letter(c) && !digit(c)) {
752: printf("invalid register specification, ");
753: printf("must be letter or digit\n");
754: error++;
755: continue;
756: }
757: if (letter(c)) {
758: if (c < 'a')
759: c = uppertolower(c);
760: c = hextodigit(c);
761: } else
762: c = numtodigit(c);
763: addr = regs[c].sv_addr;
764: value = regs[c].sv_value;
765: objsz = regs[c].sv_objsz;
766: continue;
767:
768: case 'a':
769: if (colon)
770: colon = 0;
771: else
772: goto no_colon;
773: if (match("at", 2)) { /* access time */
774: acting_on_inode = 2;
775: should_print = 1;
776: addr = (long)
777: &((struct dinode *)cur_ino)->di_atime;
778: value = get(LONG);
779: type = NULL;
780: continue;
781: }
782: goto bad_syntax;
783:
784: case 'b':
785: if (colon)
786: colon = 0;
787: else
788: goto no_colon;
789: if (match("block", 2)) { /* block conversion */
790: if (type == NUMB) {
791: value = addr;
792: cur_bytes = 0;
793: blocksize = BLKSIZE;
794: filesize = BLKSIZE * 2;
795: }
796: addr = value << FRGSHIFT;
797: bod_addr = addr;
798: value = get(LONG);
799: type = BLOCK;
800: dirslot = 0;
801: trapped++;
802: continue;
803: }
804: if (match("bs", 2)) { /* block size */
805: acting_on_inode = 1;
806: should_print = 1;
807: if (icheck(cur_ino) == 0)
808: continue;
809: addr = (long)
810: &((struct dinode *)cur_ino)->di_blocks;
811: value = get(LONG);
812: type = NULL;
813: continue;
814: }
815: if (match("base", 2)) { /* change/show base */
816: showbase:
817: if ((c = getachar()) == '\n') {
818: ungetachar(c);
819: printf("base =\t\t");
820: switch (base) {
821: case OCTAL:
822: printf("OCTAL\n");
823: continue;
824: case DECIMAL:
825: printf("DECIMAL\n");
826: continue;
827: case HEX:
828: printf("HEX\n");
829: continue;
830: }
831: }
832: if (c != '=') {
833: printf("missing '='\n");
834: error++;
835: continue;
836: }
837: value = expr();
838: switch (value) {
839: default:
840: printf("invalid base\n");
841: error++;
842: break;
843: case OCTAL:
844: case DECIMAL:
845: case HEX:
846: base = value;
847: }
848: goto showbase;
849: }
850: goto bad_syntax;
851:
852: case 'c':
853: if (colon)
854: colon = 0;
855: else
856: goto no_colon;
857: if (match("cd", 2)) { /* change directory */
858: top = filenames - 1;
859: eat_spaces();
860: if ((c = getachar()) == '\n') {
861: ungetachar(c);
862: current_pathp = -1;
863: restore_inode(2);
864: continue;
865: }
866: ungetachar(c);
867: temp = cur_inum;
868: doing_cd = 1;
869: parse();
870: doing_cd = 0;
871: if (nfiles != 1) {
872: restore_inode(temp);
873: if (!error) {
874: print_path(input_path,
875: input_pathp);
876: if (nfiles == 0)
877: printf(" not found\n");
878: else
879: printf(" ambiguous\n");
880: error++;
881: }
882: continue;
883: }
884: restore_inode(filenames->ino);
885: if ((mode = icheck(addr)) == 0)
886: continue;
887: if ((mode & IFMT) != IFDIR) {
888: restore_inode(temp);
889: print_path(input_path, input_pathp);
890: printf(" not a directory\n");
891: error++;
892: continue;
893: }
894: for (i = 0; i <= top->len; i++)
895: strcpy(current_path[i],
896: top->fname[i]);
897: current_pathp = top->len;
898: continue;
899: }
900: if (match("cg", 2)) { /* cylinder group */
901: if (type == NUMB)
902: value = addr;
903: if (value > fs->fs_ncg - 1) {
904: printf("maximum cylinder group is ");
905: print(fs->fs_ncg - 1, 8, -8, 0);
906: printf("\n");
907: error++;
908: continue;
909: }
910: type = objsz = CGRP;
911: cur_cgrp = value;
912: addr = cgtod(fs, cur_cgrp) << FRGSHIFT;
913: continue;
914: }
915: if (match("ct", 2)) { /* creation time */
916: acting_on_inode = 2;
917: should_print = 1;
918: addr = (long)
919: &((struct dinode *)cur_ino)->di_ctime;
920: value = get(LONG);
921: type = NULL;
922: continue;
923: }
924: goto bad_syntax;
925:
926: case 'd':
927: if (colon)
928: colon = 0;
929: else
930: goto no_colon;
931: if (match("directory", 2)) { /* directory offsets */
932: if (type == NUMB)
933: value = addr;
934: objsz = DIRECTORY;
935: type = DIRECTORY;
936: addr = getdirslot(value);
937: continue;
938: }
939: if (match("db", 2)) { /* direct block */
940: acting_on_inode = 1;
941: should_print = 1;
942: if (type == NUMB)
943: value = addr;
944: if (value >= NDADDR) {
945: printf("direct blocks are 0 to ");
946: print(NDADDR - 1, 0, 0, 0);
947: printf("\n");
948: error++;
949: continue;
950: }
951: addr = cur_ino;
952: if (!icheck(addr))
953: continue;
954: addr = (long)
955: &((struct dinode *)cur_ino)->di_db[value];
956: bod_addr = addr;
957: cur_bytes = (value) * BLKSIZE;
958: cur_block = value;
959: type = BLOCK;
960: dirslot = 0;
961: value = get(LONG);
962: if (!value && !override) {
963: printf("non existent block\n");
964: error++;
965: }
966: continue;
967: }
968: goto bad_syntax;
969:
970: case 'f':
971: if (colon)
972: colon = 0;
973: else
974: goto no_colon;
975: if (match("find", 3)) { /* find command */
976: find();
977: continue;
978: }
979: if (match("fragment", 2)) { /* fragment conv. */
980: if (type == NUMB) {
981: value = addr;
982: cur_bytes = 0;
983: blocksize = FRGSIZE;
984: filesize = FRGSIZE * 2;
985: }
986: if (min(blocksize, filesize) - cur_bytes >
987: FRGSIZE) {
988: blocksize = cur_bytes + FRGSIZE;
989: filesize = blocksize * 2;
990: }
991: addr = value << FRGSHIFT;
992: bod_addr = addr;
993: value = get(LONG);
994: type = FRAGMENT;
995: dirslot = 0;
996: trapped++;
997: continue;
998: }
999: if (match("file", 4)) { /* access as file */
1000: acting_on_inode = 1;
1001: should_print = 1;
1002: if (type == NUMB)
1003: value = addr;
1004: addr = cur_ino;
1005: if ((mode = icheck(addr)) == 0)
1006: continue;
1007: if ((mode & IFCHR) && !override) {
1008: printf("special device\n");
1009: error++;
1010: continue;
1011: }
1012: if ((addr = (bmap(value) << FRGSHIFT)) == 0)
1013: continue;
1014: cur_block = value;
1015: bod_addr = addr;
1016: type = BLOCK;
1017: dirslot = 0;
1018: continue;
1019: }
1020: if (match("fill", 4)) { /* fill */
1021: if (getachar() != '=') {
1022: printf("missing '='\n");
1023: error++;
1024: continue;
1025: }
1026: if (objsz == INODE || objsz == DIRECTORY) {
1027: printf("can't fill inode or directory\n");
1028: error++;
1029: continue;
1030: }
1031: fill();
1032: continue;
1033: }
1034: goto bad_syntax;
1035:
1036: case 'g':
1037: if (colon)
1038: colon = 0;
1039: else
1040: goto no_colon;
1041: if (match("gid", 1)) { /* group id */
1042: acting_on_inode = 1;
1043: should_print = 1;
1044: addr = (long)
1045: &((struct dinode *)cur_ino)->di_gid;
1046: value = get(SHORT);
1047: type = NULL;
1048: continue;
1049: }
1050: goto bad_syntax;
1051:
1052: case 'i':
1053: if (colon)
1054: colon = 0;
1055: else
1056: goto no_colon;
1057: if (match("inode", 2)) { /* i# to inode conversion */
1058: if (c_count == 2) {
1059: addr = cur_ino;
1060: value = get(INODE);
1061: type = NULL;
1062: laststyle = '=';
1063: lastpo = 'i';
1064: should_print = 1;
1065: continue;
1066: }
1067: if (type == NUMB)
1068: value = addr;
1069: addr = itob(value);
1070: if (!icheck(addr))
1071: continue;
1072: cur_ino = addr;
1073: cur_inum = value;
1074: value = get(INODE);
1075: type = NULL;
1076: continue;
1077: }
1078: if (match("ib", 2)) { /* indirect block */
1079: acting_on_inode = 1;
1080: should_print = 1;
1081: if (type == NUMB)
1082: value = addr;
1083: if (value >= NIADDR) {
1084: printf("indirect blocks are 0 to ");
1085: print(NIADDR - 1, 0, 0, 0);
1086: printf("\n");
1087: error++;
1088: continue;
1089: }
1090: addr = (long)
1091: &((struct dinode *)cur_ino)->di_ib[value];
1092: cur_bytes = (NDADDR - 1) * BLKSIZE;
1093: temp = 1;
1094: for (i = 0; i < value; i++) {
1095: temp *= NINDIR(fs) * BLKSIZE;
1096: cur_bytes += temp;
1097: }
1098: type = BLOCK;
1099: dirslot = 0;
1100: value = get(LONG);
1101: if (!value && !override) {
1102: printf("non existent block\n");
1103: error++;
1104: }
1105: continue;
1106: }
1107: goto bad_syntax;
1108:
1109: case 'l':
1110: if (colon)
1111: colon = 0;
1112: else
1113: goto no_colon;
1114: if (match("ls", 2)) { /* ls command */
1115: temp = cur_inum;
1116: recursive = long_list = 0;
1117: top = filenames - 1;
1118: for (;;) {
1119: eat_spaces();
1120: if ((c = getachar()) == '-') {
1121: if ((c = getachar()) == 'R') {
1122: recursive = 1;
1123: continue;
1124: } else if (c == 'l') {
1125: long_list = 1;
1126: } else {
1127: printf("unknown option ");
1128: printf("'%c'\n", c);
1129: error++;
1130: break;
1131: }
1132: } else
1133: ungetachar(c);
1134: if ((c = getachar()) == '\n') {
1135: if (c_count != 2) {
1136: ungetachar(c);
1137: break;
1138: }
1139: }
1140: c_count++;
1141: ungetachar(c);
1142: parse();
1143: restore_inode(temp);
1144: if (error)
1145: break;
1146: }
1147: recursive = 0;
1148: if (error || nfiles == 0) {
1149: if (!error) {
1150: print_path(input_path,
1151: input_pathp);
1152: printf(" not found\n");
1153: }
1154: continue;
1155: }
1156: if (nfiles) {
1157: cmp_level = 0;
1158: qsort((char *)filenames, nfiles,
1159: sizeof (struct filenames), ffcmp);
1160: ls(filenames, filenames + (nfiles - 1), 0);
1161: } else {
1162: printf("no match\n");
1163: error++;
1164: }
1165: restore_inode(temp);
1166: continue;
1167: }
1168: if (match("ln", 2)) { /* link count */
1169: acting_on_inode = 1;
1170: should_print = 1;
1171: addr = (long)
1172: &((struct dinode *)cur_ino)->di_nlink;
1173: value = get(SHORT);
1174: type = NULL;
1175: continue;
1176: }
1177: goto bad_syntax;
1178:
1179: case 'm':
1180: if (colon)
1181: colon = 0;
1182: else
1183: goto no_colon;
1184: addr = cur_ino;
1185: if ((mode = icheck(addr)) == 0)
1186: continue;
1187: if (match("mt", 2)) { /* modification time */
1188: acting_on_inode = 2;
1189: should_print = 1;
1190: addr = (long)
1191: &((struct dinode *)cur_ino)->di_mtime;
1192: value = get(LONG);
1193: type = NULL;
1194: continue;
1195: }
1196: if (match("md", 2)) { /* mode */
1197: acting_on_inode = 1;
1198: should_print = 1;
1199: addr = (long)
1200: &((struct dinode *)cur_ino)->di_mode;
1201: value = get(SHORT);
1202: type = NULL;
1203: continue;
1204: }
1205: if (match("maj", 2)) { /* major device number */
1206: acting_on_inode = 1;
1207: should_print = 1;
1208: if (devcheck(mode))
1209: continue;
1210: addr = (long)
1211: &((struct dinode *)cur_ino)->di_db[1];
1212: value = get(LONG);
1213: type = NULL;
1214: continue;
1215: }
1216: if (match("min", 2)) { /* minor device number */
1217: acting_on_inode = 1;
1218: should_print = 1;
1219: if (devcheck(mode))
1220: continue;
1221: addr = (long)
1222: &((struct dinode *)cur_ino)->di_db[0];
1223: value = get(LONG);
1224: type = NULL;
1225: continue;
1226: }
1227: goto bad_syntax;
1228:
1229: case 'n':
1230: if (colon)
1231: colon = 0;
1232: else
1233: goto no_colon;
1234: if (match("nm", 1)) { /* directory name */
1235: objsz = DIRECTORY;
1236: acting_on_directory = 1;
1237: cur_dir = addr;
1238: if ((cptr = getblk(addr)) == 0)
1239: continue;
1240: dirp = (struct direct *)(cptr+blkoff(fs, addr));
1241: stringsize = (long)dirp->d_reclen -
1242: ((long)&dirp->d_name[0] - (long)&dirp->d_ino);
1243: addr = (long)
1244: &((struct direct *)addr)->d_name[0];
1245: type = NULL;
1246: continue;
1247: }
1248: goto bad_syntax;
1249:
1250: case 'o':
1251: if (colon)
1252: colon = 0;
1253: else
1254: goto no_colon;
1255: if (match("override", 1)) { /* override flip flop */
1256: if (override = !override)
1257: printf("error checking off\n");
1258: else
1259: printf("error checking on\n");
1260: continue;
1261: }
1262: goto bad_syntax;
1263:
1264: case 'p':
1265: if (colon)
1266: colon = 0;
1267: else
1268: goto no_colon;
1269: if (match("pwd", 2)) { /* print working dir */
1270: print_path(current_path, current_pathp);
1271: printf("\n");
1272: continue;
1273: }
1274: if (match("prompt", 2)) { /* change prompt */
1275: if ((c = getachar()) != '=') {
1276: printf("missing '='\n");
1277: error++;
1278: continue;
1279: }
1280: if ((c = getachar()) != '"') {
1281: printf("missing '\"'\n");
1282: error++;
1283: continue;
1284: }
1285: i = 0;
1286: prompt = &prompt[0];
1287: while ((c = getachar()) != '"' &&
1288: c != '\n') {
1289: prompt[i++] = c;
1290: if (i >= PROMPTSIZE) {
1291: printf("string too long\n");
1292: error++;
1293: break;
1294: }
1295: }
1296: prompt[i] = '\0';
1297: continue;
1298: }
1299: goto bad_syntax;
1300:
1301: case 'q':
1302: if (!colon)
1303: goto no_colon;
1304: if (match("quit", 1)) { /* quit */
1305: if ((c = getachar()) != '\n') {
1306: error++;
1307: continue;
1308: }
1309: exit(0);
1310: }
1311: goto bad_syntax;
1312:
1313: case 's':
1314: if (colon)
1315: colon = 0;
1316: else
1317: goto no_colon;
1318: if (match("sb", 2)) { /* super block */
1319: if (c_count == 2) {
1320: cur_cgrp = -1;
1321: type = objsz = SB;
1322: laststyle = '=';
1323: lastpo = 's';
1324: should_print = 1;
1325: continue;
1326: }
1327: if (type == NUMB)
1328: value = addr;
1329: if (value > fs->fs_ncg - 1) {
1330: printf("maximum super block is ");
1331: print(fs->fs_ncg - 1, 8, -8, 0);
1332: printf("\n");
1333: error++;
1334: continue;
1335: }
1336: type = objsz = SB;
1337: cur_cgrp = value;
1338: addr = cgsblock(fs, cur_cgrp) << FRGSHIFT;
1339: continue;
1340: }
1341: if (match("sz", 2)) { /* file size */
1342: acting_on_inode = 1;
1343: should_print = 1;
1344: addr = (long)
1345: &((struct dinode *)cur_ino)->di_size;
1346: value = get(LONG);
1347: type = NULL;
1348: continue;
1349: }
1350: goto bad_syntax;
1351:
1352: case 'u':
1353: if (colon)
1354: colon = 0;
1355: else
1356: goto no_colon;
1357: if (match("uid", 1)) { /* user id */
1358: acting_on_inode = 1;
1359: should_print = 1;
1360: addr = (long)
1361: &((struct dinode *)cur_ino)->di_uid;
1362: value = get(SHORT);
1363: type = NULL;
1364: continue;
1365: }
1366: goto bad_syntax;
1367:
1368: case 'F': /* buffer status (internal use only) */
1369: if (colon)
1370: colon = 0;
1371: else
1372: goto no_colon;
1373: for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
1374: printf("%8x %d\n",bp->blkno,bp->valid);
1375: printf("\n");
1376: printf("# commands\t\t%d\n", commands);
1377: printf("# read requests\t\t%d\n", read_requests);
1378: printf("# actual disk reads\t%d\n", actual_disk_reads);
1379: continue;
1380: no_colon:
1381: printf("a colon should precede a command\n");
1382: error++;
1383: continue;
1384: bad_syntax:
1385: printf("more letters needed to distinguish command\n");
1386: error++;
1387: continue;
1388: }
1389: }
1390: }
1391:
1392: /*
1393: * getachar - get next character from input buffer.
1394: */
1395: char
1396: getachar()
1397: {
1398: return(input_buffer[input_pointer++]);
1399: }
1400:
1401: /*
1402: * ungetachar - return character to input buffer.
1403: */
1404: ungetachar(c)
1405: register char c;
1406: {
1407: if (input_pointer == 0) {
1408: printf("internal problem maintaining input buffer\n");
1409: error++;
1410: return;
1411: }
1412: input_buffer[--input_pointer] = c;
1413: }
1414:
1415: /*
1416: * getnextinput - display the prompt and read an input line.
1417: * An input line is up to 128 characters terminated by the newline
1418: * character. Handle overflow, shell escape, and eof.
1419: */
1420: getnextinput()
1421: {
1422: register int i;
1423: register char c;
1424: register short pid, rpid;
1425: int retcode;
1426:
1427: newline:
1428: i = 0;
1429: printf("%s", prompt);
1430: ignore_eol:
1431: while ((c = getc(stdin)) != '\n' && !(c == '!' && i == 0) &&
1432: !feof(stdin) && i <= INPUTBUFFER - 2)
1433: input_buffer[i++] = c;
1434: if (input_buffer[i - 1] == '\\') {
1435: input_buffer[i++] = c;
1436: goto ignore_eol;
1437: }
1438: if (feof(stdin)) {
1439: printf("\n");
1440: exit(0);
1441: }
1442: if (c == '!') {
1443: if ((pid = fork()) == 0) {
1444: execl("/bin/sh", "sh", "-t", 0);
1445: error++;
1446: return;
1447: }
1448: while ((rpid = wait(&retcode)) != pid && rpid != -1)
1449: ;
1450: printf("!\n");
1451: goto newline;
1452: }
1453: if (c != '\n')
1454: printf("input truncated to 128 characters\n");
1455: input_buffer[i] = '\n';
1456: input_pointer = 0;
1457: }
1458:
1459: /*
1460: * eat_spaces - read extraneous spaces.
1461: */
1462: eat_spaces()
1463: {
1464: register char c;
1465:
1466: while ((c = getachar()) == ' ')
1467: ;
1468: ungetachar(c);
1469: }
1470:
1471: /*
1472: * restore_inode - set up all inode indicators so inum is now
1473: * the current inode.
1474: */
1475: restore_inode(inum)
1476: long inum;
1477: {
1478: errinum = cur_inum = inum;
1479: addr = errino = cur_ino = itob(inum);
1480: }
1481:
1482: /*
1483: * match - return false if the input does not match string up to
1484: * upto letters. Then proceed to chew up extraneous letters.
1485: */
1486: match(string, upto)
1487: register char *string;
1488: register int upto;
1489: {
1490: register int i, length = strlen(string) - 1;
1491: register char c;
1492: int save_upto = upto;
1493:
1494: while (--upto) {
1495: string++;
1496: if ((c = getachar()) != *string) {
1497: for (i = save_upto - upto; i; i--) {
1498: ungetachar(c);
1499: c = *--string;
1500: }
1501: return(0);
1502: }
1503: length--;
1504: }
1505: while (length--) {
1506: string++;
1507: if ((c = getachar()) != *string) {
1508: ungetachar(c);
1509: return(1);
1510: }
1511: }
1512: return(1);
1513: }
1514:
1515: /*
1516: * expr - expression evaluator. Will evaluate expressions from
1517: * left to right with no operator precedence. Parentheses may
1518: * be used.
1519: */
1520: long
1521: expr()
1522: {
1523: register long numb = 0, temp;
1524: register char c;
1525:
1526: numb = term();
1527: for (;;) {
1528: if (error)
1529: return;
1530: c = getachar();
1531: switch (c) {
1532:
1533: case '+':
1534: numb += term();
1535: continue;
1536:
1537: case '-':
1538: numb -= term();
1539: continue;
1540:
1541: case '*':
1542: numb *= term();
1543: continue;
1544:
1545: case '%':
1546: temp = term();
1547: if (!temp) {
1548: printf("divide by zero\n");
1549: error++;
1550: return;
1551: }
1552: numb /= temp;
1553: continue;
1554:
1555: case ')':
1556: paren--;
1557: return(numb);
1558:
1559: default:
1560: ungetachar(c);
1561: if (paren && !error) {
1562: printf("missing ')'\n");
1563: error++;
1564: }
1565: return(numb);
1566: }
1567: }
1568: }
1569:
1570: /*
1571: * term - used by expression evaluator to get an operand.
1572: */
1573: long
1574: term()
1575: {
1576: register char c;
1577:
1578: switch (c = getachar()) {
1579:
1580: default:
1581: ungetachar(c);
1582:
1583: case '+':
1584: return(getnumb());
1585:
1586: case '-':
1587: return(-getnumb());
1588:
1589: case '(':
1590: paren++;
1591: return(expr());
1592: }
1593: }
1594:
1595: /*
1596: * getnumb - read a number from the input stream. A leading
1597: * zero signifies octal interpretation, a leading '0x'
1598: * signifies hexadecimal, and a leading '0t' signifies
1599: * decimal. If the first character is a character,
1600: * return an error.
1601: */
1602: long
1603: getnumb()
1604: {
1605:
1606: register char c, savec;
1607: long number = 0, tbase, num;
1608: extern short error;
1609:
1610: c = getachar();
1611: if (!digit(c)) {
1612: error++;
1613: ungetachar(c);
1614: return(-1);
1615: }
1616: if (c == '0') {
1617: tbase = OCTAL;
1618: if ((c = getachar()) == 'x')
1619: tbase = HEX;
1620: else if (c == 't')
1621: tbase = DECIMAL;
1622: else ungetachar(c);
1623: } else {
1624: tbase = base;
1625: ungetachar(c);
1626: }
1627: for (;;) {
1628: num = tbase;
1629: c = savec = getachar();
1630: if (HEXLETTER(c))
1631: c = uppertolower(c);
1632: switch (tbase) {
1633: case HEX:
1634: if (hexletter(c)) {
1635: num = hextodigit(c);
1636: break;
1637: }
1638: case DECIMAL:
1639: if (digit(c))
1640: num = numtodigit(c);
1641: break;
1642: case OCTAL:
1643: if (octaldigit(c))
1644: num = numtodigit(c);
1645: }
1646: if (num == tbase)
1647: break;
1648: number = number * tbase + num;
1649: }
1650: ungetachar(savec);
1651: return(number);
1652: }
1653:
1654: /*
1655: * find - the syntax is almost identical to the unix command.
1656: * find dir [-name pattern] [-inum number]
1657: * Note: only one of -name or -inum may be used at a time.
1658: * Also, the -print is not needed (implied).
1659: */
1660: find()
1661: {
1662: register struct filenames *fn;
1663: register char c;
1664: long temp;
1665: short mode;
1666:
1667: eat_spaces();
1668: temp = cur_inum;
1669: top = filenames - 1;
1670: doing_cd = 1;
1671: parse();
1672: doing_cd = 0;
1673: if (nfiles != 1) {
1674: restore_inode(temp);
1675: if (!error) {
1676: print_path(input_path, input_pathp);
1677: if (nfiles == 0)
1678: printf(" not found\n");
1679: else
1680: printf(" ambiguous\n");
1681: error++;
1682: return;
1683: }
1684: }
1685: restore_inode(filenames->ino);
1686: freemem(filenames, nfiles);
1687: nfiles = 0;
1688: top = filenames - 1;
1689: if ((mode = icheck(addr)) == 0)
1690: return;
1691: if ((mode & IFMT) != IFDIR) {
1692: print_path(input_path, input_pathp);
1693: printf(" not a directory\n");
1694: error++;
1695: return;
1696: }
1697: eat_spaces();
1698: if ((c = getachar()) != '-') {
1699: printf("missing '-'\n");
1700: error++;
1701: return;
1702: }
1703: find_by_name = find_by_inode = 0;
1704: c = getachar();
1705: if (match("name", 4)) {
1706: eat_spaces();
1707: find_by_name = 1;
1708: } else if (match("inum", 4)) {
1709: eat_spaces();
1710: find_ino = expr();
1711: if (error)
1712: return;
1713: while ((c = getachar()) != '\n')
1714: ;
1715: ungetachar(c);
1716: find_by_inode = 1;
1717: } else {
1718: printf("use -name or -inum with find\n");
1719: error++;
1720: return;
1721: }
1722: doing_find = 1;
1723: parse();
1724: doing_find = 0;
1725: if (error) {
1726: restore_inode(temp);
1727: return;
1728: }
1729: for (fn = filenames; fn <= top; fn++) {
1730: if (fn->find == 0)
1731: continue;
1732: printf("i#: ");
1733: print(fn->ino, 12, -8, 0);
1734: print_path(fn->fname, fn->len);
1735: printf("\n");
1736: }
1737: restore_inode(temp);
1738: }
1739:
1740: /*
1741: * ls - do an ls. Should behave exactly as ls(1).
1742: * Only -R and -l is supported and -l gives different results.
1743: */
1744: ls(fn0, fnlast, level)
1745: struct filenames *fn0, *fnlast;
1746: short level;
1747: {
1748: register struct filenames *fn, *fnn;
1749: register int i;
1750: int fcmp();
1751:
1752: fn = fn0;
1753: for (;;) {
1754: fn0 = fn;
1755: if (fn0->len) {
1756: cmp_level = level;
1757: qsort((char *)fn0, fnlast - fn0 + 1,
1758: sizeof (struct filenames), fcmp);
1759: }
1760: for (fnn = fn, fn++; fn <= fnlast; fnn = fn, fn++) {
1761: if (fnn->len != fn->len && level == fnn->len - 1)
1762: break;
1763: if (fnn->len == 0)
1764: continue;
1765: if (strcmp(fn->fname[level], fnn->fname[level]))
1766: break;
1767: }
1768: if (fn0->len && level != fn0->len - 1)
1769: ls(fn0, fnn, level + 1);
1770: else {
1771: if (fn0 != filenames)
1772: printf("\n");
1773: print_path(fn0->fname, fn0->len - 1);
1774: printf(":\n");
1775: if (fn0->len == 0)
1776: cmp_level = level;
1777: else
1778: cmp_level = level + 1;
1779: qsort((char *)fn0, fnn - fn0 + 1,
1780: sizeof (struct filenames), fcmp);
1781: formatf(fn0, fnn);
1782: nfiles -= fnn - fn0 + 1;
1783: }
1784: if (fn > fnlast)
1785: return;
1786: }
1787: }
1788:
1789: /*
1790: * formatf - code lifted from ls.
1791: */
1792: formatf(fn0, fnlast)
1793: register struct filenames *fn0, *fnlast;
1794: {
1795: register struct filenames *fn;
1796: int width = 0, w, nentry = fnlast - fn0 + 1;
1797: int i, j, columns, lines;
1798: char *cp;
1799:
1800: if (long_list) {
1801: columns = 1;
1802: } else {
1803: for (fn = fn0; fn <= fnlast; fn++) {
1804: int len = strlen(fn->fname[cmp_level]) + 2;
1805:
1806: if (len > width)
1807: width = len;
1808: }
1809: width = (width + 8) &~ 7;
1810: columns = 80 / width;
1811: if (columns == 0)
1812: columns = 1;
1813: }
1814: lines = (nentry + columns - 1) / columns;
1815: for (i = 0; i < lines; i++) {
1816: for (j = 0; j < columns; j++) {
1817: fn = fn0 + j * lines + i;
1818: if (long_list) {
1819: printf("i#: ");
1820: print(fn->ino, 12, -8, 0);
1821: }
1822: cp = fmtentry(fn);
1823: printf("%s", cp);
1824: if (fn + lines > fnlast) {
1825: printf("\n");
1826: break;
1827: }
1828: w = strlen(cp);
1829: while (w < width) {
1830: w = (w + 8) &~ 7;
1831: putchar('\t');
1832: }
1833: }
1834: }
1835: }
1836:
1837: /*
1838: * fmtentry - code lifted from ls.
1839: */
1840: char *
1841: fmtentry(fn)
1842: register struct filenames *fn;
1843: {
1844: static char fmtres[BUFSIZ];
1845: register struct dinode *ip;
1846: register char *cptr, *cp, *dp;
1847:
1848: dp = &fmtres[0];
1849: for (cp = fn->fname[cmp_level]; *cp; cp++) {
1850: if (*cp < ' ' || *cp >= 0177)
1851: *dp++ = '?';
1852: else
1853: *dp++ = *cp;
1854: }
1855: addr = itob(fn->ino);
1856: if ((cptr = getblk(addr)) == 0)
1857: return(NULL);
1858: cptr += blkoff(fs, addr);
1859: ip = (struct dinode *)cptr;
1860: switch (ip->di_mode & IFMT) {
1861: case IFDIR:
1862: *dp++ = '/';
1863: break;
1864: case IFLNK:
1865: *dp++ = '@';
1866: break;
1867: case IFSOCK:
1868: *dp++ = '=';
1869: break;
1870: /* case IFIFO:
1871: *dp++ = 'f';
1872: break; SYSTEM V only */
1873: case IFCHR:
1874: case IFBLK:
1875: case IFREG:
1876: if (ip->di_mode & 0111)
1877: *dp++ = '*';
1878: else
1879: *dp++ = ' ';
1880: break;
1881: default:
1882: *dp++ = '?';
1883:
1884: }
1885: *dp++ = 0;
1886: return (fmtres);
1887: }
1888:
1889: /*
1890: * fcmp - routine used by qsort. Will sort first by name, then
1891: * then by pathname length if names are equal. Uses global
1892: * cmp_level to tell what component of the path name we are comparing.
1893: */
1894: fcmp(f1, f2)
1895: register struct filenames *f1, *f2;
1896: {
1897: int value;
1898:
1899: if ((value = strcmp(f1->fname[cmp_level], f2->fname[cmp_level])))
1900: return(value);
1901: return (f1->len - f2->len);
1902: }
1903:
1904: /*
1905: * ffcmp - routine used by qsort. Sort only by pathname length.
1906: */
1907: ffcmp(f1, f2)
1908: register struct filenames *f1, *f2;
1909: {
1910: return (f1->len - f2->len);
1911: }
1912:
1913: /*
1914: * parse - set up the call to follow_path.
1915: */
1916: parse()
1917: {
1918: register int i, j;
1919: char c;
1920:
1921: stack_pathp = input_pathp = -1;
1922: if ((c = getachar()) == '/') {
1923: while ((c = getachar()) == '/')
1924: ;
1925: ungetachar(c);
1926: cur_inum = 2;
1927: if ((c = getachar()) == '\n') {
1928: ungetachar('\n');
1929: if (doing_cd) {
1930: top++;
1931: top->ino = 2;
1932: top->len = -1;
1933: nfiles = 1;
1934: return;
1935: }
1936: } else
1937: ungetachar(c);
1938: } else {
1939: ungetachar(c);
1940: stack_pathp = current_pathp;
1941: if (!doing_find)
1942: input_pathp = current_pathp;
1943: for (i = 0; i <= current_pathp; i++) {
1944: if (!doing_find)
1945: strcpy(input_path[i], current_path[i]);
1946: strcpy(stack_path[i], current_path[i]);
1947: }
1948: }
1949: getname();
1950: follow_path(stack_pathp + 1, cur_inum);
1951: }
1952:
1953: /*
1954: * follow_path - called by cd, find, and ls.
1955: * input_path holds the name typed by the user.
1956: * stack_path holds the name at the current depth.
1957: */
1958: follow_path(level, inum)
1959: long level, inum;
1960: {
1961: register struct direct *dirp;
1962: register char **ccptr, *cptr, c;
1963: register int i;
1964: struct filenames *tos, *bos, *fn, *fnn, *fnnn;
1965: long block;
1966: short mode;
1967:
1968: tos = top + 1;
1969: restore_inode(inum);
1970: if ((mode = icheck(addr)) == 0)
1971: return;
1972: if ((mode & IFMT) != IFDIR)
1973: return;
1974: block = cur_bytes = 0;
1975: while (cur_bytes < filesize) {
1976: if (block == 0 || bcomp(addr)) {
1977: error = 0;
1978: if ((addr = (bmap(block++) << FRGSHIFT)) == 0)
1979: break;
1980: if ((cptr = getblk(addr)) == 0)
1981: break;
1982: cptr += blkoff(fs, addr);
1983: }
1984: dirp = (struct direct *)cptr;
1985: if (dirp->d_ino) {
1986: if (level > input_pathp || doing_find ||
1987: compare(input_path[level], &dirp->d_name[0], 1)) {
1988: if (++top - filenames >= MAXFILES) {
1989: printf("too many files\n");
1990: error++;
1991: return;
1992: }
1993: top->fname = (char **)calloc(FIRST_DEPTH, sizeof (char **));
1994: top->flag = 0;
1995: if (top->fname == 0) {
1996: printf("out of memory\n");
1997: error++;
1998: return;
1999: }
2000: nfiles++;
2001: top->ino = dirp->d_ino;
2002: top->len = stack_pathp;
2003: top->find = 0;
2004: if (doing_find) {
2005: if (find_by_name) {
2006: if (compare(input_path[0], &dirp->d_name[0], 1))
2007: top->find = 1;
2008: } else if (find_by_inode)
2009: if (find_ino == dirp->d_ino)
2010: top->find = 1;
2011: }
2012: if (top->len + 1 >= FIRST_DEPTH && top->flag == 0) {
2013: ccptr = (char **)calloc(SECOND_DEPTH, sizeof (char **));
2014: if (ccptr == 0) {
2015: printf("out of memory\n");
2016: error++;
2017: return;
2018: }
2019: for (i = 0; i < FIRST_DEPTH; i++)
2020: ccptr[i] = top->fname[i];
2021: free((char *)top->fname);
2022: top->fname = ccptr;
2023: top->flag = 1;
2024: }
2025: if (top->len >= SECOND_DEPTH) {
2026: printf("maximum depth exceeded, try to cd lower\n");
2027: error++;
2028: return;
2029: }
2030: /*
2031: * Copy current depth.
2032: */
2033: for (i = 0; i <= stack_pathp; i++) {
2034: top->fname[i]=calloc(1, strlen(stack_path[i])+1);
2035: if (top->fname[i] == 0) {
2036: printf("out of memory\n");
2037: error++;
2038: return;
2039: }
2040: strcpy(top->fname[i], stack_path[i]);
2041: }
2042: /*
2043: * Check for '.' or '..' typed.
2044: */
2045: if ((level <= input_pathp) &&
2046: (strcmp(input_path[level], ".") == 0 ||
2047: strcmp(input_path[level], "..") == 0)) {
2048: if (strcmp(input_path[level],"..") == 0 &&
2049: top->len >= 0) {
2050: free(top->fname[top->len]);
2051: top->len -= 1;
2052: }
2053: } else {
2054: /*
2055: * Check for duplicates.
2056: */
2057: if (!doing_cd && !doing_find) {
2058: for (fn = filenames; fn < top; fn++) {
2059: if (fn->ino == dirp->d_ino &&
2060: fn->len == stack_pathp + 1) {
2061: for (i = 0; i < fn->len; i++)
2062: if (strcmp(fn->fname[i], stack_path[i]))
2063: break;
2064: if (i != fn->len ||
2065: strcmp(fn->fname[i], dirp->d_name))
2066: continue;
2067: freemem(top, 1);
2068: if (top == filenames)
2069: top = NULL;
2070: else
2071: top--;
2072: nfiles--;
2073: goto duplicate;
2074: }
2075: }
2076: }
2077: top->len += 1;
2078: top->fname[top->len] = calloc(1,
2079: strlen(&dirp->d_name[0])+1);
2080: if (top->fname[top->len] == 0) {
2081: printf("out of memory\n");
2082: error++;
2083: return;
2084: }
2085: strcpy(top->fname[top->len], &dirp->d_name[0]);
2086: }
2087: }
2088: }
2089: duplicate:
2090: addr += dirp->d_reclen;
2091: cptr += dirp->d_reclen;
2092: cur_bytes += dirp->d_reclen;
2093: }
2094: if (top < filenames)
2095: return;
2096: if ((doing_cd && level == input_pathp) ||
2097: (!recursive && !doing_find && level > input_pathp))
2098: return;
2099: bos = top;
2100: /*
2101: * Check newly added entries to determine if further expansion
2102: * is required.
2103: */
2104: for (fn = tos; fn <= bos; fn++) {
2105: /*
2106: * Avoid '.' and '..' if beyond input.
2107: */
2108: if ((recursive || doing_find) && (level > input_pathp) &&
2109: (strcmp(fn->fname[fn->len], ".") == 0 ||
2110: strcmp(fn->fname[fn->len], "..") == 0))
2111: continue;
2112: restore_inode(fn->ino);
2113: if ((mode = icheck(cur_ino)) == 0)
2114: return;
2115: if ((mode & IFMT) == IFDIR || level < input_pathp) {
2116: /*
2117: * Set up current depth, remove current entry and
2118: * continue recursion.
2119: */
2120: for (i = 0; i <= fn->len; i++)
2121: strcpy(stack_path[i], fn->fname[i]);
2122: stack_pathp = fn->len;
2123: if (!doing_find &&
2124: (!recursive || (recursive && level <= input_pathp))) {
2125: /*
2126: * Remove current entry by moving others up.
2127: */
2128: freemem(fn, 1);
2129: fnn = fn;
2130: for (fnnn = fnn, fnn++; fnn <= top; fnnn = fnn, fnn++) {
2131: fnnn->ino = fnn->ino;
2132: fnnn->len = fnn->len;
2133: if (fnnn->len + 1 < FIRST_DEPTH) {
2134: fnnn->fname = (char **)calloc(FIRST_DEPTH,
2135: sizeof (char **));
2136: fnnn->flag = 0;
2137: } else if (fnnn->len < SECOND_DEPTH) {
2138: fnnn->fname = (char **)calloc(SECOND_DEPTH,
2139: sizeof (char **));
2140: fnnn->flag = 1;
2141: } else {
2142: printf("maximum depth exceeded, ");
2143: printf("try to cd lower\n");
2144: error++;
2145: return;
2146: }
2147: for (i = 0; i <= fnn->len; i++)
2148: fnnn->fname[i] = fnn->fname[i];
2149: }
2150: if (fn == tos)
2151: fn--;
2152: top--;
2153: bos--;
2154: nfiles--;
2155: }
2156: follow_path(level + 1, cur_inum);
2157: if (error)
2158: return;
2159: }
2160: }
2161: }
2162:
2163: /*
2164: * getname - break up the pathname entered by the user into components.
2165: */
2166: getname()
2167: {
2168: register int i;
2169: char c;
2170:
2171: if ((c = getachar()) == '\n') {
2172: ungetachar(c);
2173: return;
2174: }
2175: ungetachar(c);
2176: input_pathp++;
2177: clear:
2178: for (i = 0; i < MAXNAMLEN; i++)
2179: input_path[input_pathp][i] = '\0';
2180: for (;;) {
2181: c = getachar();
2182: if (c == '\\') {
2183: if (strlen(input_path[input_pathp]) + 1 >= MAXNAMLEN) {
2184: printf("maximum name length exceeded, ");
2185: printf("truncating\n");
2186: return;
2187: }
2188: input_path[input_pathp][strlen(input_path[input_pathp])] = c;
2189: input_path[input_pathp][strlen(input_path[input_pathp])] =
2190: getachar();
2191: continue;
2192: }
2193: if (c == ' ' || c == '\n') {
2194: ungetachar(c);
2195: return;
2196: }
2197: if (!doing_find && c == '/') {
2198: if (++input_pathp >= MAXPATHLEN) {
2199: printf("maximum path length exceeded, ");
2200: printf("truncating\n");
2201: input_pathp--;
2202: return;
2203: }
2204: goto clear;
2205: }
2206: if (strlen(input_path[input_pathp]) >= MAXNAMLEN) {
2207: printf("maximum name length exceeded, truncating\n");
2208: return;
2209: }
2210: input_path[input_pathp][strlen(input_path[input_pathp])] = c;
2211: }
2212: }
2213:
2214: /*
2215: * compare - check if a filename matches the pattern entered by the user.
2216: * Handles '*', '?', and '[]'.
2217: */
2218: compare(s1, s2, at_start)
2219: char *s1, *s2;
2220: short at_start;
2221: {
2222: register char c, *s;
2223:
2224: s = s2;
2225: while (c = *s1) {
2226: if (c == '*') {
2227: if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
2228: return(0);
2229: if (*++s1 == 0)
2230: return(1);
2231: while (*s2) {
2232: if (compare(s1, s2, 0))
2233: return(1);
2234: if (error)
2235: return(0);
2236: s2++;
2237: }
2238: }
2239: if (*s2 == 0)
2240: return(0);
2241: if (c == '\\') {
2242: s1++;
2243: goto compare_chars;
2244: }
2245: if (c == '?') {
2246: if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
2247: return(0);
2248: s1++;
2249: s2++;
2250: continue;
2251: }
2252: if (c == '[') {
2253: s1++;
2254: if (*s2 >= *s1++) {
2255: if (*s1++ != '-') {
2256: printf("missing '-'\n");
2257: error++;
2258: return(0);
2259: }
2260: if (*s2 <= *s1++) {
2261: if (*s1++ != ']') {
2262: printf("missing ']'");
2263: error++;
2264: return(0);
2265: }
2266: s2++;
2267: continue;
2268: }
2269: }
2270: }
2271: compare_chars:
2272: if (*s1++ == *s2++)
2273: continue;
2274: else
2275: return(0);
2276: }
2277: if (*s1 == *s2)
2278: return(1);
2279: return(0);
2280: }
2281:
2282: /*
2283: * freemem - free the memory allocated to the filenames structure.
2284: */
2285: freemem(p, numb)
2286: struct filenames *p;
2287: int numb;
2288: {
2289: register int i, j;
2290:
2291: if (numb == 0)
2292: return;
2293: for (i = 0; i < numb; i++, p++) {
2294: for (j = 0; j <= p->len; j++)
2295: free(p->fname[j]);
2296: free((char *)p->fname);
2297: }
2298: }
2299:
2300: /*
2301: * print_path - print the pathname held in p.
2302: */
2303: print_path(p, pntr)
2304: char *p[];
2305: short pntr;
2306: {
2307: register int i;
2308:
2309: printf("/");
2310: if (pntr >= 0) {
2311: for (i = 0; i < pntr; i++)
2312: printf("%s/", p[i]);
2313: printf("%s", p[pntr]);
2314: }
2315: }
2316:
2317: /*
2318: * fill - fill a section with a value or string.
2319: * addr,count:fill=[value, "string"].
2320: */
2321: fill()
2322: {
2323: register char *cptr;
2324: register int i;
2325: short eof_flag, end = 0, eof = 0;
2326: long temp, tcount, taddr;
2327:
2328: if (!wrtflag) {
2329: printf("not opened for write '-w'\n");
2330: error++;
2331: return;
2332: }
2333: temp = expr();
2334: if (error)
2335: return;
2336: if ((cptr = getblk(addr)) == 0)
2337: return;
2338: if (type == NUMB)
2339: eof_flag = 0;
2340: else
2341: eof_flag = 1;
2342: taddr = addr;
2343: switch (objsz) {
2344: case LONG:
2345: addr &= ~(LONG - 1);
2346: break;
2347: case SHORT:
2348: addr &= ~(SHORT - 1);
2349: temp &= 0177777L;
2350: break;
2351: case CHAR:
2352: temp &= 0377;
2353: }
2354: cur_bytes -= taddr - addr;
2355: cptr += blkoff(fs, addr);
2356: tcount = check_addr(eof_flag, &end, &eof, 0);
2357: for (i = 0; i < tcount; i++) {
2358: switch (objsz) {
2359: case LONG:
2360: *(long *)cptr = temp;
2361: break;
2362: case SHORT:
2363: *(short *)cptr = temp;
2364: break;
2365: case CHAR:
2366: *cptr = temp;
2367: }
2368: cptr += objsz;
2369: }
2370: addr += (tcount - 1) * objsz;
2371: cur_bytes += (tcount - 1) * objsz;
2372: put(temp, objsz);
2373: if (eof) {
2374: printf("end of file\n");
2375: error++;
2376: } else if (end) {
2377: printf("end of block\n");
2378: error++;
2379: }
2380: }
2381:
2382: /*
2383: * get - read a byte, short or long from the file system.
2384: * The entire block containing the desired item is read
2385: * and the appropriate data is extracted and returned.
2386: */
2387: long
2388: get(lngth)
2389: short lngth;
2390: {
2391:
2392: register char *bptr;
2393: long temp = addr;
2394:
2395: objsz = lngth;
2396: if (objsz == INODE || objsz == SHORT)
2397: temp &= ~(SHORT - 1);
2398: else if (objsz == DIRECTORY || objsz == LONG)
2399: temp &= ~(LONG - 1);
2400: if ((bptr = getblk(temp)) == 0)
2401: return(-1);
2402: bptr += blkoff(fs, temp);
2403: switch (objsz) {
2404: case CHAR:
2405: return((long)*bptr);
2406: case SHORT:
2407: case INODE:
2408: return((long)(*(short *)bptr));
2409: case LONG:
2410: case DIRECTORY:
2411: return(*(long *)bptr);
2412: }
2413: return(0);
2414: }
2415:
2416: /*
2417: * cgrp_check - make sure that we don't bump the cylinder group
2418: * beyond the total number of cylinder groups or before the start.
2419: */
2420: cgrp_check(cgrp)
2421: long cgrp;
2422: {
2423: if (cgrp < 0) {
2424: if (objsz == CGRP)
2425: printf("beginning of cylinder groups\n");
2426: else
2427: printf("beginning of super blocks\n");
2428: error++;
2429: return(0);
2430: }
2431: if (cgrp >= fs->fs_ncg) {
2432: if (objsz == CGRP)
2433: printf("end of cylinder groups\n");
2434: else
2435: printf("end of super blocks\n");
2436: error++;
2437: return(0);
2438: }
2439: if (objsz == CGRP)
2440: return(cgtod(fs, cgrp) << FRGSHIFT);
2441: else
2442: return(cgsblock(fs, cgrp) << FRGSHIFT);
2443: }
2444:
2445: /*
2446: * icheck - make sure we can read the block containing the inode
2447: * and determine the filesize (0 if inode not allocated). Return
2448: * 0 if error otherwise return the mode.
2449: */
2450: icheck(address)
2451: long address;
2452: {
2453: register char *cptr;
2454: register struct dinode *ip;
2455:
2456: if ((cptr = getblk(address)) == 0)
2457: return(0);
2458: cptr += blkoff(fs, address);
2459: ip = (struct dinode *)cptr;
2460: if ((ip->di_mode & IFMT) == 0) {
2461: if (!override) {
2462: printf("inode not allocated\n");
2463: error++;
2464: return(0);
2465: }
2466: blocksize = filesize = 0;
2467: } else {
2468: trapped++;
2469: filesize = ip->di_size;
2470: blocksize = filesize * 2;
2471: }
2472: return(ip->di_mode);
2473: }
2474:
2475: /*
2476: * getdirslot - get the address of the directory slot desired.
2477: */
2478: getdirslot(slot)
2479: short slot;
2480: {
2481: register char *cptr;
2482: register struct direct *dirp;
2483: register short i;
2484: char *string = &scratch[0];
2485: short bod = 0, mode, temp;
2486:
2487: if (slot < 0) {
2488: slot = 0;
2489: bod++;
2490: }
2491: if (type != DIRECTORY) {
2492: if (type == BLOCK)
2493: string = "block";
2494: else
2495: string = "fragment";
2496: addr = bod_addr;
2497: if ((cptr = getblk(addr)) == 0)
2498: return(0);
2499: cptr += blkoff(fs, addr);
2500: cur_bytes = 0;
2501: dirp = (struct direct *)cptr;
2502: for (dirslot = 0; dirslot < slot; dirslot++) {
2503: dirp = (struct direct *)cptr;
2504: if (blocksize > filesize) {
2505: if (cur_bytes + dirp->d_reclen >= filesize) {
2506: printf("end of file\n");
2507: erraddr = addr;
2508: errcur_bytes = cur_bytes;
2509: stringsize = STRINGSIZE(dirp);
2510: error++;
2511: return(addr);
2512: }
2513: } else {
2514: if (cur_bytes + dirp->d_reclen >= blocksize) {
2515: printf("end of %s\n", string);
2516: erraddr = addr;
2517: errcur_bytes = cur_bytes;
2518: stringsize = STRINGSIZE(dirp);
2519: error++;
2520: return(addr);
2521: }
2522: }
2523: cptr += dirp->d_reclen;
2524: addr += dirp->d_reclen;
2525: cur_bytes += dirp->d_reclen;
2526: }
2527: if (bod) {
2528: if (blocksize > filesize)
2529: printf("beginning of file\n");
2530: else
2531: printf("beginning of %s\n", string);
2532: erraddr = addr;
2533: errcur_bytes = cur_bytes;
2534: error++;
2535: }
2536: stringsize = STRINGSIZE(dirp);
2537: return(addr);
2538: } else {
2539: addr = cur_ino;
2540: if ((mode = icheck(addr)) == 0)
2541: return(0);
2542: if (!override && (mode & IFDIR) == 0) {
2543: printf("inode is not a directory\n");
2544: error++;
2545: return(0);
2546: }
2547: temp = slot;
2548: i = cur_bytes = 0;
2549: for (;;) {
2550: if (i == 0 || bcomp(addr)) {
2551: error = 0;
2552: if ((addr=(bmap(i++) << FRGSHIFT)) == 0)
2553: break;
2554: if ((cptr = getblk(addr)) == 0)
2555: break;
2556: cptr += blkoff(fs, addr);
2557: }
2558: dirp = (struct direct *)cptr;
2559: value = dirp->d_ino;
2560: if (!temp--)
2561: break;
2562: if (cur_bytes + dirp->d_reclen >= filesize) {
2563: printf("end of file\n");
2564: dirslot = slot - temp - 1;
2565: objsz = DIRECTORY;
2566: erraddr = addr;
2567: errcur_bytes = cur_bytes;
2568: stringsize = STRINGSIZE(dirp);
2569: error++;
2570: return(addr);
2571: }
2572: addr += dirp->d_reclen;
2573: cptr += dirp->d_reclen;
2574: cur_bytes += dirp->d_reclen;
2575: }
2576: dirslot = slot;
2577: objsz = DIRECTORY;
2578: if (bod) {
2579: printf("beginning of file\n");
2580: erraddr = addr;
2581: errcur_bytes = cur_bytes;
2582: error++;
2583: }
2584: stringsize = STRINGSIZE(dirp);
2585: return(addr);
2586: }
2587: }
2588:
2589: /*
2590: * putf - print a byte as an ascii character if possible.
2591: * The exceptions are tabs, newlines, backslashes
2592: * and nulls which are printed as the standard C
2593: * language escapes. Characters which are not
2594: * recognized are printed as \?.
2595: */
2596: putf(c)
2597: register char c;
2598: {
2599:
2600: if (c<=037 || c>=0177 || c=='\\') {
2601: printf("\\");
2602: switch (c) {
2603: case '\\':
2604: printf("\\");
2605: break;
2606: case '\t':
2607: printf("t");
2608: break;
2609: case '\n':
2610: printf("n");
2611: break;
2612: case '\0':
2613: printf("0");
2614: break;
2615: default:
2616: printf("?");
2617: }
2618: }
2619: else {
2620: printf("%c", c);
2621: printf(" ");
2622: }
2623: }
2624:
2625: /*
2626: * put - write an item into the buffer for the current address
2627: * block. The value is checked to make sure that it will
2628: * fit in the size given without truncation. If successful,
2629: * the entire block is written back to the file system.
2630: */
2631: put(item,lngth)
2632: long item;
2633: short lngth;
2634: {
2635:
2636: register char *bptr, *sbptr;
2637: register long *vptr;
2638: long s_err,nbytes;
2639: long olditem;
2640:
2641: if (!wrtflag) {
2642: printf("not opened for write '-w'\n");
2643: error++;
2644: return;
2645: }
2646: objsz = lngth;
2647: if ((sbptr = getblk(addr)) == 0)
2648: return;
2649: bptr = sbptr + blkoff(fs, addr);
2650: switch (objsz) {
2651: case LONG:
2652: case DIRECTORY:
2653: olditem = *(long *)bptr;
2654: *(long *)bptr = item;
2655: break;
2656: case SHORT:
2657: case INODE:
2658: olditem = (long)*(short *)bptr;
2659: item &= 0177777L;
2660: *(short *)bptr = item;
2661: break;
2662: case CHAR:
2663: olditem = (long)*bptr;
2664: item &= 0377;
2665: *bptr = lobyte(loword(item));
2666: break;
2667: default:
2668: error++;
2669: return;
2670: }
2671: if ((s_err = lseek(fd, addr & fs->fs_bmask, 0)) == -1) {
2672: error++;
2673: printf("seek error : %x\n",addr);
2674: return(0);
2675: }
2676: if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
2677: error++;
2678: printf("write error : addr = %x\n",addr);
2679: printf(" : s_err = %x\n",s_err);
2680: printf(" : nbytes = %x\n",nbytes);
2681: return(0);
2682: }
2683: if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
2684: index(base);
2685: print(olditem, 8, -8, 0);
2686: printf("\t=\t");
2687: print(item, 8, -8, 0);
2688: printf("\n");
2689: } else {
2690: if (objsz == DIRECTORY) {
2691: addr = cur_dir;
2692: fprnt('?', 'd');
2693: } else {
2694: addr = cur_ino;
2695: objsz = INODE;
2696: fprnt('?', 'i');
2697: }
2698: }
2699: return;
2700: }
2701:
2702: /*
2703: * getblk - check if the desired block is in the file system.
2704: * Search the incore buffers to see if the block is already
2705: * available. If successful, unlink the buffer control block
2706: * from its position in the buffer list and re-insert it at
2707: * the head of the list. If failure, use the last buffer
2708: * in the list for the desired block. Again, this control
2709: * block is placed at the head of the list. This process
2710: * will leave commonly requested blocks in the in-core buffers.
2711: * Finally, a pointer to the buffer is returned.
2712: */
2713: char *
2714: getblk(address)
2715: long address;
2716: {
2717:
2718: register struct buf *bp;
2719: long s_err, nbytes;
2720: unsigned long block;
2721:
2722: read_requests++;
2723: block = lblkno(fs, address);
2724: if (block >= fragstoblks(fs, fs->fs_size)) {
2725: printf("block exceeds maximum block in file system\n");
2726: error++;
2727: return(0);
2728: }
2729: for (bp=bhdr.fwd; bp!= &bhdr; bp=bp->fwd)
2730: if (bp->valid && bp->blkno==block)
2731: goto xit;
2732: actual_disk_reads++;
2733: bp = bhdr.back;
2734: bp->blkno = block;
2735: bp->valid = 0;
2736: if ((s_err = lseek(fd, address & fs->fs_bmask, 0)) == -1) {
2737: error++;
2738: printf("seek error : %x\n",address);
2739: return(0);
2740: }
2741: if ((nbytes = read(fd, bp->blkaddr, BLKSIZE)) != BLKSIZE) {
2742: error++;
2743: printf("read error : addr = %x\n",address);
2744: printf(" : s_err = %x\n",s_err);
2745: printf(" : nbytes = %x\n",nbytes);
2746: return(0);
2747: }
2748: bp->valid++;
2749: xit: bp->back->fwd = bp->fwd;
2750: bp->fwd->back = bp->back;
2751: insert(bp);
2752: return(bp->blkaddr);
2753: }
2754:
2755: /*
2756: * insert - place the designated buffer control block
2757: * at the head of the linked list of buffers.
2758: */
2759: insert(bp)
2760: register struct buf *bp;
2761: {
2762:
2763: bp->back = &bhdr;
2764: bp->fwd = bhdr.fwd;
2765: bhdr.fwd->back = bp;
2766: bhdr.fwd = bp;
2767: }
2768:
2769: /*
2770: * err - called on interrupts. Set the current address
2771: * back to the last address stored in erraddr. Reset all
2772: * appropriate flags. A reset call is made to return
2773: * to the main loop;
2774: */
2775: err()
2776: {
2777: freemem(filenames, nfiles);
2778: nfiles = 0;
2779: signal(2,err);
2780: addr = erraddr;
2781: cur_ino = errino;
2782: cur_inum = errinum;
2783: cur_bytes = errcur_bytes;
2784: error = 0;
2785: c_count = 0;
2786: printf("\n?\n");
2787: fseek(stdin, 0L, 2);
2788: longjmp(env,0);
2789: }
2790:
2791: /*
2792: * devcheck - check that the given mode represents a
2793: * special device. The IFCHR bit is on for both
2794: * character and block devices.
2795: */
2796: devcheck(md)
2797: register short md;
2798: {
2799: if (override)
2800: return(0);
2801: if (md & IFCHR)
2802: return(0);
2803: printf("not character or block device\n");
2804: error++;
2805: return(1);
2806: }
2807:
2808: /*
2809: * nullblk - return error if address is zero. This is done
2810: * to prevent block 0 from being used as an indirect block
2811: * for a large file or as a data block for a small file.
2812: */
2813: nullblk(bn)
2814: long bn;
2815: {
2816: if (bn != 0)
2817: return(0);
2818: printf("non existent block\n");
2819: error++;
2820: return(1);
2821: }
2822:
2823: /*
2824: * puta - put ascii characters into a buffer. The string
2825: * terminates with a quote or newline. The leading quote,
2826: * which is optional for directory names, was stripped off
2827: * by the assignment case in the main loop.
2828: */
2829: puta()
2830: {
2831: register char *cptr, c;
2832: register int i;
2833: char *sbptr;
2834: short terror = 0;
2835: long maxchars, s_err, nbytes, temp;
2836: long taddr = addr, tcount = 0, item, olditem = 0;
2837:
2838: if (!wrtflag) {
2839: printf("not opened for write '-w'\n");
2840: error++;
2841: return;
2842: }
2843: if ((sbptr = getblk(addr)) == 0)
2844: return;
2845: cptr = sbptr + blkoff(fs, addr);
2846: if (objsz == DIRECTORY) {
2847: if (acting_on_directory)
2848: maxchars = stringsize - 1;
2849: else
2850: maxchars = LONG;
2851: } else if (objsz == INODE)
2852: maxchars = objsz - (addr - cur_ino);
2853: else
2854: maxchars = min(blocksize - cur_bytes, filesize - cur_bytes);
2855: while ((c = getachar()) != '"') {
2856: if (tcount >= maxchars) {
2857: printf("string too long\n");
2858: if (objsz == DIRECTORY)
2859: addr = cur_dir;
2860: else if (acting_on_inode || objsz == INODE)
2861: addr = cur_ino;
2862: else
2863: addr = taddr;
2864: erraddr = addr;
2865: errcur_bytes = cur_bytes;
2866: terror++;
2867: break;
2868: }
2869: tcount++;
2870: if (c == '\n') {
2871: ungetachar(c);
2872: break;
2873: }
2874: temp = (long)*cptr;
2875: olditem <<= BITSPERCHAR;
2876: olditem += temp & 0xff;
2877: if (c == '\\') {
2878: switch (c = getachar()) {
2879: case 't':
2880: *cptr++ = '\t';
2881: break;
2882: case 'n':
2883: *cptr++ = '\n';
2884: break;
2885: case '0':
2886: *cptr++ = '\0';
2887: break;
2888: default:
2889: *cptr++ = c;
2890: break;
2891: }
2892: }
2893: else
2894: *cptr++ = c;
2895: }
2896: if (objsz == DIRECTORY && acting_on_directory)
2897: for (i = tcount; i <= maxchars; i++)
2898: *cptr++ = '\0';
2899: if ((s_err = lseek(fd, addr & fs->fs_bmask, 0)) == -1) {
2900: error++;
2901: printf("seek error : %x\n",addr);
2902: return(0);
2903: }
2904: if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
2905: error++;
2906: printf("write error : addr = %x\n",addr);
2907: printf(" : s_err = %x\n",s_err);
2908: printf(" : nbytes = %x\n",nbytes);
2909: return(0);
2910: }
2911: if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
2912: addr += tcount;
2913: cur_bytes += tcount;
2914: taddr = addr;
2915: if (objsz != CHAR) {
2916: addr &= ~(objsz - 1);
2917: cur_bytes -= taddr - addr;
2918: }
2919: if (addr == taddr) {
2920: addr -= objsz;
2921: taddr = addr;
2922: }
2923: tcount = LONG - (taddr - addr);
2924: index(base);
2925: if ((cptr = getblk(addr)) == 0)
2926: return;
2927: cptr += blkoff(fs, addr);
2928: switch (objsz) {
2929: case LONG:
2930: item = *(long *)cptr;
2931: if (tcount < LONG) {
2932: olditem <<= tcount * BITSPERCHAR;
2933: temp = 1;
2934: for (i = 0; i < (tcount*BITSPERCHAR); i++)
2935: temp <<= 1;
2936: olditem += item & (temp - 1);
2937: }
2938: break;
2939: case SHORT:
2940: item = (long)*(short *)cptr;
2941: if (tcount < SHORT) {
2942: olditem <<= tcount * BITSPERCHAR;
2943: temp = 1;
2944: for (i = 0; i < (tcount * BITSPERCHAR); i++)
2945: temp <<= 1;
2946: olditem += item & (temp - 1);
2947: }
2948: olditem &= 0177777L;
2949: break;
2950: case CHAR:
2951: item = (long)*cptr;
2952: olditem &= 0377;
2953: }
2954: print(olditem, 8, -8, 0);
2955: printf("\t=\t");
2956: print(item, 8, -8, 0);
2957: printf("\n");
2958: } else {
2959: if (objsz == DIRECTORY) {
2960: addr = cur_dir;
2961: fprnt('?', 'd');
2962: } else {
2963: addr = cur_ino;
2964: objsz = INODE;
2965: fprnt('?', 'i');
2966: }
2967: }
2968: if (terror)
2969: error++;
2970: }
2971:
2972: /*
2973: * fprnt - print data. 'count' elements are printed where '*' will
2974: * print an entire blocks worth or up to the eof, whichever
2975: * occurs first. An error will occur if crossing a block boundary
2976: * is attempted since consecutive blocks don't usually have
2977: * meaning. Current print types:
2978: * / b - print as bytes (base sensitive)
2979: * c - print as characters
2980: * o O - print as octal shorts (longs)
2981: * d D - print as decimal shorts (longs)
2982: * x X - print as hexadecimal shorts (longs)
2983: * ? c - print as cylinder groups
2984: * d - print as directories
2985: * i - print as inodes
2986: * s - print as super blocks
2987: */
2988: fprnt(style, po)
2989: register char style, po;
2990: {
2991: register int i;
2992: register struct fs *sb;
2993: register struct cg *cg;
2994: register struct direct *dirp;
2995: register struct dinode *ip;
2996: int tbase;
2997: char c, *cptr, *p;
2998: long tinode, tcount, temp, taddr;
2999: short offset, mode, end = 0, eof = 0, eof_flag;
3000: unsigned short *sptr;
3001: unsigned long *lptr;
3002:
3003: laststyle = style;
3004: lastpo = po;
3005: should_print = 0;
3006: if (count != 1) {
3007: if (clear) {
3008: count = 1;
3009: star = 0;
3010: clear = 0;
3011: } else
3012: clear = 1;
3013: }
3014: tcount = count;
3015: offset = blkoff(fs, addr);
3016:
3017: if (style == '/') {
3018: if (type == NUMB)
3019: eof_flag = 0;
3020: else
3021: eof_flag = 1;
3022: switch (po) {
3023:
3024: case 'c': /* print as characters */
3025: case 'b': /* or bytes */
3026: if ((cptr = getblk(addr)) == 0)
3027: return;
3028: cptr += offset;
3029: objsz = CHAR;
3030: tcount = check_addr(eof_flag, &end, &eof, 0);
3031: if (tcount) {
3032: for (i=0; tcount--; i++) {
3033: if (i % 16 == 0) {
3034: if (i)
3035: printf("\n");
3036: index(base);
3037: }
3038: if (po == 'c') {
3039: putf(*cptr++);
3040: if ((i + 1) % 16)
3041: printf(" ");
3042: } else {
3043: if ((i + 1) % 16 == 0)
3044: print(*cptr++ & 0377,
3045: 2,-2,0);
3046: else
3047: print(*cptr++ & 0377,
3048: 4,-2,0);
3049: }
3050: addr += CHAR;
3051: cur_bytes += CHAR;
3052: }
3053: printf("\n");
3054: }
3055: addr -= CHAR;
3056: erraddr = addr;
3057: cur_bytes -= CHAR;
3058: errcur_bytes = cur_bytes;
3059: if (eof) {
3060: printf("end of file\n");
3061: error++;
3062: } else if (end) {
3063: if (type == BLOCK)
3064: printf("end of block\n");
3065: else
3066: printf("end of fragment\n");
3067: error++;
3068: }
3069: return;
3070:
3071: case 'o': /* print as octal shorts */
3072: tbase = OCTAL;
3073: goto otx;
3074: case 'd': /* print as decimal shorts */
3075: tbase = DECIMAL;
3076: goto otx;
3077: case 'x': /* print as hex shorts */
3078: tbase = HEX;
3079: otx:
3080: if ((cptr = getblk(addr)) == 0)
3081: return;
3082: taddr = addr;
3083: addr &= ~(SHORT - 1);
3084: cur_bytes -= taddr - addr;
3085: cptr += blkoff(fs, addr);
3086: sptr = (unsigned short *)cptr;
3087: objsz = SHORT;
3088: tcount = check_addr(eof_flag, &end, &eof, 0);
3089: if (tcount) {
3090: for (i=0; tcount--; i++) {
3091: sptr = (unsigned short *)
3092: print_check(sptr, &tcount, tbase, i);
3093: switch (po) {
3094: case 'o':
3095: printf("%06o ",*sptr++);
3096: break;
3097: case 'd':
3098: printf("%05d ",*sptr++);
3099: break;
3100: case 'x':
3101: printf("%04x ",*sptr++);
3102: }
3103: addr += SHORT;
3104: cur_bytes += SHORT;
3105: }
3106: printf("\n");
3107: }
3108: addr -= SHORT;
3109: erraddr = addr;
3110: cur_bytes -= SHORT;
3111: errcur_bytes = cur_bytes;
3112: if (eof) {
3113: printf("end of file\n");
3114: error++;
3115: } else if (end) {
3116: if (type == BLOCK)
3117: printf("end of block\n");
3118: else
3119: printf("end of fragment\n");
3120: error++;
3121: }
3122: return;
3123:
3124: case 'O': /* print as octal longs */
3125: tbase = OCTAL;
3126: goto OTX;
3127: case 'D': /* print as decimal longs */
3128: tbase = DECIMAL;
3129: goto OTX;
3130: case 'X': /* print as hex longs */
3131: tbase = HEX;
3132: OTX:
3133: if ((cptr = getblk(addr)) == 0)
3134: return;
3135: taddr = addr;
3136: addr &= ~(LONG - 1);
3137: cur_bytes -= taddr - addr;
3138: cptr += blkoff(fs, addr);
3139: lptr = (unsigned long *)cptr;
3140: objsz = LONG;
3141: tcount = check_addr(eof_flag, &end, &eof, 0);
3142: if (tcount) {
3143: for (i=0; tcount--; i++) {
3144: lptr =
3145: print_check(lptr, &tcount, tbase, i);
3146: switch (po) {
3147: case 'O':
3148: printf("%011o ",*lptr++);
3149: break;
3150: case 'D':
3151: printf("%010u ",*lptr++);
3152: break;
3153: case 'X':
3154: printf("%08x ",*lptr++);
3155: }
3156: addr += LONG;
3157: cur_bytes += LONG;
3158: }
3159: printf("\n");
3160: }
3161: addr -= LONG;
3162: erraddr = addr;
3163: cur_bytes -= LONG;
3164: errcur_bytes = cur_bytes;
3165: if (eof) {
3166: printf("end of file\n");
3167: error++;
3168: } else if (end) {
3169: if (type == BLOCK)
3170: printf("end of block\n");
3171: else
3172: printf("end of fragment\n");
3173: error++;
3174: }
3175: return;
3176:
3177: default:
3178: error++;
3179: printf("no such print option\n");
3180: return;
3181: }
3182: } else
3183: switch (po) {
3184:
3185: case 'c': /* print as cylinder group */
3186: if (type != NUMB)
3187: if (cur_cgrp + count > fs->fs_ncg) {
3188: tcount = fs->fs_ncg - cur_cgrp;
3189: if (!star)
3190: end++;
3191: }
3192: addr &= ~(LONG - 1);
3193: for (; tcount--;) {
3194: erraddr = addr;
3195: errcur_bytes = cur_bytes;
3196: if (type != NUMB) {
3197: addr = cgtod(fs, cur_cgrp)
3198: << FRGSHIFT;
3199: cur_cgrp++;
3200: }
3201: if ((cptr = getblk(addr)) == 0) {
3202: if (cur_cgrp)
3203: cur_cgrp--;
3204: return;
3205: }
3206: cptr += blkoff(fs, addr);
3207: cg = (struct cg *)cptr;
3208: if (type == NUMB) {
3209: cur_cgrp = cg->cg_cgx + 1;
3210: type = objsz = CGRP;
3211: if (cur_cgrp + count - 1 > fs->fs_ncg) {
3212: tcount = fs->fs_ncg - cur_cgrp;
3213: if (!star)
3214: end++;
3215: }
3216: }
3217: if (!override && cg->cg_magic != CG_MAGIC) {
3218: printf("invalid cylinder group ");
3219: printf("magic word\n");
3220: if (cur_cgrp)
3221: cur_cgrp--;
3222: error++;
3223: return;
3224: }
3225: printf("\tcylinder group ");
3226: print(cur_cgrp - 1, 0, 0, 0);
3227: printf(":\n");
3228: printf("cg_cgx = ");
3229: print(cg->cg_cgx, 12, -8, 0);
3230: printf("cg_ncyl = ");
3231: print(cg->cg_ncyl, 12, -8, 0);
3232: printf("\ncg_niblk = ");
3233: print(cg->cg_niblk, 12, -8, 0);
3234: printf("cg_ndblk = ");
3235: print(cg->cg_ndblk, 12, -8, 0);
3236: printf("\ncg_rotor = ");
3237: print(cg->cg_rotor, 12, -8, 0);
3238: printf("cg_frotor = ");
3239: print(cg->cg_frotor, 12, -8, 0);
3240: printf("cg_irotor = ");
3241: print(cg->cg_irotor, 12, -8, 0);
3242: printf("\n\tcylinder group summary info:\n");
3243: printf("cs_ndir = ");
3244: print(cg->cg_cs.cs_ndir, 12, -8, 0);
3245: printf("cs_nbfree = ");
3246: print(cg->cg_cs.cs_nbfree, 12, -8, 0);
3247: printf("\ncs_nifree = ");
3248: print(cg->cg_cs.cs_nifree, 12, -8, 0);
3249: printf("cs_nffree = ");
3250: print(cg->cg_cs.cs_nffree, 12, -8, 0);
3251: printf("\n");
3252: if (count == 1)
3253: printf("\tmodified: %s",
3254: ctime(&cg->cg_time));
3255: if (tcount)
3256: printf("\n");
3257: }
3258: cur_cgrp--;
3259: if (end) {
3260: printf("end of cylinder groups\n");
3261: error++;
3262: }
3263: return;
3264:
3265: case 'd': /* print as directories */
3266: if ((cptr = getblk(addr)) == 0)
3267: return;
3268: if (type == NUMB) {
3269: if (fragoff(fs, addr)) {
3270: printf("address must be at the ");
3271: printf("beginning of a fragment\n");
3272: error++;
3273: return;
3274: }
3275: bod_addr = addr;
3276: type = FRAGMENT;
3277: dirslot = 0;
3278: cur_bytes = 0;
3279: blocksize = FRGSIZE;
3280: filesize = FRGSIZE * 2;
3281: }
3282: cptr += offset;
3283: objsz = DIRECTORY;
3284: while (tcount-- && cur_bytes < filesize &&
3285: cur_bytes < blocksize && !bcomp(addr)) {
3286: dirp = (struct direct *)cptr;
3287: tinode = dirp->d_ino;
3288: printf("i#: ");
3289: if (tinode == 0)
3290: printf("free\t");
3291: else
3292: print(tinode, 12, -8, 0);
3293: printf("%s\n",&dirp->d_name[0]);
3294: erraddr = addr;
3295: errcur_bytes = cur_bytes;
3296: addr += dirp->d_reclen;
3297: cptr += dirp->d_reclen;
3298: cur_bytes += dirp->d_reclen;
3299: dirslot++;
3300: }
3301: addr = erraddr;
3302: cur_dir = addr;
3303: cur_bytes = errcur_bytes;
3304: stringsize = STRINGSIZE(dirp);
3305: dirslot--;
3306: if (tcount >= 0 && !star) {
3307: switch (type) {
3308: case FRAGMENT:
3309: printf("end of fragment\n");
3310: break;
3311: case BLOCK:
3312: printf("end of block\n");
3313: break;
3314: default:
3315: printf("end of directory\n");
3316: }
3317: error++;
3318: } else
3319: error = 0;
3320: return;
3321:
3322: case 'i': /* print as inodes */
3323: if ((ip = (struct dinode *)getblk(addr)) == 0)
3324: return;
3325: for (i=1; i < fs->fs_ncg; i++)
3326: if (addr < (cgimin(fs,i) << FRGSHIFT))
3327: break;
3328: i--;
3329: offset /= INODE;
3330: temp = (addr - (cgimin(fs,i) << FRGSHIFT)) >> FRGSHIFT;
3331: temp = (i * fs->fs_ipg) + fragstoblks(fs,temp) *
3332: INOPB(fs) + offset;
3333: if (count + offset > INOPB(fs)) {
3334: tcount = INOPB(fs) - offset;
3335: if (!star)
3336: end++;
3337: }
3338: objsz = INODE;
3339: ip += offset;
3340: for (i=0; tcount--; ip++, temp++) {
3341: if ((mode = icheck(addr)) == 0)
3342: if (!override)
3343: continue;
3344: p = " ugtrwxrwxrwx";
3345:
3346: switch (mode & IFMT) {
3347: case IFDIR:
3348: c = 'd';
3349: break;
3350: case IFCHR:
3351: c = 'c';
3352: break;
3353: case IFBLK:
3354: c = 'b';
3355: break;
3356: case IFREG:
3357: c = '-';
3358: break;
3359: /* case IFIFO:
3360: c = 'p';
3361: break; SYSTEM V only */
3362: case IFLNK:
3363: c = 'l';
3364: break;
3365: case IFSOCK:
3366: c = 's';
3367: break;
3368: default:
3369: c = '?';
3370: if (!override)
3371: goto empty;
3372:
3373: }
3374: printf("i#: ");
3375: print(temp,12,-8,0);
3376: printf(" md: ");
3377: printf("%c", c);
3378: for (mode = mode << 4; *++p; mode = mode << 1) {
3379: if (mode & IFREG)
3380: printf("%c", *p);
3381: else
3382: printf("-");
3383: }
3384: printf(" uid: ");
3385: print(ip->di_uid,8,-4,0);
3386: printf(" gid: ");
3387: print(ip->di_gid,8,-4,0);
3388: printf("\n");
3389: printf("ln: ");
3390: print(ip->di_nlink,8,-4,0);
3391: printf(" bs: ");
3392: print(ip->di_blocks,12,-8,0);
3393: printf(" sz : ");
3394: print(ip->di_size,12,-8,0);
3395: printf("\n");
3396: if (ip->di_mode & IFCHR) {
3397: printf("maj: ");
3398: print(ip->di_db[1] & 0377,4,-2,0);
3399: printf(" min: ");
3400: print(ip->di_db[0] & 0377,4,-2,0);
3401: printf("\n");
3402: } else {
3403: for (i = 0; i < NDADDR; ) {
3404: if (ip->di_db[i] == 0)
3405: break;
3406: printf("db#%x: ",i);
3407: print(ip->di_db[i],11,-8,0);
3408: if (++i % 4 == 0)
3409: printf("\n");
3410: else
3411: printf(" ");
3412: }
3413: if (i % 4)
3414: printf("\n");
3415: for (i = 0; i < NIADDR; i++) {
3416: if (ip->di_ib[i] == 0)
3417: break;
3418: printf("ib#%x: ",i);
3419: print(ip->di_ib[i],11,-8,0);
3420: printf(" ");
3421: }
3422: if (i)
3423: printf("\n");
3424: }
3425: if (count == 1) {
3426: printf("\taccessed: %s",
3427: ctime(&ip->di_atime));
3428: printf("\tmodified: %s",
3429: ctime(&ip->di_mtime));
3430: printf("\tcreated : %s",
3431: ctime(&ip->di_ctime));
3432: }
3433: if (tcount)
3434: printf("\n");
3435: empty:
3436: if (c == '?' && !override) {
3437: printf("i#: ");
3438: print(temp, 12, -8, 0);
3439: printf(" is unallocated\n");
3440: if (count != 1)
3441: printf("\n");
3442: }
3443: cur_ino = erraddr = addr;
3444: errcur_bytes = cur_bytes;
3445: cur_inum++;
3446: addr = addr + INODE;
3447: }
3448: addr = erraddr;
3449: cur_bytes = errcur_bytes;
3450: cur_inum--;
3451: if (end) {
3452: printf("end of block\n");
3453: error++;
3454: }
3455: return;
3456:
3457: case 's': /* print as super block */
3458: if (cur_cgrp == -1) {
3459: addr = SBLOCK * DEV_BSIZE;
3460: type = NUMB;
3461: }
3462: addr &= ~(LONG - 1);
3463: if (type != NUMB)
3464: if (cur_cgrp + count > fs->fs_ncg) {
3465: tcount = fs->fs_ncg - cur_cgrp;
3466: if (!star)
3467: end++;
3468: }
3469: for (; tcount--;) {
3470: erraddr = addr;
3471: cur_bytes = errcur_bytes;
3472: if (type != NUMB) {
3473: addr = cgsblock(fs, cur_cgrp)
3474: << FRGSHIFT;
3475: cur_cgrp++;
3476: }
3477: if ((cptr = getblk(addr)) == 0) {
3478: if (cur_cgrp)
3479: cur_cgrp--;
3480: return;
3481: }
3482: cptr += blkoff(fs, addr);
3483: sb = (struct fs *)cptr;
3484: if (type == NUMB) {
3485: for (i = 0; i < fs->fs_ncg; i++)
3486: if (addr == cgsblock(fs, i) <<
3487: FRGSHIFT)
3488: break;
3489: if (i == fs->fs_ncg)
3490: cur_cgrp = 0;
3491: else
3492: cur_cgrp = i + 1;
3493: type = objsz = SB;
3494: if (cur_cgrp + count - 1 > fs->fs_ncg) {
3495: tcount = fs->fs_ncg - cur_cgrp;
3496: if (!star)
3497: end++;
3498: }
3499: }
3500: if (sb->fs_magic != FS_MAGIC) {
3501: cur_cgrp = 0;
3502: if (!override) {
3503: printf("invalid super block ");
3504: printf("magic word\n");
3505: cur_cgrp--;
3506: error++;
3507: return;
3508: }
3509: }
3510: if (cur_cgrp == 0)
3511: printf("\tsuper block:\n");
3512: else {
3513: printf("\tsuper block in cylinder ");
3514: printf("group ");
3515: print(cur_cgrp - 1, 0, 0, 0);
3516: printf(":\n");
3517: }
3518: printf("fs_sblkno = ");
3519: print(fs->fs_sblkno, 12, -8, 0);
3520: printf("fs_cblkno = ");
3521: print(fs->fs_cblkno, 12, -8, 0);
3522: printf("fs_iblkno = ");
3523: print(fs->fs_iblkno, 12, -8, 0);
3524: printf("\nfs_dblkno = ");
3525: print(fs->fs_dblkno, 12, -8, 0);
3526: printf("fs_cgoffset = ");
3527: print(fs->fs_cgoffset, 12, -8, 0);
3528: printf("fs_cgmask = ");
3529: print(fs->fs_cgmask, 12, -8, 0);
3530: printf("\nfs_size = ");
3531: print(fs->fs_size, 12, -8, 0);
3532: printf("fs_dsize = ");
3533: print(fs->fs_dsize, 12, -8, 0);
3534: printf("fs_ncg = ");
3535: print(fs->fs_ncg, 12, -8, 0);
3536: printf("\nfs_bsize = ");
3537: print(fs->fs_bsize, 12, -8, 0);
3538: printf("fs_fsize = ");
3539: print(fs->fs_fsize, 12, -8, 0);
3540: printf("fs_frag = ");
3541: print(fs->fs_frag, 12, -8, 0);
3542: printf("\nfs_minfree = ");
3543: print(fs->fs_minfree, 12, -8, 0);
3544: printf("fs_rotdelay = ");
3545: print(fs->fs_rotdelay, 12, -8, 0);
3546: printf("fs_rps = ");
3547: print(fs->fs_rps, 12, -8, 0);
3548: printf("\nfs_bmask = ");
3549: print(fs->fs_bmask, 12, -8, 0);
3550: printf("fs_fmask = ");
3551: print(fs->fs_fmask, 12, -8, 0);
3552: printf("fs_bshift = ");
3553: print(fs->fs_bshift, 12, -8, 0);
3554: printf("\nfs_fshift = ");
3555: print(fs->fs_fshift, 12, -8, 0);
3556: printf("fs_maxcontig = ");
3557: print(fs->fs_maxcontig, 12, -8, 0);
3558: printf("fs_maxbpg = ");
3559: print(fs->fs_maxbpg, 12, -8, 0);
3560: printf("\nfs_fragshift = ");
3561: print(fs->fs_fragshift, 12, -8, 0);
3562: printf("fs_fsbtodb = ");
3563: print(fs->fs_fsbtodb, 12, -8, 0);
3564: printf("fs_sbsize = ");
3565: print(fs->fs_sbsize, 12, -8, 0);
3566: printf("\nfs_csmask = ");
3567: print(fs->fs_csmask, 12, -8, 0);
3568: printf("fs_csshift = ");
3569: print(fs->fs_csshift, 12, -8, 0);
3570: printf("fs_nindir = ");
3571: print(fs->fs_nindir, 12, -8, 0);
3572: printf("\nfs_inopb = ");
3573: print(fs->fs_inopb, 12, -8, 0);
3574: printf("fs_nspf = ");
3575: print(fs->fs_nspf, 12, -8, 0);
3576: printf("fs_csaddr = ");
3577: print(fs->fs_csaddr, 12, -8, 0);
3578: printf("\nfs_cssize = ");
3579: print(fs->fs_cssize, 12, -8, 0);
3580: printf("fs_cgsize = ");
3581: print(fs->fs_cgsize, 12, -8, 0);
3582: printf("fs_ntrak = ");
3583: print(fs->fs_ntrak, 12, -8, 0);
3584: printf("\nfs_nsect = ");
3585: print(fs->fs_nsect, 12, -8, 0);
3586: printf("fs_spc = ");
3587: print(fs->fs_spc, 12, -8, 0);
3588: printf("fs_ncyl = ");
3589: print(fs->fs_ncyl, 12, -8, 0);
3590: printf("\nfs_cpg = ");
3591: print(fs->fs_cpg, 12, -8, 0);
3592: printf("fs_ipg = ");
3593: print(fs->fs_ipg, 12, -8, 0);
3594: printf("fs_fpg = ");
3595: print(fs->fs_fpg, 12, -8, 0);
3596: printf("\nfs_fmod = ");
3597: print(fs->fs_fmod, 12, -8, 0);
3598: printf("fs_clean = ");
3599: print(fs->fs_clean, 12, -8, 0);
3600: printf("fs_ronly = ");
3601: print(fs->fs_ronly, 12, -8, 0);
3602: printf("\nfs_flags = ");
3603: print(fs->fs_flags, 12, -8, 0);
3604: printf("fs_cgrotor = ");
3605: print(fs->fs_cgrotor, 12, -8, 0);
3606: printf("fs_cpc = ");
3607: print(fs->fs_cpc, 12, -8, 0);
3608: printf("\nfs_magic = ");
3609: print(fs->fs_magic, 12, -8, 0);
3610: printf("\n");
3611: printf("\ttotal cylinder group summary ");
3612: printf("info:\n");
3613: printf("cs_ndir = ");
3614: print(fs->fs_cstotal.cs_ndir, 12, -8, 0);
3615: printf("cs_nbfree = ");
3616: print(fs->fs_cstotal.cs_nbfree, 12, -8, 0);
3617: printf("\ncs_nifree = ");
3618: print(fs->fs_cstotal.cs_nifree, 12, -8, 0);
3619: printf("cs_nffree = ");
3620: print(fs->fs_cstotal.cs_nffree, 12, -8, 0);
3621: printf("\n");
3622: if (count == 1)
3623: printf("\tmodified: %s",
3624: ctime(&fs->fs_time));
3625: if (tcount)
3626: printf("\n");
3627: }
3628: cur_cgrp--;
3629: if (end) {
3630: printf("end of super blocks\n");
3631: error++;
3632: }
3633: return;
3634: default:
3635: error++;
3636: printf("no such print option\n");
3637: return;
3638: }
3639: }
3640:
3641: /*
3642: * valid_addr - call check_addr to validate the current address.
3643: */
3644: valid_addr()
3645: {
3646: short eof_flag, end = 0, eof = 0;
3647: long tcount = count;
3648:
3649: if (!trapped)
3650: return(1);
3651: if (cur_bytes < 0) {
3652: cur_bytes = 0;
3653: if (blocksize > filesize) {
3654: printf("beginning of file\n");
3655: } else {
3656: if (type == BLOCK)
3657: printf("beginning of block\n");
3658: else
3659: printf("beginning of fragment\n");
3660: }
3661: error++;
3662: return(0);
3663: }
3664: count = 1;
3665: check_addr(1, &end, &eof, (filesize < blocksize));
3666: count = tcount;
3667: if (eof) {
3668: printf("end of file\n");
3669: error++;
3670: return(0);
3671: }
3672: if (end == 2) {
3673: if (erraddr > addr) {
3674: if (type == BLOCK)
3675: printf("beginning of block\n");
3676: else
3677: printf("beginning of fragment\n");
3678: error++;
3679: return(0);
3680: }
3681: }
3682: if (end) {
3683: if (type == BLOCK)
3684: printf("end of block\n");
3685: else
3686: printf("end of fragment\n");
3687: error++;
3688: return(0);
3689: }
3690: return(1);
3691: }
3692:
3693: /*
3694: * check_addr - check if the address crosses the end of block or
3695: * end of file. Return the proper count.
3696: */
3697: check_addr(eof_flag, end, eof, keep_on)
3698: short eof_flag, *end, *eof, keep_on;
3699: {
3700: long temp, tcount = count, taddr = addr, tcur_bytes = cur_bytes;
3701:
3702: if (bcomp(addr + count * objsz - 1) ||
3703: (keep_on && taddr < (bmap(cur_block) << FRGSHIFT))) {
3704: error = 0;
3705: addr = taddr;
3706: cur_bytes = tcur_bytes;
3707: if (keep_on) {
3708: if (addr < erraddr) {
3709: if (cur_bytes < 0) {
3710: (*end) = 2;
3711: return;
3712: }
3713: temp = cur_block - lblkno(fs, cur_bytes);
3714: cur_block -= temp;
3715: if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
3716: cur_block += temp;
3717: return;
3718: }
3719: temp = tcur_bytes - cur_bytes;
3720: addr += temp;
3721: cur_bytes += temp;
3722: return;
3723: } else {
3724: if (cur_bytes >= filesize) {
3725: (*eof)++;
3726: return;
3727: }
3728: temp = lblkno(fs, cur_bytes) - cur_block;
3729: cur_block += temp;
3730: if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
3731: cur_block -= temp;
3732: return;
3733: }
3734: temp = tcur_bytes - cur_bytes;
3735: addr += temp;
3736: cur_bytes += temp;
3737: return;
3738: }
3739: }
3740: tcount = (blkroundup(fs, addr+1)-addr) / objsz;
3741: if (!star)
3742: (*end) = 2;
3743: }
3744: addr = taddr;
3745: cur_bytes = tcur_bytes;
3746: if (eof_flag) {
3747: if (blocksize > filesize) {
3748: if (cur_bytes >= filesize) {
3749: tcount = 0;
3750: (*eof)++;
3751: } else if (tcount > (filesize - cur_bytes) / objsz) {
3752: tcount = (filesize - cur_bytes) / objsz;
3753: if (!star || tcount == 0)
3754: (*eof)++;
3755: }
3756: } else {
3757: if (cur_bytes >= blocksize) {
3758: tcount = 0;
3759: (*end)++;
3760: } else if (tcount > (blocksize - cur_bytes) / objsz) {
3761: tcount = (blocksize - cur_bytes) / objsz;
3762: if (!star || tcount == 0)
3763: (*end)++;
3764: }
3765: }
3766: }
3767: return(tcount);
3768: }
3769:
3770: /*
3771: * print_check - check if the index needs to be printed and delete
3772: * rows of zeros from the output.
3773: */
3774: unsigned long *
3775: print_check(lptr, tcount, tbase, i)
3776: unsigned long *lptr;
3777: long *tcount;
3778: short tbase;
3779: register int i;
3780: {
3781: register int j, k, temp = BYTESPERLINE / objsz;
3782: short first_time = 0;
3783: unsigned long *tlptr;
3784: unsigned short *tsptr, *sptr;
3785:
3786: sptr = (unsigned short *)lptr;
3787: if (i == 0)
3788: first_time = 1;
3789: if (i % temp == 0) {
3790: if (*tcount >= temp - 1) {
3791: if (objsz == SHORT)
3792: tsptr = sptr;
3793: else
3794: tlptr = lptr;
3795: k = *tcount - 1;
3796: for (j = i; k--; j++)
3797: if (objsz == SHORT) {
3798: if (*tsptr++ != 0)
3799: break;
3800: } else {
3801: if (*tlptr++ != 0)
3802: break;
3803: }
3804: if (j > (i + temp - 1)) {
3805: j = (j - i) / temp;
3806: while (j-- > 0) {
3807: if (objsz == SHORT)
3808: sptr += temp;
3809: else
3810: lptr += temp;
3811: *tcount -= temp;
3812: i += temp;
3813: addr += BYTESPERLINE;
3814: cur_bytes += BYTESPERLINE;
3815: }
3816: if (first_time)
3817: printf("*");
3818: else
3819: printf("\n*");
3820: }
3821: if (i)
3822: printf("\n");
3823: index(tbase);
3824: } else {
3825: if (i)
3826: printf("\n");
3827: index(tbase);
3828: }
3829: }
3830: if(objsz == SHORT)
3831: return((unsigned long *)sptr);
3832: else
3833: return(lptr);
3834: }
3835:
3836: /*
3837: * index - print a byte index for the printout in base b
3838: * with leading zeros.
3839: */
3840: index(b)
3841: int b;
3842: {
3843: int tbase = base;
3844:
3845: base = b;
3846: print(addr, 8, 8, 1);
3847: printf(":\t");
3848: base = tbase;
3849: }
3850:
3851: /*
3852: * print - print out the value to digits places with/without
3853: * leading zeros and right/left justified in the current base.
3854: */
3855: print(value, fieldsz, digits, lead)
3856: int value, fieldsz, digits, lead;
3857: {
3858: register int i, left = 0;
3859: char mode = BASE[base - OCTAL];
3860: char *string = &scratch[0];
3861:
3862: if (digits < 0) {
3863: left = 1;
3864: digits *= -1;
3865: }
3866: if (base != HEX)
3867: if (digits)
3868: digits = digits + (digits - 1)/((base >> 1) - 1) + 1;
3869: else
3870: digits = 1;
3871: if (lead) {
3872: if (left)
3873: sprintf(string, "%%%c%d%d.%d%c",
3874: '-', 0, digits, lead, mode);
3875: else
3876: sprintf(string, "%%%d%d.%d%c", 0, digits, lead, mode);
3877: } else {
3878: if (left)
3879: sprintf(string, "%%%c%d%c", '-', digits, mode);
3880: else
3881: sprintf(string, "%%%d%c", digits, mode);
3882: }
3883: printf(string, value);
3884: for (i = 0; i < fieldsz - digits; i++)
3885: printf(" ");
3886: }
3887:
3888: /*
3889: * bcomp - used to check for block over/under flows when stepping through
3890: * a file system.
3891: */
3892: bcomp(addr)
3893: long addr;
3894: {
3895: if (override)
3896: return(0);
3897: if (lblkno(fs, addr) == (bhdr.fwd)->blkno)
3898: return(0);
3899: error++;
3900: return(1);
3901: }
3902:
3903: /*
3904: * bmap - maps the logical block number of a file into
3905: * the corresponding physical block on the file
3906: * system.
3907: */
3908: long
3909: bmap(bn)
3910: long bn;
3911: {
3912: register int i, j;
3913: register struct dinode *ip;
3914: int sh;
3915: long nb;
3916:
3917: ip = (struct dinode *)cur_ino;
3918: if (bn < NDADDR) {
3919: addr = (long)&ip->di_db[bn];
3920: cur_bytes = bn * BLKSIZE;
3921: return(nullblk(nb=get(LONG)) ? 0L : nb);
3922: }
3923:
3924: sh = 1;
3925: bn -= NDADDR;
3926: for (j = NIADDR; j > 0; j--) {
3927: sh *= NINDIR(fs);
3928: if (bn < sh)
3929: break;
3930: bn -= sh;
3931: }
3932: if (j == 0) {
3933: printf("file too big\n");
3934: error++;
3935: return(0L);
3936: }
3937: addr = (long)&ip->di_ib[NIADDR - j];
3938: nb = get(LONG);
3939: if (nb == 0)
3940: return(0L);
3941: for (; j <= NIADDR; j++) {
3942: sh /= NINDIR(fs);
3943: addr = (nb << FRGSHIFT) + ((bn / sh) % NINDIR(fs)) * LONG;
3944: if (nullblk(nb = get(LONG)))
3945: return(0L);
3946: }
3947: return(nb);
3948: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.