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