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