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