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