Print this page
5396 gcc 4.8.2 longjmp errors for cscope-fast
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fs.d/ufs/fsdb/fsdb.c
+++ new/usr/src/cmd/fs.d/ufs/fsdb/fsdb.c
1 1 /*
2 + * Copyright 2015 Gary Mills
2 3 * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
3 4 */
4 5
5 6 /*
6 7 * Copyright (c) 1988 Regents of the University of California.
7 8 * All rights reserved.
8 9 *
9 10 * This code is derived from software contributed to Berkeley by
10 11 * Computer Consoles Inc.
11 12 *
12 13 * Redistribution and use in source and binary forms are permitted
13 14 * provided that: (1) source distributions retain this entire copyright
14 15 * notice and comment, and (2) distributions including binaries display
15 16 * the following acknowledgement: ``This product includes software
16 17 * developed by the University of California, Berkeley and its contributors''
17 18 * in the documentation or other materials provided with the distribution
18 19 * and in all advertising materials mentioning features or use of this
19 20 * software. Neither the name of the University nor the names of its
20 21 * contributors may be used to endorse or promote products derived
21 22 * from this software without specific prior written permission.
22 23 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
23 24 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
24 25 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
25 26 */
26 27
27 28 #ifndef lint
28 29 char copyright[] =
29 30 "@(#) Copyright(c) 1988 Regents of the University of California.\n\
30 31 All rights reserved.\n";
31 32 #endif /* not lint */
32 33
33 34 #ifndef lint
34 35 static char sccsid[] = "@(#)fsdb.c 5.8 (Berkeley) 6/1/90";
35 36 #endif /* not lint */
36 37
37 38 /*
38 39 * fsdb - file system debugger
39 40 *
40 41 * usage: fsdb [-o suboptions] special
41 42 * options/suboptions:
42 43 * -o
43 44 * ? display usage
44 45 * o override some error conditions
45 46 * p="string" set prompt to string
46 47 * w open for write
47 48 */
48 49
49 50 #include <sys/param.h>
50 51 #include <sys/signal.h>
51 52 #include <sys/file.h>
52 53 #include <inttypes.h>
53 54 #include <sys/sysmacros.h>
54 55
55 56 #ifdef sun
56 57 #include <unistd.h>
57 58 #include <stdlib.h>
58 59 #include <string.h>
59 60 #include <fcntl.h>
60 61 #include <signal.h>
61 62 #include <sys/types.h>
62 63 #include <sys/vnode.h>
63 64 #include <sys/mntent.h>
64 65 #include <sys/wait.h>
65 66 #include <sys/fs/ufs_fsdir.h>
66 67 #include <sys/fs/ufs_fs.h>
67 68 #include <sys/fs/ufs_inode.h>
68 69 #include <sys/fs/ufs_acl.h>
69 70 #include <sys/fs/ufs_log.h>
70 71 #else
71 72 #include <sys/dir.h>
72 73 #include <ufs/fs.h>
73 74 #include <ufs/dinode.h>
74 75 #include <paths.h>
75 76 #endif /* sun */
76 77
77 78 #include <stdio.h>
78 79 #include <setjmp.h>
79 80
80 81 #define OLD_FSDB_COMPATIBILITY /* To support the obsoleted "-z" option */
81 82
82 83 #ifndef _PATH_BSHELL
83 84 #define _PATH_BSHELL "/bin/sh"
84 85 #endif /* _PATH_BSHELL */
85 86 /*
86 87 * Defines from the 4.3-tahoe file system, for systems with the 4.2 or 4.3
87 88 * file system.
88 89 */
89 90 #ifndef FS_42POSTBLFMT
90 91 #define cg_blktot(cgp) (((cgp))->cg_btot)
91 92 #define cg_blks(fs, cgp, cylno) (((cgp))->cg_b[cylno])
92 93 #define cg_inosused(cgp) (((cgp))->cg_iused)
93 94 #define cg_blksfree(cgp) (((cgp))->cg_free)
94 95 #define cg_chkmagic(cgp) ((cgp)->cg_magic == CG_MAGIC)
95 96 #endif
96 97
97 98 /*
98 99 * Never changing defines.
99 100 */
100 101 #define OCTAL 8 /* octal base */
101 102 #define DECIMAL 10 /* decimal base */
102 103 #define HEX 16 /* hexadecimal base */
103 104
104 105 /*
105 106 * Adjustable defines.
106 107 */
107 108 #define NBUF 10 /* number of cache buffers */
108 109 #define PROMPTSIZE 80 /* size of user definable prompt */
109 110 #define MAXFILES 40000 /* max number of files ls can handle */
110 111 #define FIRST_DEPTH 10 /* default depth for find and ls */
111 112 #define SECOND_DEPTH 100 /* second try at depth (maximum) */
112 113 #define INPUTBUFFER 1040 /* size of input buffer */
113 114 #define BYTESPERLINE 16 /* bytes per line of /dxo output */
114 115 #define NREG 36 /* number of save registers */
115 116
116 117 #define DEVPREFIX "/dev/" /* Uninteresting part of "special" */
117 118
118 119 #if defined(OLD_FSDB_COMPATIBILITY)
119 120 #define FSDB_OPTIONS "o:wp:z:"
120 121 #else
121 122 #define FSDB_OPTIONS "o:wp:"
122 123 #endif /* OLD_FSDB_COMPATIBILITY */
123 124
124 125
125 126 /*
126 127 * Values dependent on sizes of structs and such.
127 128 */
128 129 #define NUMB 3 /* these three are arbitrary, */
129 130 #define BLOCK 5 /* but must be different from */
130 131 #define FRAGMENT 7 /* the rest (hence odd). */
131 132 #define BITSPERCHAR 8 /* couldn't find it anywhere */
132 133 #define CHAR (sizeof (char))
133 134 #define SHORT (sizeof (short))
134 135 #define LONG (sizeof (long))
135 136 #define U_OFFSET_T (sizeof (u_offset_t)) /* essentially "long long" */
136 137 #define INODE (sizeof (struct dinode))
137 138 #define DIRECTORY (sizeof (struct direct))
138 139 #define CGRP (sizeof (struct cg))
139 140 #define SB (sizeof (struct fs))
140 141 #define BLKSIZE (fs->fs_bsize) /* for clarity */
141 142 #define FRGSIZE (fs->fs_fsize)
142 143 #define BLKSHIFT (fs->fs_bshift)
143 144 #define FRGSHIFT (fs->fs_fshift)
144 145 #define SHADOW_DATA (sizeof (struct ufs_fsd))
145 146
146 147 /*
147 148 * Messy macros that would otherwise clutter up such glamorous code.
148 149 */
149 150 #define itob(i) (((u_offset_t)itod(fs, (i)) << \
150 151 (u_offset_t)FRGSHIFT) + (u_offset_t)itoo(fs, (i)) * (u_offset_t)INODE)
151 152 #define min(x, y) ((x) < (y) ? (x) : (y))
152 153 #define STRINGSIZE(d) ((long)d->d_reclen - \
153 154 ((long)&d->d_name[0] - (long)&d->d_ino))
154 155 #define letter(c) ((((c) >= 'a')&&((c) <= 'z')) ||\
155 156 (((c) >= 'A')&&((c) <= 'Z')))
156 157 #define digit(c) (((c) >= '0') && ((c) <= '9'))
157 158 #define HEXLETTER(c) (((c) >= 'A') && ((c) <= 'F'))
158 159 #define hexletter(c) (((c) >= 'a') && ((c) <= 'f'))
159 160 #define octaldigit(c) (((c) >= '0') && ((c) <= '7'))
160 161 #define uppertolower(c) ((c) - 'A' + 'a')
161 162 #define hextodigit(c) ((c) - 'a' + 10)
162 163 #define numtodigit(c) ((c) - '0')
163 164
164 165 #if !defined(loword)
165 166 #define loword(X) (((ushort_t *)&X)[1])
166 167 #endif /* loword */
167 168
168 169 #if !defined(lobyte)
169 170 #define lobyte(X) (((unsigned char *)&X)[1])
170 171 #endif /* lobyte */
171 172
172 173 /*
173 174 * buffer cache structure.
174 175 */
175 176 static struct lbuf {
176 177 struct lbuf *fwd;
177 178 struct lbuf *back;
178 179 char *blkaddr;
179 180 short valid;
180 181 u_offset_t blkno;
181 182 } lbuf[NBUF], bhdr;
182 183
183 184 /*
184 185 * used to hold save registers (see '<' and '>').
185 186 */
186 187 struct save_registers {
187 188 u_offset_t sv_addr;
188 189 u_offset_t sv_value;
189 190 long sv_objsz;
190 191 } regs[NREG];
191 192
192 193 /*
193 194 * cd, find, and ls use this to hold filenames. Each filename is broken
194 195 * up by a slash. In other words, /usr/src/adm would have a len field
195 196 * of 2 (starting from 0), and filenames->fname[0-2] would hold usr,
196 197 * src, and adm components of the pathname.
197 198 */
198 199 static struct filenames {
199 200 ino_t ino; /* inode */
200 201 long len; /* number of components */
201 202 char flag; /* flag if using SECOND_DEPTH allocator */
202 203 char find; /* flag if found by find */
203 204 char **fname; /* hold components of pathname */
204 205 } *filenames, *top;
205 206
206 207 enum log_enum { LOG_NDELTAS, LOG_ALLDELTAS, LOG_CHECKSCAN };
207 208 #ifdef sun
208 209 struct fs *fs;
209 210 static union {
210 211 struct fs un_filesystem;
211 212 char un_sbsize[SBSIZE];
212 213 } fs_un;
213 214 #define filesystem fs_un.un_filesystem
214 215 #else
215 216 struct fs filesystem, *fs; /* super block */
216 217 #endif /* sun */
217 218
218 219 /*
219 220 * Global data.
220 221 */
221 222 static char *input_path[MAXPATHLEN];
222 223 static char *stack_path[MAXPATHLEN];
223 224 static char *current_path[MAXPATHLEN];
224 225 static char input_buffer[INPUTBUFFER];
225 226 static char *prompt;
226 227 static char *buffers;
227 228 static char scratch[64];
228 229 static char BASE[] = "o u x";
229 230 static char PROMPT[PROMPTSIZE];
230 231 static char laststyle = '/';
231 232 static char lastpo = 'x';
232 233 static short input_pointer;
233 234 static short current_pathp;
234 235 static short stack_pathp;
235 236 static short input_pathp;
236 237 static short cmp_level;
237 238 static int nfiles;
238 239 static short type = NUMB;
239 240 static short dirslot;
240 241 static short fd;
241 242 static short c_count;
242 243 static short error;
243 244 static short paren;
244 245 static short trapped;
245 246 static short doing_cd;
246 247 static short doing_find;
247 248 static short find_by_name;
248 249 static short find_by_inode;
249 250 static short long_list;
250 251 static short recursive;
251 252 static short objsz = SHORT;
252 253 static short override = 0;
253 254 static short wrtflag = O_RDONLY;
254 255 static short base = HEX;
255 256 static short acting_on_inode;
256 257 static short acting_on_directory;
257 258 static short should_print = 1;
258 259 static short clear;
259 260 static short star;
260 261 static u_offset_t addr;
261 262 static u_offset_t bod_addr;
262 263 static u_offset_t value;
263 264 static u_offset_t erraddr;
264 265 static long errcur_bytes;
265 266 static u_offset_t errino;
266 267 static long errinum;
267 268 static long cur_cgrp;
268 269 static u_offset_t cur_ino;
269 270 static long cur_inum;
270 271 static u_offset_t cur_dir;
271 272 static long cur_block;
272 273 static long cur_bytes;
273 274 static long find_ino;
274 275 static u_offset_t filesize;
275 276 static u_offset_t blocksize;
276 277 static long stringsize;
277 278 static long count = 1;
278 279 static long commands;
279 280 static long read_requests;
280 281 static long actual_disk_reads;
281 282 static jmp_buf env;
282 283 static long maxfiles;
283 284 static long cur_shad;
284 285
285 286 #ifndef sun
286 287 extern char *malloc(), *calloc();
287 288 #endif
288 289 static char getachar();
289 290 static char *getblk(), *fmtentry();
290 291
291 292 static offset_t get(short);
292 293 static long bmap();
293 294 static long expr();
294 295 static long term();
295 296 static long getnumb();
296 297 static u_offset_t getdirslot();
297 298 static unsigned long *print_check(unsigned long *, long *, short, int);
298 299
299 300 static void usage(char *);
300 301 static void ungetachar(char);
301 302 static void getnextinput();
302 303 static void eat_spaces();
303 304 static void restore_inode(ino_t);
304 305 static void find();
305 306 static void ls(struct filenames *, struct filenames *, short);
306 307 static void formatf(struct filenames *, struct filenames *);
307 308 static void parse();
308 309 static void follow_path(long, long);
309 310 static void getname();
310 311 static void freemem(struct filenames *, int);
311 312 static void print_path(char **, int);
312 313 static void fill();
313 314 static void put(u_offset_t, short);
314 315 static void insert(struct lbuf *);
315 316 static void puta();
316 317 static void fprnt(char, char);
317 318 static void index();
318 319 #ifdef _LARGEFILE64_SOURCE
319 320 static void printll
320 321 (u_offset_t value, int fieldsz, int digits, int lead);
321 322 #define print(value, fieldsz, digits, lead) \
322 323 printll((u_offset_t)value, fieldsz, digits, lead)
323 324 #else /* !_LARGEFILE64_SOURCE */
324 325 static void print(long value, int fieldsz, int digits, int lead);
325 326 #endif /* _LARGEFILE64_SOURCE */
326 327 static void printsb(struct fs *);
327 328 static void printcg(struct cg *);
328 329 static void pbits(unsigned char *, int);
329 330 static void old_fsdb(int, char *); /* For old fsdb functionality */
330 331
331 332 static int isnumber(char *);
332 333 static int icheck(u_offset_t);
333 334 static int cgrp_check(long);
334 335 static int valid_addr();
335 336 static int match(char *, int);
336 337 static int devcheck(short);
337 338 static int bcomp();
338 339 static int compare(char *, char *, short);
339 340 static int check_addr(short, short *, short *, short);
340 341 static int fcmp();
341 342 static int ffcmp();
342 343
343 344 static int getshadowslot(long);
344 345 static void getshadowdata(long *, int);
345 346 static void syncshadowscan(int);
346 347 static void log_display_header(void);
347 348 static void log_show(enum log_enum);
348 349
349 350 #ifdef sun
350 351 static void err();
351 352 #else
352 353 static int err();
353 354 #endif /* sun */
354 355
355 356 /* Suboption vector */
356 357 static char *subopt_v[] = {
357 358 #define OVERRIDE 0
358 359 "o",
359 360 #define NEW_PROMPT 1
360 361 "p",
361 362 #define WRITE_ENABLED 2
362 363 "w",
363 364 #define ALT_PROMPT 3
364 365 "prompt",
365 366 NULL
366 367 };
367 368
368 369 /*
369 370 * main - lines are read up to the unprotected ('\') newline and
370 371 * held in an input buffer. Characters may be read from the
371 372 * input buffer using getachar() and unread using ungetachar().
372 373 * Reading the whole line ahead allows the use of debuggers
373 374 * which would otherwise be impossible since the debugger
374 375 * and fsdb could not share stdin.
375 376 */
↓ open down ↓ |
364 lines elided |
↑ open up ↑ |
376 377
377 378 int
378 379 main(int argc, char *argv[])
379 380 {
380 381
381 382 char c, *cptr;
382 383 short i;
383 384 struct direct *dirp;
384 385 struct lbuf *bp;
385 386 char *progname;
386 - short colon, mode;
387 + volatile short colon;
388 + short mode;
387 389 long temp;
388 390
389 391 /* Options/Suboptions processing */
390 392 int opt;
391 393 char *subopts;
392 394 char *optval;
393 395
394 396 /*
395 397 * The following are used to support the old fsdb functionality
396 398 * of clearing an inode. It's better to use 'clri'.
397 399 */
398 400 int inum; /* Inode number to clear */
399 401 char *special;
400 402
401 403 setbuf(stdin, NULL);
402 404 progname = argv[0];
403 405 prompt = &PROMPT[0];
404 406 /*
405 407 * Parse options.
406 408 */
407 409 while ((opt = getopt(argc, argv, FSDB_OPTIONS)) != EOF) {
408 410 switch (opt) {
409 411 #if defined(OLD_FSDB_COMPATIBILITY)
410 412 case 'z': /* Hack - Better to use clri */
411 413 (void) fprintf(stderr, "%s\n%s\n%s\n%s\n",
412 414 "Warning: The '-z' option of 'fsdb_ufs' has been declared obsolete",
413 415 "and may not be supported in a future version of Solaris.",
414 416 "While this functionality is currently still supported, the",
415 417 "recommended procedure to clear an inode is to use clri(1M).");
416 418 if (isnumber(optarg)) {
417 419 inum = atoi(optarg);
418 420 special = argv[optind];
419 421 /* Doesn't return */
420 422 old_fsdb(inum, special);
421 423 } else {
422 424 usage(progname);
423 425 exit(31+1);
424 426 }
425 427 /* Should exit() before here */
426 428 /*NOTREACHED*/
427 429 #endif /* OLD_FSDB_COMPATIBILITY */
428 430 case 'o':
429 431 /* UFS Specific Options */
430 432 subopts = optarg;
431 433 while (*subopts != '\0') {
432 434 switch (getsubopt(&subopts, subopt_v,
433 435 &optval)) {
434 436 case OVERRIDE:
435 437 printf("error checking off\n");
436 438 override = 1;
437 439 break;
438 440
439 441 /*
440 442 * Change the "-o prompt=foo" option to
441 443 * "-o p=foo" to match documentation.
442 444 * ALT_PROMPT continues support for the
443 445 * undocumented "-o prompt=foo" option so
444 446 * that we don't break anyone.
445 447 */
446 448 case NEW_PROMPT:
447 449 case ALT_PROMPT:
448 450 if (optval == NULL) {
449 451 (void) fprintf(stderr,
450 452 "No prompt string\n");
451 453 usage(progname);
452 454 }
453 455 (void) strncpy(PROMPT, optval,
454 456 PROMPTSIZE);
455 457 break;
456 458
457 459 case WRITE_ENABLED:
458 460 /* suitable for open */
459 461 wrtflag = O_RDWR;
460 462 break;
461 463
462 464 default:
463 465 usage(progname);
464 466 /* Should exit here */
465 467 }
466 468 }
467 469 break;
468 470
469 471 default:
470 472 usage(progname);
471 473 }
472 474 }
473 475
474 476 if ((argc - optind) != 1) { /* Should just have "special" left */
475 477 usage(progname);
476 478 }
477 479 special = argv[optind];
478 480
479 481 /*
480 482 * Unless it's already been set, the default prompt includes the
481 483 * name of the special device.
482 484 */
483 485 if (*prompt == NULL)
484 486 (void) sprintf(prompt, "%s > ", special);
485 487
486 488 /*
487 489 * Attempt to open the special file.
488 490 */
489 491 if ((fd = open(special, wrtflag)) < 0) {
490 492 perror(special);
491 493 exit(1);
492 494 }
493 495 /*
494 496 * Read in the super block and validate (not too picky).
495 497 */
496 498 if (llseek(fd, (offset_t)(SBLOCK * DEV_BSIZE), 0) == -1) {
497 499 perror(special);
498 500 exit(1);
499 501 }
500 502
501 503 #ifdef sun
502 504 if (read(fd, &filesystem, SBSIZE) != SBSIZE) {
503 505 printf("%s: cannot read superblock\n", special);
504 506 exit(1);
505 507 }
506 508 #else
507 509 if (read(fd, &filesystem, sizeof (filesystem)) != sizeof (filesystem)) {
508 510 printf("%s: cannot read superblock\n", special);
509 511 exit(1);
510 512 }
511 513 #endif /* sun */
512 514
513 515 fs = &filesystem;
514 516 if ((fs->fs_magic != FS_MAGIC) && (fs->fs_magic != MTB_UFS_MAGIC)) {
515 517 if (!override) {
516 518 printf("%s: Bad magic number in file system\n",
517 519 special);
518 520 exit(1);
519 521 }
520 522
521 523 printf("WARNING: Bad magic number in file system. ");
522 524 printf("Continue? (y/n): ");
523 525 (void) fflush(stdout);
524 526 if (gets(input_buffer) == NULL) {
525 527 exit(1);
526 528 }
527 529
528 530 if (*input_buffer != 'y' && *input_buffer != 'Y') {
529 531 exit(1);
530 532 }
531 533 }
532 534
533 535 if ((fs->fs_magic == FS_MAGIC &&
534 536 (fs->fs_version != UFS_EFISTYLE4NONEFI_VERSION_2 &&
535 537 fs->fs_version != UFS_VERSION_MIN)) ||
536 538 (fs->fs_magic == MTB_UFS_MAGIC &&
537 539 (fs->fs_version > MTB_UFS_VERSION_1 ||
538 540 fs->fs_version < MTB_UFS_VERSION_MIN))) {
539 541 if (!override) {
540 542 printf("%s: Unrecognized UFS version number: %d\n",
541 543 special, fs->fs_version);
542 544 exit(1);
543 545 }
544 546
545 547 printf("WARNING: Unrecognized UFS version number. ");
546 548 printf("Continue? (y/n): ");
547 549 (void) fflush(stdout);
548 550 if (gets(input_buffer) == NULL) {
549 551 exit(1);
550 552 }
551 553
552 554 if (*input_buffer != 'y' && *input_buffer != 'Y') {
553 555 exit(1);
554 556 }
555 557 }
556 558 #ifdef FS_42POSTBLFMT
557 559 if (fs->fs_postblformat == FS_42POSTBLFMT)
558 560 fs->fs_nrpos = 8;
559 561 #endif
560 562 printf("fsdb of %s %s -- last mounted on %s\n",
561 563 special,
562 564 (wrtflag == O_RDWR) ? "(Opened for write)" : "(Read only)",
563 565 &fs->fs_fsmnt[0]);
564 566 #ifdef sun
565 567 printf("fs_clean is currently set to ");
566 568 switch (fs->fs_clean) {
567 569
568 570 case FSACTIVE:
569 571 printf("FSACTIVE\n");
570 572 break;
571 573 case FSCLEAN:
572 574 printf("FSCLEAN\n");
573 575 break;
574 576 case FSSTABLE:
575 577 printf("FSSTABLE\n");
576 578 break;
577 579 case FSBAD:
578 580 printf("FSBAD\n");
579 581 break;
580 582 case FSSUSPEND:
581 583 printf("FSSUSPEND\n");
582 584 break;
583 585 case FSLOG:
584 586 printf("FSLOG\n");
585 587 break;
586 588 case FSFIX:
587 589 printf("FSFIX\n");
588 590 if (!override) {
589 591 printf("%s: fsck may be running on this file system\n",
590 592 special);
591 593 exit(1);
592 594 }
593 595
594 596 printf("WARNING: fsck may be running on this file system. ");
595 597 printf("Continue? (y/n): ");
596 598 (void) fflush(stdout);
597 599 if (gets(input_buffer) == NULL) {
598 600 exit(1);
599 601 }
600 602
601 603 if (*input_buffer != 'y' && *input_buffer != 'Y') {
602 604 exit(1);
603 605 }
604 606 break;
605 607 default:
606 608 printf("an unknown value (0x%x)\n", fs->fs_clean);
607 609 break;
608 610 }
609 611
610 612 if (fs->fs_state == (FSOKAY - fs->fs_time)) {
611 613 printf("fs_state consistent (fs_clean CAN be trusted)\n");
612 614 } else {
613 615 printf("fs_state inconsistent (fs_clean CAN'T trusted)\n");
614 616 }
615 617 #endif /* sun */
616 618 /*
617 619 * Malloc buffers and set up cache.
618 620 */
619 621 buffers = malloc(NBUF * BLKSIZE);
620 622 bhdr.fwd = bhdr.back = &bhdr;
621 623 for (i = 0; i < NBUF; i++) {
622 624 bp = &lbuf[i];
623 625 bp->blkaddr = buffers + (i * BLKSIZE);
624 626 bp->valid = 0;
625 627 insert(bp);
626 628 }
627 629 /*
628 630 * Malloc filenames structure. The space for the actual filenames
629 631 * is allocated as it needs it. We estimate the size based on the
630 632 * number of inodes(objects) in the filesystem and the number of
631 633 * directories. The number of directories are padded by 3 because
632 634 * each directory traversed during a "find" or "ls -R" needs 3
633 635 * entries.
634 636 */
635 637 maxfiles = (long)((((u_offset_t)fs->fs_ncg * (u_offset_t)fs->fs_ipg) -
636 638 (u_offset_t)fs->fs_cstotal.cs_nifree) +
637 639 ((u_offset_t)fs->fs_cstotal.cs_ndir * (u_offset_t)3));
638 640
639 641 filenames = (struct filenames *)calloc(maxfiles,
640 642 sizeof (struct filenames));
641 643 if (filenames == NULL) {
642 644 /*
643 645 * If we could not allocate memory for all of files
644 646 * in the filesystem then, back off to the old fixed
645 647 * value.
646 648 */
647 649 maxfiles = MAXFILES;
648 650 filenames = (struct filenames *)calloc(maxfiles,
649 651 sizeof (struct filenames));
650 652 if (filenames == NULL) {
651 653 printf("out of memory\n");
652 654 exit(1);
653 655 }
654 656 }
655 657
656 658 restore_inode(2);
657 659 /*
658 660 * Malloc a few filenames (needed by pwd for example).
659 661 */
660 662 for (i = 0; i < MAXPATHLEN; i++) {
661 663 input_path[i] = calloc(1, MAXNAMLEN);
662 664 stack_path[i] = calloc(1, MAXNAMLEN);
663 665 current_path[i] = calloc(1, MAXNAMLEN);
664 666 if (current_path[i] == NULL) {
665 667 printf("out of memory\n");
666 668 exit(1);
667 669 }
668 670 }
669 671 current_pathp = -1;
670 672
671 673 (void) signal(2, err);
672 674 (void) setjmp(env);
673 675
674 676 getnextinput();
675 677 /*
676 678 * Main loop and case statement. If an error condition occurs
677 679 * initialization and recovery is attempted.
678 680 */
679 681 for (;;) {
680 682 if (error) {
681 683 freemem(filenames, nfiles);
682 684 nfiles = 0;
683 685 c_count = 0;
684 686 count = 1;
685 687 star = 0;
686 688 error = 0;
687 689 paren = 0;
688 690 acting_on_inode = 0;
689 691 acting_on_directory = 0;
690 692 should_print = 1;
691 693 addr = erraddr;
692 694 cur_ino = errino;
693 695 cur_inum = errinum;
694 696 cur_bytes = errcur_bytes;
695 697 printf("?\n");
696 698 getnextinput();
697 699 if (error)
698 700 continue;
699 701 }
700 702 c_count++;
701 703
702 704 switch (c = getachar()) {
703 705
704 706 case '\n': /* command end */
705 707 freemem(filenames, nfiles);
706 708 nfiles = 0;
707 709 if (should_print && laststyle == '=') {
708 710 ungetachar(c);
709 711 goto calc;
710 712 }
711 713 if (c_count == 1) {
712 714 clear = 0;
713 715 should_print = 1;
714 716 erraddr = addr;
715 717 errino = cur_ino;
716 718 errinum = cur_inum;
717 719 errcur_bytes = cur_bytes;
718 720 switch (objsz) {
719 721 case DIRECTORY:
720 722 if ((addr = getdirslot(
721 723 (long)dirslot+1)) == 0)
722 724 should_print = 0;
723 725 if (error) {
724 726 ungetachar(c);
725 727 continue;
726 728 }
727 729 break;
728 730 case INODE:
729 731 cur_inum++;
730 732 addr = itob(cur_inum);
731 733 if (!icheck(addr)) {
732 734 cur_inum--;
733 735 should_print = 0;
734 736 }
735 737 break;
736 738 case CGRP:
737 739 case SB:
738 740 cur_cgrp++;
739 741 addr = cgrp_check(cur_cgrp);
740 742 if (addr == 0) {
741 743 cur_cgrp--;
742 744 continue;
743 745 }
744 746 break;
745 747 case SHADOW_DATA:
746 748 if ((addr = getshadowslot(
747 749 (long)cur_shad + 1)) == 0)
748 750 should_print = 0;
749 751 if (error) {
750 752 ungetachar(c);
751 753 continue;
752 754 }
753 755 break;
754 756 default:
755 757 addr += objsz;
756 758 cur_bytes += objsz;
757 759 if (valid_addr() == 0)
758 760 continue;
759 761 }
760 762 }
761 763 if (type == NUMB)
762 764 trapped = 0;
763 765 if (should_print)
764 766 switch (objsz) {
765 767 case DIRECTORY:
766 768 fprnt('?', 'd');
767 769 break;
768 770 case INODE:
769 771 fprnt('?', 'i');
770 772 if (!error)
771 773 cur_ino = addr;
772 774 break;
773 775 case CGRP:
774 776 fprnt('?', 'c');
775 777 break;
776 778 case SB:
777 779 fprnt('?', 's');
778 780 break;
779 781 case SHADOW_DATA:
780 782 fprnt('?', 'S');
781 783 break;
782 784 case CHAR:
783 785 case SHORT:
784 786 case LONG:
785 787 fprnt(laststyle, lastpo);
786 788 }
787 789 if (error) {
788 790 ungetachar(c);
789 791 continue;
790 792 }
791 793 c_count = colon = acting_on_inode = 0;
792 794 acting_on_directory = 0;
793 795 should_print = 1;
794 796 getnextinput();
795 797 if (error)
796 798 continue;
797 799 erraddr = addr;
798 800 errino = cur_ino;
799 801 errinum = cur_inum;
800 802 errcur_bytes = cur_bytes;
801 803 continue;
802 804
803 805 case '(': /* numeric expression or unknown command */
804 806 default:
805 807 colon = 0;
806 808 if (digit(c) || c == '(') {
807 809 ungetachar(c);
808 810 addr = expr();
809 811 type = NUMB;
810 812 value = addr;
811 813 continue;
812 814 }
813 815 printf("unknown command or bad syntax\n");
814 816 error++;
815 817 continue;
816 818
817 819 case '?': /* general print facilities */
818 820 case '/':
819 821 fprnt(c, getachar());
820 822 continue;
821 823
822 824 case ';': /* command separator and . */
823 825 case '\t':
824 826 case ' ':
825 827 case '.':
826 828 continue;
827 829
828 830 case ':': /* command indicator */
829 831 colon++;
830 832 commands++;
831 833 should_print = 0;
832 834 stringsize = 0;
833 835 trapped = 0;
834 836 continue;
835 837
836 838 case ',': /* count indicator */
837 839 colon = star = 0;
838 840 if ((c = getachar()) == '*') {
839 841 star = 1;
840 842 count = BLKSIZE;
841 843 } else {
842 844 ungetachar(c);
843 845 count = expr();
844 846 if (error)
845 847 continue;
846 848 if (!count)
847 849 count = 1;
848 850 }
849 851 clear = 0;
850 852 continue;
851 853
852 854 case '+': /* address addition */
853 855 colon = 0;
854 856 c = getachar();
855 857 ungetachar(c);
856 858 if (c == '\n')
857 859 temp = 1;
858 860 else {
859 861 temp = expr();
860 862 if (error)
861 863 continue;
862 864 }
863 865 erraddr = addr;
864 866 errcur_bytes = cur_bytes;
865 867 switch (objsz) {
866 868 case DIRECTORY:
867 869 addr = getdirslot((long)(dirslot + temp));
868 870 if (error)
869 871 continue;
870 872 break;
871 873 case INODE:
872 874 cur_inum += temp;
873 875 addr = itob(cur_inum);
874 876 if (!icheck(addr)) {
875 877 cur_inum -= temp;
876 878 continue;
877 879 }
878 880 break;
879 881 case CGRP:
880 882 case SB:
881 883 cur_cgrp += temp;
882 884 if ((addr = cgrp_check(cur_cgrp)) == 0) {
883 885 cur_cgrp -= temp;
884 886 continue;
885 887 }
886 888 break;
887 889 case SHADOW_DATA:
888 890 addr = getshadowslot((long)(cur_shad + temp));
889 891 if (error)
890 892 continue;
891 893 break;
892 894
893 895 default:
894 896 laststyle = '/';
895 897 addr += temp * objsz;
896 898 cur_bytes += temp * objsz;
897 899 if (valid_addr() == 0)
898 900 continue;
899 901 }
900 902 value = get(objsz);
901 903 continue;
902 904
903 905 case '-': /* address subtraction */
904 906 colon = 0;
905 907 c = getachar();
906 908 ungetachar(c);
907 909 if (c == '\n')
908 910 temp = 1;
909 911 else {
910 912 temp = expr();
911 913 if (error)
912 914 continue;
913 915 }
914 916 erraddr = addr;
915 917 errcur_bytes = cur_bytes;
916 918 switch (objsz) {
917 919 case DIRECTORY:
918 920 addr = getdirslot((long)(dirslot - temp));
919 921 if (error)
920 922 continue;
921 923 break;
922 924 case INODE:
923 925 cur_inum -= temp;
924 926 addr = itob(cur_inum);
925 927 if (!icheck(addr)) {
926 928 cur_inum += temp;
927 929 continue;
928 930 }
929 931 break;
930 932 case CGRP:
931 933 case SB:
932 934 cur_cgrp -= temp;
933 935 if ((addr = cgrp_check(cur_cgrp)) == 0) {
934 936 cur_cgrp += temp;
935 937 continue;
936 938 }
937 939 break;
938 940 case SHADOW_DATA:
939 941 addr = getshadowslot((long)(cur_shad - temp));
940 942 if (error)
941 943 continue;
942 944 break;
943 945 default:
944 946 laststyle = '/';
945 947 addr -= temp * objsz;
946 948 cur_bytes -= temp * objsz;
947 949 if (valid_addr() == 0)
948 950 continue;
949 951 }
950 952 value = get(objsz);
951 953 continue;
952 954
953 955 case '*': /* address multiplication */
954 956 colon = 0;
955 957 temp = expr();
956 958 if (error)
957 959 continue;
958 960 if (objsz != INODE && objsz != DIRECTORY)
959 961 laststyle = '/';
960 962 addr *= temp;
961 963 value = get(objsz);
962 964 continue;
963 965
964 966 case '%': /* address division */
965 967 colon = 0;
966 968 temp = expr();
967 969 if (error)
968 970 continue;
969 971 if (!temp) {
970 972 printf("divide by zero\n");
971 973 error++;
972 974 continue;
973 975 }
974 976 if (objsz != INODE && objsz != DIRECTORY)
975 977 laststyle = '/';
976 978 addr /= temp;
977 979 value = get(objsz);
978 980 continue;
979 981
980 982 case '=': { /* assignment operation */
981 983 short tbase;
982 984 calc:
983 985 tbase = base;
984 986
985 987 c = getachar();
986 988 if (c == '\n') {
987 989 ungetachar(c);
988 990 c = lastpo;
989 991 if (acting_on_inode == 1) {
990 992 if (c != 'o' && c != 'd' && c != 'x' &&
991 993 c != 'O' && c != 'D' && c != 'X') {
992 994 switch (objsz) {
993 995 case LONG:
994 996 c = lastpo = 'X';
995 997 break;
996 998 case SHORT:
997 999 c = lastpo = 'x';
998 1000 break;
999 1001 case CHAR:
1000 1002 c = lastpo = 'c';
1001 1003 }
1002 1004 }
1003 1005 } else {
1004 1006 if (acting_on_inode == 2)
1005 1007 c = lastpo = 't';
1006 1008 }
1007 1009 } else if (acting_on_inode)
1008 1010 lastpo = c;
1009 1011 should_print = star = 0;
1010 1012 count = 1;
1011 1013 erraddr = addr;
1012 1014 errcur_bytes = cur_bytes;
1013 1015 switch (c) {
1014 1016 case '"': /* character string */
1015 1017 if (type == NUMB) {
1016 1018 blocksize = BLKSIZE;
1017 1019 filesize = BLKSIZE * 2;
1018 1020 cur_bytes = blkoff(fs, addr);
1019 1021 if (objsz == DIRECTORY ||
1020 1022 objsz == INODE)
1021 1023 lastpo = 'X';
1022 1024 }
1023 1025 puta();
1024 1026 continue;
1025 1027 case '+': /* =+ operator */
1026 1028 temp = expr();
1027 1029 value = get(objsz);
1028 1030 if (!error)
1029 1031 put(value+temp, objsz);
1030 1032 continue;
1031 1033 case '-': /* =- operator */
1032 1034 temp = expr();
1033 1035 value = get(objsz);
1034 1036 if (!error)
1035 1037 put(value-temp, objsz);
1036 1038 continue;
1037 1039 case 'b':
1038 1040 case 'c':
1039 1041 if (objsz == CGRP)
1040 1042 fprnt('?', c);
1041 1043 else
1042 1044 fprnt('/', c);
1043 1045 continue;
1044 1046 case 'i':
1045 1047 addr = cur_ino;
1046 1048 fprnt('?', 'i');
1047 1049 continue;
1048 1050 case 's':
1049 1051 fprnt('?', 's');
1050 1052 continue;
1051 1053 case 't':
1052 1054 case 'T':
1053 1055 laststyle = '=';
1054 1056 printf("\t\t");
1055 1057 {
1056 1058 /*
1057 1059 * Truncation is intentional so
1058 1060 * ctime is happy.
1059 1061 */
1060 1062 time_t tvalue = (time_t)value;
1061 1063 printf("%s", ctime(&tvalue));
1062 1064 }
1063 1065 continue;
1064 1066 case 'o':
1065 1067 base = OCTAL;
1066 1068 goto otx;
1067 1069 case 'd':
1068 1070 if (objsz == DIRECTORY) {
1069 1071 addr = cur_dir;
1070 1072 fprnt('?', 'd');
1071 1073 continue;
1072 1074 }
1073 1075 base = DECIMAL;
1074 1076 goto otx;
1075 1077 case 'x':
1076 1078 base = HEX;
1077 1079 otx:
1078 1080 laststyle = '=';
1079 1081 printf("\t\t");
1080 1082 if (acting_on_inode)
1081 1083 print(value & 0177777L, 12, -8, 0);
1082 1084 else
1083 1085 print(addr & 0177777L, 12, -8, 0);
1084 1086 printf("\n");
1085 1087 base = tbase;
1086 1088 continue;
1087 1089 case 'O':
1088 1090 base = OCTAL;
1089 1091 goto OTX;
1090 1092 case 'D':
1091 1093 base = DECIMAL;
1092 1094 goto OTX;
1093 1095 case 'X':
1094 1096 base = HEX;
1095 1097 OTX:
1096 1098 laststyle = '=';
1097 1099 printf("\t\t");
1098 1100 if (acting_on_inode)
1099 1101 print(value, 12, -8, 0);
1100 1102 else
1101 1103 print(addr, 12, -8, 0);
1102 1104 printf("\n");
1103 1105 base = tbase;
1104 1106 continue;
1105 1107 default: /* regular assignment */
1106 1108 ungetachar(c);
1107 1109 value = expr();
1108 1110 if (error)
1109 1111 printf("syntax error\n");
1110 1112 else
1111 1113 put(value, objsz);
1112 1114 continue;
1113 1115 }
1114 1116 }
1115 1117
1116 1118 case '>': /* save current address */
1117 1119 colon = 0;
1118 1120 should_print = 0;
1119 1121 c = getachar();
1120 1122 if (!letter(c) && !digit(c)) {
1121 1123 printf("invalid register specification, ");
1122 1124 printf("must be letter or digit\n");
1123 1125 error++;
1124 1126 continue;
1125 1127 }
1126 1128 if (letter(c)) {
1127 1129 if (c < 'a')
1128 1130 c = uppertolower(c);
1129 1131 c = hextodigit(c);
1130 1132 } else
1131 1133 c = numtodigit(c);
1132 1134 regs[c].sv_addr = addr;
1133 1135 regs[c].sv_value = value;
1134 1136 regs[c].sv_objsz = objsz;
1135 1137 continue;
1136 1138
1137 1139 case '<': /* restore saved address */
1138 1140 colon = 0;
1139 1141 should_print = 0;
1140 1142 c = getachar();
1141 1143 if (!letter(c) && !digit(c)) {
1142 1144 printf("invalid register specification, ");
1143 1145 printf("must be letter or digit\n");
1144 1146 error++;
1145 1147 continue;
1146 1148 }
1147 1149 if (letter(c)) {
1148 1150 if (c < 'a')
1149 1151 c = uppertolower(c);
1150 1152 c = hextodigit(c);
1151 1153 } else
1152 1154 c = numtodigit(c);
1153 1155 addr = regs[c].sv_addr;
1154 1156 value = regs[c].sv_value;
1155 1157 objsz = regs[c].sv_objsz;
1156 1158 continue;
1157 1159
1158 1160 case 'a':
1159 1161 if (colon)
1160 1162 colon = 0;
1161 1163 else
1162 1164 goto no_colon;
1163 1165 if (match("at", 2)) { /* access time */
1164 1166 acting_on_inode = 2;
1165 1167 should_print = 1;
1166 1168 addr = (long)&((struct dinode *)
1167 1169 (uintptr_t)cur_ino)->di_atime;
1168 1170 value = get(LONG);
1169 1171 type = NULL;
1170 1172 continue;
1171 1173 }
1172 1174 goto bad_syntax;
1173 1175
1174 1176 case 'b':
1175 1177 if (colon)
1176 1178 colon = 0;
1177 1179 else
1178 1180 goto no_colon;
1179 1181 if (match("block", 2)) { /* block conversion */
1180 1182 if (type == NUMB) {
1181 1183 value = addr;
1182 1184 cur_bytes = 0;
1183 1185 blocksize = BLKSIZE;
1184 1186 filesize = BLKSIZE * 2;
1185 1187 }
1186 1188 addr = value << FRGSHIFT;
1187 1189 bod_addr = addr;
1188 1190 value = get(LONG);
1189 1191 type = BLOCK;
1190 1192 dirslot = 0;
1191 1193 trapped++;
1192 1194 continue;
1193 1195 }
1194 1196 if (match("bs", 2)) { /* block size */
1195 1197 acting_on_inode = 1;
1196 1198 should_print = 1;
1197 1199 if (icheck(cur_ino) == 0)
1198 1200 continue;
1199 1201 addr = (long)&((struct dinode *)
1200 1202 (uintptr_t)cur_ino)->di_blocks;
1201 1203 value = get(LONG);
1202 1204 type = NULL;
1203 1205 continue;
1204 1206 }
1205 1207 if (match("base", 2)) { /* change/show base */
1206 1208 showbase:
1207 1209 if ((c = getachar()) == '\n') {
1208 1210 ungetachar(c);
1209 1211 printf("base =\t\t");
1210 1212 switch (base) {
1211 1213 case OCTAL:
1212 1214 printf("OCTAL\n");
1213 1215 continue;
1214 1216 case DECIMAL:
1215 1217 printf("DECIMAL\n");
1216 1218 continue;
1217 1219 case HEX:
1218 1220 printf("HEX\n");
1219 1221 continue;
1220 1222 }
1221 1223 }
1222 1224 if (c != '=') {
1223 1225 printf("missing '='\n");
1224 1226 error++;
1225 1227 continue;
1226 1228 }
1227 1229 value = expr();
1228 1230 switch (value) {
1229 1231 default:
1230 1232 printf("invalid base\n");
1231 1233 error++;
1232 1234 break;
1233 1235 case OCTAL:
1234 1236 case DECIMAL:
1235 1237 case HEX:
1236 1238 base = (short)value;
1237 1239 }
1238 1240 goto showbase;
1239 1241 }
1240 1242 goto bad_syntax;
1241 1243
1242 1244 case 'c':
1243 1245 if (colon)
1244 1246 colon = 0;
1245 1247 else
1246 1248 goto no_colon;
1247 1249 if (match("cd", 2)) { /* change directory */
1248 1250 top = filenames - 1;
1249 1251 eat_spaces();
1250 1252 if ((c = getachar()) == '\n') {
1251 1253 ungetachar(c);
1252 1254 current_pathp = -1;
1253 1255 restore_inode(2);
1254 1256 continue;
1255 1257 }
1256 1258 ungetachar(c);
1257 1259 temp = cur_inum;
1258 1260 doing_cd = 1;
1259 1261 parse();
1260 1262 doing_cd = 0;
1261 1263 if (nfiles != 1) {
1262 1264 restore_inode((ino_t)temp);
1263 1265 if (!error) {
1264 1266 print_path(input_path,
1265 1267 (int)input_pathp);
1266 1268 if (nfiles == 0)
1267 1269 printf(" not found\n");
1268 1270 else
1269 1271 printf(" ambiguous\n");
1270 1272 error++;
1271 1273 }
1272 1274 continue;
1273 1275 }
1274 1276 restore_inode(filenames->ino);
1275 1277 if ((mode = icheck(addr)) == 0)
1276 1278 continue;
1277 1279 if ((mode & IFMT) != IFDIR) {
1278 1280 restore_inode((ino_t)temp);
1279 1281 print_path(input_path,
1280 1282 (int)input_pathp);
1281 1283 printf(" not a directory\n");
1282 1284 error++;
1283 1285 continue;
1284 1286 }
1285 1287 for (i = 0; i <= top->len; i++)
1286 1288 (void) strcpy(current_path[i],
1287 1289 top->fname[i]);
1288 1290 current_pathp = top->len;
1289 1291 continue;
1290 1292 }
1291 1293 if (match("cg", 2)) { /* cylinder group */
1292 1294 if (type == NUMB)
1293 1295 value = addr;
1294 1296 if (value > fs->fs_ncg - 1) {
1295 1297 printf("maximum cylinder group is ");
1296 1298 print(fs->fs_ncg - 1, 8, -8, 0);
1297 1299 printf("\n");
1298 1300 error++;
1299 1301 continue;
1300 1302 }
1301 1303 type = objsz = CGRP;
1302 1304 cur_cgrp = (long)value;
1303 1305 addr = cgtod(fs, cur_cgrp) << FRGSHIFT;
1304 1306 continue;
1305 1307 }
1306 1308 if (match("ct", 2)) { /* creation time */
1307 1309 acting_on_inode = 2;
1308 1310 should_print = 1;
1309 1311 addr = (long)&((struct dinode *)
1310 1312 (uintptr_t)cur_ino)->di_ctime;
1311 1313 value = get(LONG);
1312 1314 type = NULL;
1313 1315 continue;
1314 1316 }
1315 1317 goto bad_syntax;
1316 1318
1317 1319 case 'd':
1318 1320 if (colon)
1319 1321 colon = 0;
1320 1322 else
1321 1323 goto no_colon;
1322 1324 if (match("directory", 2)) { /* directory offsets */
1323 1325 if (type == NUMB)
1324 1326 value = addr;
1325 1327 objsz = DIRECTORY;
1326 1328 type = DIRECTORY;
1327 1329 addr = (u_offset_t)getdirslot((long)value);
1328 1330 continue;
1329 1331 }
1330 1332 if (match("db", 2)) { /* direct block */
1331 1333 acting_on_inode = 1;
1332 1334 should_print = 1;
1333 1335 if (type == NUMB)
1334 1336 value = addr;
1335 1337 if (value >= NDADDR) {
1336 1338 printf("direct blocks are 0 to ");
1337 1339 print(NDADDR - 1, 0, 0, 0);
1338 1340 printf("\n");
1339 1341 error++;
1340 1342 continue;
1341 1343 }
1342 1344 addr = cur_ino;
1343 1345 if (!icheck(addr))
1344 1346 continue;
1345 1347 addr = (long)
1346 1348 &((struct dinode *)(uintptr_t)cur_ino)->
1347 1349 di_db[value];
1348 1350 bod_addr = addr;
1349 1351 cur_bytes = (value) * BLKSIZE;
1350 1352 cur_block = (long)value;
1351 1353 type = BLOCK;
1352 1354 dirslot = 0;
1353 1355 value = get(LONG);
1354 1356 if (!value && !override) {
1355 1357 printf("non existent block\n");
1356 1358 error++;
1357 1359 }
1358 1360 continue;
1359 1361 }
1360 1362 goto bad_syntax;
1361 1363
1362 1364 case 'f':
1363 1365 if (colon)
1364 1366 colon = 0;
1365 1367 else
1366 1368 goto no_colon;
1367 1369 if (match("find", 3)) { /* find command */
1368 1370 find();
1369 1371 continue;
1370 1372 }
1371 1373 if (match("fragment", 2)) { /* fragment conv. */
1372 1374 if (type == NUMB) {
1373 1375 value = addr;
1374 1376 cur_bytes = 0;
1375 1377 blocksize = FRGSIZE;
1376 1378 filesize = FRGSIZE * 2;
1377 1379 }
1378 1380 if (min(blocksize, filesize) - cur_bytes >
1379 1381 FRGSIZE) {
1380 1382 blocksize = cur_bytes + FRGSIZE;
1381 1383 filesize = blocksize * 2;
1382 1384 }
1383 1385 addr = value << FRGSHIFT;
1384 1386 bod_addr = addr;
1385 1387 value = get(LONG);
1386 1388 type = FRAGMENT;
1387 1389 dirslot = 0;
1388 1390 trapped++;
1389 1391 continue;
1390 1392 }
1391 1393 if (match("file", 4)) { /* access as file */
1392 1394 acting_on_inode = 1;
1393 1395 should_print = 1;
1394 1396 if (type == NUMB)
1395 1397 value = addr;
1396 1398 addr = cur_ino;
1397 1399 if ((mode = icheck(addr)) == 0)
1398 1400 continue;
1399 1401 if (!override) {
1400 1402 switch (mode & IFMT) {
1401 1403 case IFCHR:
1402 1404 case IFBLK:
1403 1405 printf("special device\n");
1404 1406 error++;
1405 1407 continue;
1406 1408 }
1407 1409 }
1408 1410 if ((addr = (u_offset_t)
1409 1411 (bmap((long)value) << FRGSHIFT)) == 0)
1410 1412 continue;
1411 1413 cur_block = (long)value;
1412 1414 bod_addr = addr;
1413 1415 type = BLOCK;
1414 1416 dirslot = 0;
1415 1417 continue;
1416 1418 }
1417 1419 if (match("fill", 4)) { /* fill */
1418 1420 if (getachar() != '=') {
1419 1421 printf("missing '='\n");
1420 1422 error++;
1421 1423 continue;
1422 1424 }
1423 1425 if (objsz == INODE || objsz == DIRECTORY ||
1424 1426 objsz == SHADOW_DATA) {
1425 1427 printf(
1426 1428 "can't fill inode or directory\n");
1427 1429 error++;
1428 1430 continue;
1429 1431 }
1430 1432 fill();
1431 1433 continue;
1432 1434 }
1433 1435 goto bad_syntax;
1434 1436
1435 1437 case 'g':
1436 1438 if (colon)
1437 1439 colon = 0;
1438 1440 else
1439 1441 goto no_colon;
1440 1442 if (match("gid", 1)) { /* group id */
1441 1443 acting_on_inode = 1;
1442 1444 should_print = 1;
1443 1445 addr = (long)&((struct dinode *)
1444 1446 (uintptr_t)cur_ino)->di_gid;
1445 1447 value = get(SHORT);
1446 1448 type = NULL;
1447 1449 continue;
1448 1450 }
1449 1451 goto bad_syntax;
1450 1452
1451 1453 case 'i':
1452 1454 if (colon)
1453 1455 colon = 0;
1454 1456 else
1455 1457 goto no_colon;
1456 1458 if (match("inode", 2)) { /* i# to inode conversion */
1457 1459 if (c_count == 2) {
1458 1460 addr = cur_ino;
1459 1461 value = get(INODE);
1460 1462 type = NULL;
1461 1463 laststyle = '=';
1462 1464 lastpo = 'i';
1463 1465 should_print = 1;
1464 1466 continue;
1465 1467 }
1466 1468 if (type == NUMB)
1467 1469 value = addr;
1468 1470 addr = itob(value);
1469 1471 if (!icheck(addr))
1470 1472 continue;
1471 1473 cur_ino = addr;
1472 1474 cur_inum = (long)value;
1473 1475 value = get(INODE);
1474 1476 type = NULL;
1475 1477 continue;
1476 1478 }
1477 1479 if (match("ib", 2)) { /* indirect block */
1478 1480 acting_on_inode = 1;
1479 1481 should_print = 1;
1480 1482 if (type == NUMB)
1481 1483 value = addr;
1482 1484 if (value >= NIADDR) {
1483 1485 printf("indirect blocks are 0 to ");
1484 1486 print(NIADDR - 1, 0, 0, 0);
1485 1487 printf("\n");
1486 1488 error++;
1487 1489 continue;
1488 1490 }
1489 1491 addr = (long)&((struct dinode *)(uintptr_t)
1490 1492 cur_ino)->di_ib[value];
1491 1493 cur_bytes = (NDADDR - 1) * BLKSIZE;
1492 1494 temp = 1;
1493 1495 for (i = 0; i < value; i++) {
1494 1496 temp *= NINDIR(fs) * BLKSIZE;
1495 1497 cur_bytes += temp;
1496 1498 }
1497 1499 type = BLOCK;
1498 1500 dirslot = 0;
1499 1501 value = get(LONG);
1500 1502 if (!value && !override) {
1501 1503 printf("non existent block\n");
1502 1504 error++;
1503 1505 }
1504 1506 continue;
1505 1507 }
1506 1508 goto bad_syntax;
1507 1509
1508 1510 case 'l':
1509 1511 if (colon)
1510 1512 colon = 0;
1511 1513 else
1512 1514 goto no_colon;
1513 1515 if (match("log_head", 8)) {
1514 1516 log_display_header();
1515 1517 should_print = 0;
1516 1518 continue;
1517 1519 }
1518 1520 if (match("log_delta", 9)) {
1519 1521 log_show(LOG_NDELTAS);
1520 1522 should_print = 0;
1521 1523 continue;
1522 1524 }
1523 1525 if (match("log_show", 8)) {
1524 1526 log_show(LOG_ALLDELTAS);
1525 1527 should_print = 0;
1526 1528 continue;
1527 1529 }
1528 1530 if (match("log_chk", 7)) {
1529 1531 log_show(LOG_CHECKSCAN);
1530 1532 should_print = 0;
1531 1533 continue;
1532 1534 }
1533 1535 if (match("log_otodb", 9)) {
1534 1536 if (log_lodb((u_offset_t)addr, &temp)) {
1535 1537 addr = temp;
1536 1538 should_print = 1;
1537 1539 laststyle = '=';
1538 1540 } else
1539 1541 error++;
1540 1542 continue;
1541 1543 }
1542 1544 if (match("ls", 2)) { /* ls command */
1543 1545 temp = cur_inum;
1544 1546 recursive = long_list = 0;
1545 1547 top = filenames - 1;
1546 1548 for (;;) {
1547 1549 eat_spaces();
1548 1550 if ((c = getachar()) == '-') {
1549 1551 if ((c = getachar()) == 'R') {
1550 1552 recursive = 1;
1551 1553 continue;
1552 1554 } else if (c == 'l') {
1553 1555 long_list = 1;
1554 1556 } else {
1555 1557 printf(
1556 1558 "unknown option ");
1557 1559 printf("'%c'\n", c);
1558 1560 error++;
1559 1561 break;
1560 1562 }
1561 1563 } else
1562 1564 ungetachar(c);
1563 1565 if ((c = getachar()) == '\n') {
1564 1566 if (c_count != 2) {
1565 1567 ungetachar(c);
1566 1568 break;
1567 1569 }
1568 1570 }
1569 1571 c_count++;
1570 1572 ungetachar(c);
1571 1573 parse();
1572 1574 restore_inode((ino_t)temp);
1573 1575 if (error)
1574 1576 break;
1575 1577 }
1576 1578 recursive = 0;
1577 1579 if (error || nfiles == 0) {
1578 1580 if (!error) {
1579 1581 print_path(input_path,
1580 1582 (int)input_pathp);
1581 1583 printf(" not found\n");
1582 1584 }
1583 1585 continue;
1584 1586 }
1585 1587 if (nfiles) {
1586 1588 cmp_level = 0;
1587 1589 qsort((char *)filenames, nfiles,
1588 1590 sizeof (struct filenames), ffcmp);
1589 1591 ls(filenames, filenames + (nfiles - 1), 0);
1590 1592 } else {
1591 1593 printf("no match\n");
1592 1594 error++;
1593 1595 }
1594 1596 restore_inode((ino_t)temp);
1595 1597 continue;
1596 1598 }
1597 1599 if (match("ln", 2)) { /* link count */
1598 1600 acting_on_inode = 1;
1599 1601 should_print = 1;
1600 1602 addr = (long)&((struct dinode *)
1601 1603 (uintptr_t)cur_ino)->di_nlink;
1602 1604 value = get(SHORT);
1603 1605 type = NULL;
1604 1606 continue;
1605 1607 }
1606 1608 goto bad_syntax;
1607 1609
1608 1610 case 'm':
1609 1611 if (colon)
1610 1612 colon = 0;
1611 1613 else
1612 1614 goto no_colon;
1613 1615 addr = cur_ino;
1614 1616 if ((mode = icheck(addr)) == 0)
1615 1617 continue;
1616 1618 if (match("mt", 2)) { /* modification time */
1617 1619 acting_on_inode = 2;
1618 1620 should_print = 1;
1619 1621 addr = (long)&((struct dinode *)
1620 1622 (uintptr_t)cur_ino)->di_mtime;
1621 1623 value = get(LONG);
1622 1624 type = NULL;
1623 1625 continue;
1624 1626 }
1625 1627 if (match("md", 2)) { /* mode */
1626 1628 acting_on_inode = 1;
1627 1629 should_print = 1;
1628 1630 addr = (long)&((struct dinode *)
1629 1631 (uintptr_t)cur_ino)->di_mode;
1630 1632 value = get(SHORT);
1631 1633 type = NULL;
1632 1634 continue;
1633 1635 }
1634 1636 if (match("maj", 2)) { /* major device number */
1635 1637 acting_on_inode = 1;
1636 1638 should_print = 1;
1637 1639 if (devcheck(mode))
1638 1640 continue;
1639 1641 addr = (uintptr_t)&((struct dinode *)(uintptr_t)
1640 1642 cur_ino)->di_ordev;
1641 1643 {
1642 1644 long dvalue;
1643 1645 dvalue = get(LONG);
1644 1646 value = major(dvalue);
1645 1647 }
1646 1648 type = NULL;
1647 1649 continue;
1648 1650 }
1649 1651 if (match("min", 2)) { /* minor device number */
1650 1652 acting_on_inode = 1;
1651 1653 should_print = 1;
1652 1654 if (devcheck(mode))
1653 1655 continue;
1654 1656 addr = (uintptr_t)&((struct dinode *)(uintptr_t)
1655 1657 cur_ino)->di_ordev;
1656 1658 {
1657 1659 long dvalue;
1658 1660 dvalue = (long)get(LONG);
1659 1661 value = minor(dvalue);
1660 1662 }
1661 1663 type = NULL;
1662 1664 continue;
1663 1665 }
1664 1666 goto bad_syntax;
1665 1667
1666 1668 case 'n':
1667 1669 if (colon)
1668 1670 colon = 0;
1669 1671 else
1670 1672 goto no_colon;
1671 1673 if (match("nm", 1)) { /* directory name */
1672 1674 objsz = DIRECTORY;
1673 1675 acting_on_directory = 1;
1674 1676 cur_dir = addr;
1675 1677 if ((cptr = getblk(addr)) == 0)
1676 1678 continue;
1677 1679 /*LINTED*/
1678 1680 dirp = (struct direct *)(cptr+blkoff(fs, addr));
1679 1681 stringsize = (long)dirp->d_reclen -
1680 1682 ((long)&dirp->d_name[0] -
1681 1683 (long)&dirp->d_ino);
1682 1684 addr = (long)&((struct direct *)
1683 1685 (uintptr_t)addr)->d_name[0];
1684 1686 type = NULL;
1685 1687 continue;
1686 1688 }
1687 1689 goto bad_syntax;
1688 1690
1689 1691 case 'o':
1690 1692 if (colon)
1691 1693 colon = 0;
1692 1694 else
1693 1695 goto no_colon;
1694 1696 if (match("override", 1)) { /* override flip flop */
1695 1697 override = !override;
1696 1698 if (override)
1697 1699 printf("error checking off\n");
1698 1700 else
1699 1701 printf("error checking on\n");
1700 1702 continue;
1701 1703 }
1702 1704 goto bad_syntax;
1703 1705
1704 1706 case 'p':
1705 1707 if (colon)
1706 1708 colon = 0;
1707 1709 else
1708 1710 goto no_colon;
1709 1711 if (match("pwd", 2)) { /* print working dir */
1710 1712 print_path(current_path, (int)current_pathp);
1711 1713 printf("\n");
1712 1714 continue;
1713 1715 }
1714 1716 if (match("prompt", 2)) { /* change prompt */
1715 1717 if ((c = getachar()) != '=') {
1716 1718 printf("missing '='\n");
1717 1719 error++;
1718 1720 continue;
1719 1721 }
1720 1722 if ((c = getachar()) != '"') {
1721 1723 printf("missing '\"'\n");
1722 1724 error++;
1723 1725 continue;
1724 1726 }
1725 1727 i = 0;
1726 1728 prompt = &prompt[0];
1727 1729 while ((c = getachar()) != '"' && c != '\n') {
1728 1730 prompt[i++] = c;
1729 1731 if (i >= PROMPTSIZE) {
1730 1732 printf("string too long\n");
1731 1733 error++;
1732 1734 break;
1733 1735 }
1734 1736 }
1735 1737 prompt[i] = '\0';
1736 1738 continue;
1737 1739 }
1738 1740 goto bad_syntax;
1739 1741
1740 1742 case 'q':
1741 1743 if (!colon)
1742 1744 goto no_colon;
1743 1745 if (match("quit", 1)) { /* quit */
1744 1746 if ((c = getachar()) != '\n') {
1745 1747 error++;
1746 1748 continue;
1747 1749 }
1748 1750 exit(0);
1749 1751 }
1750 1752 goto bad_syntax;
1751 1753
1752 1754 case 's':
1753 1755 if (colon)
1754 1756 colon = 0;
1755 1757 else
1756 1758 goto no_colon;
1757 1759 if (match("sb", 2)) { /* super block */
1758 1760 if (c_count == 2) {
1759 1761 cur_cgrp = -1;
1760 1762 type = objsz = SB;
1761 1763 laststyle = '=';
1762 1764 lastpo = 's';
1763 1765 should_print = 1;
1764 1766 continue;
1765 1767 }
1766 1768 if (type == NUMB)
1767 1769 value = addr;
1768 1770 if (value > fs->fs_ncg - 1) {
1769 1771 printf("maximum super block is ");
1770 1772 print(fs->fs_ncg - 1, 8, -8, 0);
1771 1773 printf("\n");
1772 1774 error++;
1773 1775 continue;
1774 1776 }
1775 1777 type = objsz = SB;
1776 1778 cur_cgrp = (long)value;
1777 1779 addr = cgsblock(fs, cur_cgrp) << FRGSHIFT;
1778 1780 continue;
1779 1781 }
1780 1782 if (match("shadow", 2)) { /* shadow inode data */
1781 1783 if (type == NUMB)
1782 1784 value = addr;
1783 1785 objsz = SHADOW_DATA;
1784 1786 type = SHADOW_DATA;
1785 1787 addr = getshadowslot(value);
1786 1788 continue;
1787 1789 }
1788 1790 if (match("si", 2)) { /* shadow inode field */
1789 1791 acting_on_inode = 1;
1790 1792 should_print = 1;
1791 1793 addr = (long)&((struct dinode *)
1792 1794 (uintptr_t)cur_ino)->di_shadow;
1793 1795 value = get(LONG);
1794 1796 type = NULL;
1795 1797 continue;
1796 1798 }
1797 1799
1798 1800 if (match("sz", 2)) { /* file size */
1799 1801 acting_on_inode = 1;
1800 1802 should_print = 1;
1801 1803 addr = (long)&((struct dinode *)
1802 1804 (uintptr_t)cur_ino)->di_size;
1803 1805 value = get(U_OFFSET_T);
1804 1806 type = NULL;
1805 1807 objsz = U_OFFSET_T;
1806 1808 laststyle = '=';
1807 1809 lastpo = 'X';
1808 1810 continue;
1809 1811 }
1810 1812 goto bad_syntax;
1811 1813
1812 1814 case 'u':
1813 1815 if (colon)
1814 1816 colon = 0;
1815 1817 else
1816 1818 goto no_colon;
1817 1819 if (match("uid", 1)) { /* user id */
1818 1820 acting_on_inode = 1;
1819 1821 should_print = 1;
1820 1822 addr = (long)&((struct dinode *)
1821 1823 (uintptr_t)cur_ino)->di_uid;
1822 1824 value = get(SHORT);
1823 1825 type = NULL;
1824 1826 continue;
1825 1827 }
1826 1828 goto bad_syntax;
1827 1829
1828 1830 case 'F': /* buffer status (internal use only) */
1829 1831 if (colon)
1830 1832 colon = 0;
1831 1833 else
1832 1834 goto no_colon;
1833 1835 for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
1834 1836 printf("%8" PRIx64 " %d\n",
1835 1837 bp->blkno, bp->valid);
1836 1838 printf("\n");
1837 1839 printf("# commands\t\t%ld\n", commands);
1838 1840 printf("# read requests\t\t%ld\n", read_requests);
1839 1841 printf("# actual disk reads\t%ld\n", actual_disk_reads);
1840 1842 continue;
1841 1843 no_colon:
1842 1844 printf("a colon should precede a command\n");
1843 1845 error++;
1844 1846 continue;
1845 1847 bad_syntax:
1846 1848 printf("more letters needed to distinguish command\n");
1847 1849 error++;
1848 1850 continue;
1849 1851 }
1850 1852 }
1851 1853 }
1852 1854
1853 1855 /*
1854 1856 * usage - print usage and exit
1855 1857 */
1856 1858 static void
1857 1859 usage(char *progname)
1858 1860 {
1859 1861 printf("usage: %s [options] special\n", progname);
1860 1862 printf("options:\n");
1861 1863 printf("\t-o Specify ufs filesystem sepcific options\n");
1862 1864 printf(" Available suboptions are:\n");
1863 1865 printf("\t\t? display usage\n");
1864 1866 printf("\t\to override some error conditions\n");
1865 1867 printf("\t\tp=\"string\" set prompt to string\n");
1866 1868 printf("\t\tw open for write\n");
1867 1869 exit(1);
1868 1870 }
1869 1871
1870 1872 /*
1871 1873 * getachar - get next character from input buffer.
1872 1874 */
1873 1875 static char
1874 1876 getachar()
1875 1877 {
1876 1878 return (input_buffer[input_pointer++]);
1877 1879 }
1878 1880
1879 1881 /*
1880 1882 * ungetachar - return character to input buffer.
1881 1883 */
1882 1884 static void
1883 1885 ungetachar(char c)
1884 1886 {
1885 1887 if (input_pointer == 0) {
1886 1888 printf("internal problem maintaining input buffer\n");
1887 1889 error++;
1888 1890 return;
1889 1891 }
1890 1892 input_buffer[--input_pointer] = c;
1891 1893 }
1892 1894
1893 1895 /*
1894 1896 * getnextinput - display the prompt and read an input line.
1895 1897 * An input line is up to 128 characters terminated by the newline
1896 1898 * character. Handle overflow, shell escape, and eof.
1897 1899 */
1898 1900 static void
1899 1901 getnextinput()
1900 1902 {
1901 1903 int i;
1902 1904 char c;
1903 1905 short pid, rpid;
1904 1906 int retcode;
1905 1907
1906 1908 newline:
1907 1909 i = 0;
1908 1910 printf("%s", prompt);
1909 1911 ignore_eol:
1910 1912 while ((c = getc(stdin)) != '\n' && !(c == '!' && i == 0) &&
1911 1913 !feof(stdin) && i <= INPUTBUFFER - 2)
1912 1914 input_buffer[i++] = c;
1913 1915 if (i > 0 && input_buffer[i - 1] == '\\') {
1914 1916 input_buffer[i++] = c;
1915 1917 goto ignore_eol;
1916 1918 }
1917 1919 if (feof(stdin)) {
1918 1920 printf("\n");
1919 1921 exit(0);
1920 1922 }
1921 1923 if (c == '!') {
1922 1924 if ((pid = fork()) == 0) {
1923 1925 (void) execl(_PATH_BSHELL, "sh", "-t", 0);
1924 1926 error++;
1925 1927 return;
1926 1928 }
1927 1929 while ((rpid = wait(&retcode)) != pid && rpid != -1)
1928 1930 ;
1929 1931 printf("!\n");
1930 1932 goto newline;
1931 1933 }
1932 1934 if (c != '\n')
1933 1935 printf("input truncated to 128 characters\n");
1934 1936 input_buffer[i] = '\n';
1935 1937 input_pointer = 0;
1936 1938 }
1937 1939
1938 1940 /*
1939 1941 * eat_spaces - read extraneous spaces.
1940 1942 */
1941 1943 static void
1942 1944 eat_spaces()
1943 1945 {
1944 1946 char c;
1945 1947
1946 1948 while ((c = getachar()) == ' ')
1947 1949 ;
1948 1950 ungetachar(c);
1949 1951 }
1950 1952
1951 1953 /*
1952 1954 * restore_inode - set up all inode indicators so inum is now
1953 1955 * the current inode.
1954 1956 */
1955 1957 static void
1956 1958 restore_inode(ino_t inum)
1957 1959 {
1958 1960 errinum = cur_inum = inum;
1959 1961 addr = errino = cur_ino = itob(inum);
1960 1962 }
1961 1963
1962 1964 /*
1963 1965 * match - return false if the input does not match string up to
1964 1966 * upto letters. Then proceed to chew up extraneous letters.
1965 1967 */
1966 1968 static int
1967 1969 match(char *string, int upto)
1968 1970 {
1969 1971 int i, length = strlen(string) - 1;
1970 1972 char c;
1971 1973 int save_upto = upto;
1972 1974
1973 1975 while (--upto) {
1974 1976 string++;
1975 1977 if ((c = getachar()) != *string) {
1976 1978 for (i = save_upto - upto; i; i--) {
1977 1979 ungetachar(c);
1978 1980 c = *--string;
1979 1981 }
1980 1982 return (0);
1981 1983 }
1982 1984 length--;
1983 1985 }
1984 1986 while (length--) {
1985 1987 string++;
1986 1988 if ((c = getachar()) != *string) {
1987 1989 ungetachar(c);
1988 1990 return (1);
1989 1991 }
1990 1992 }
1991 1993 return (1);
1992 1994 }
1993 1995
1994 1996 /*
1995 1997 * expr - expression evaluator. Will evaluate expressions from
1996 1998 * left to right with no operator precedence. Parentheses may
1997 1999 * be used.
1998 2000 */
1999 2001 static long
2000 2002 expr()
2001 2003 {
2002 2004 long numb = 0, temp;
2003 2005 char c;
2004 2006
2005 2007 numb = term();
2006 2008 for (;;) {
2007 2009 if (error)
2008 2010 return (~0); /* error is set so value is ignored */
2009 2011 c = getachar();
2010 2012 switch (c) {
2011 2013
2012 2014 case '+':
2013 2015 numb += term();
2014 2016 continue;
2015 2017
2016 2018 case '-':
2017 2019 numb -= term();
2018 2020 continue;
2019 2021
2020 2022 case '*':
2021 2023 numb *= term();
2022 2024 continue;
2023 2025
2024 2026 case '%':
2025 2027 temp = term();
2026 2028 if (!temp) {
2027 2029 printf("divide by zero\n");
2028 2030 error++;
2029 2031 return (~0);
2030 2032 }
2031 2033 numb /= temp;
2032 2034 continue;
2033 2035
2034 2036 case ')':
2035 2037 paren--;
2036 2038 return (numb);
2037 2039
2038 2040 default:
2039 2041 ungetachar(c);
2040 2042 if (paren && !error) {
2041 2043 printf("missing ')'\n");
2042 2044 error++;
2043 2045 }
2044 2046 return (numb);
2045 2047 }
2046 2048 }
2047 2049 }
2048 2050
2049 2051 /*
2050 2052 * term - used by expression evaluator to get an operand.
2051 2053 */
2052 2054 static long
2053 2055 term()
2054 2056 {
2055 2057 char c;
2056 2058
2057 2059 switch (c = getachar()) {
2058 2060
2059 2061 default:
2060 2062 ungetachar(c);
2061 2063 /*FALLTHRU*/
2062 2064 case '+':
2063 2065 return (getnumb());
2064 2066
2065 2067 case '-':
2066 2068 return (-getnumb());
2067 2069
2068 2070 case '(':
2069 2071 paren++;
2070 2072 return (expr());
2071 2073 }
2072 2074 }
2073 2075
2074 2076 /*
2075 2077 * getnumb - read a number from the input stream. A leading
2076 2078 * zero signifies octal interpretation, a leading '0x'
2077 2079 * signifies hexadecimal, and a leading '0t' signifies
2078 2080 * decimal. If the first character is a character,
2079 2081 * return an error.
2080 2082 */
2081 2083 static long
2082 2084 getnumb()
2083 2085 {
2084 2086
2085 2087 char c, savec;
2086 2088 long number = 0, tbase, num;
2087 2089 extern short error;
2088 2090
2089 2091 c = getachar();
2090 2092 if (!digit(c)) {
2091 2093 error++;
2092 2094 ungetachar(c);
2093 2095 return (-1);
2094 2096 }
2095 2097 if (c == '0') {
2096 2098 tbase = OCTAL;
2097 2099 if ((c = getachar()) == 'x')
2098 2100 tbase = HEX;
2099 2101 else if (c == 't')
2100 2102 tbase = DECIMAL;
2101 2103 else ungetachar(c);
2102 2104 } else {
2103 2105 tbase = base;
2104 2106 ungetachar(c);
2105 2107 }
2106 2108 for (;;) {
2107 2109 num = tbase;
2108 2110 c = savec = getachar();
2109 2111 if (HEXLETTER(c))
2110 2112 c = uppertolower(c);
2111 2113 switch (tbase) {
2112 2114 case HEX:
2113 2115 if (hexletter(c)) {
2114 2116 num = hextodigit(c);
2115 2117 break;
2116 2118 }
2117 2119 /*FALLTHRU*/
2118 2120 case DECIMAL:
2119 2121 if (digit(c))
2120 2122 num = numtodigit(c);
2121 2123 break;
2122 2124 case OCTAL:
2123 2125 if (octaldigit(c))
2124 2126 num = numtodigit(c);
2125 2127 }
2126 2128 if (num == tbase)
2127 2129 break;
2128 2130 number = number * tbase + num;
2129 2131 }
2130 2132 ungetachar(savec);
2131 2133 return (number);
2132 2134 }
2133 2135
2134 2136 /*
2135 2137 * find - the syntax is almost identical to the unix command.
2136 2138 * find dir [-name pattern] [-inum number]
2137 2139 * Note: only one of -name or -inum may be used at a time.
2138 2140 * Also, the -print is not needed (implied).
2139 2141 */
2140 2142 static void
2141 2143 find()
2142 2144 {
2143 2145 struct filenames *fn;
2144 2146 char c;
2145 2147 long temp;
2146 2148 short mode;
2147 2149
2148 2150 eat_spaces();
2149 2151 temp = cur_inum;
2150 2152 top = filenames - 1;
2151 2153 doing_cd = 1;
2152 2154 parse();
2153 2155 doing_cd = 0;
2154 2156 if (nfiles != 1) {
2155 2157 restore_inode((ino_t)temp);
2156 2158 if (!error) {
2157 2159 print_path(input_path, (int)input_pathp);
2158 2160 if (nfiles == 0)
2159 2161 printf(" not found\n");
2160 2162 else
2161 2163 printf(" ambiguous\n");
2162 2164 error++;
2163 2165 return;
2164 2166 }
2165 2167 }
2166 2168 restore_inode(filenames->ino);
2167 2169 freemem(filenames, nfiles);
2168 2170 nfiles = 0;
2169 2171 top = filenames - 1;
2170 2172 if ((mode = icheck(addr)) == 0)
2171 2173 return;
2172 2174 if ((mode & IFMT) != IFDIR) {
2173 2175 print_path(input_path, (int)input_pathp);
2174 2176 printf(" not a directory\n");
2175 2177 error++;
2176 2178 return;
2177 2179 }
2178 2180 eat_spaces();
2179 2181 if ((c = getachar()) != '-') {
2180 2182 restore_inode((ino_t)temp);
2181 2183 printf("missing '-'\n");
2182 2184 error++;
2183 2185 return;
2184 2186 }
2185 2187 find_by_name = find_by_inode = 0;
2186 2188 c = getachar();
2187 2189 if (match("name", 4)) {
2188 2190 eat_spaces();
2189 2191 find_by_name = 1;
2190 2192 } else if (match("inum", 4)) {
2191 2193 eat_spaces();
2192 2194 find_ino = expr();
2193 2195 if (error) {
2194 2196 restore_inode((ino_t)temp);
2195 2197 return;
2196 2198 }
2197 2199 while ((c = getachar()) != '\n')
2198 2200 ;
2199 2201 ungetachar(c);
2200 2202 find_by_inode = 1;
2201 2203 } else {
2202 2204 restore_inode((ino_t)temp);
2203 2205 printf("use -name or -inum with find\n");
2204 2206 error++;
2205 2207 return;
2206 2208 }
2207 2209 doing_find = 1;
2208 2210 parse();
2209 2211 doing_find = 0;
2210 2212 if (error) {
2211 2213 restore_inode((ino_t)temp);
2212 2214 return;
2213 2215 }
2214 2216 for (fn = filenames; fn <= top; fn++) {
2215 2217 if (fn->find == 0)
2216 2218 continue;
2217 2219 printf("i#: ");
2218 2220 print(fn->ino, 12, -8, 0);
2219 2221 print_path(fn->fname, (int)fn->len);
2220 2222 printf("\n");
2221 2223 }
2222 2224 restore_inode((ino_t)temp);
2223 2225 }
2224 2226
2225 2227 /*
2226 2228 * ls - do an ls. Should behave exactly as ls(1).
2227 2229 * Only -R and -l is supported and -l gives different results.
2228 2230 */
2229 2231 static void
2230 2232 ls(struct filenames *fn0, struct filenames *fnlast, short level)
2231 2233 {
2232 2234 struct filenames *fn, *fnn;
2233 2235
2234 2236 fn = fn0;
2235 2237 for (;;) {
2236 2238 fn0 = fn;
2237 2239 if (fn0->len) {
2238 2240 cmp_level = level;
2239 2241 qsort((char *)fn0, fnlast - fn0 + 1,
2240 2242 sizeof (struct filenames), fcmp);
2241 2243 }
2242 2244 for (fnn = fn, fn++; fn <= fnlast; fnn = fn, fn++) {
2243 2245 if (fnn->len != fn->len && level == fnn->len - 1)
2244 2246 break;
2245 2247 if (fnn->len == 0)
2246 2248 continue;
2247 2249 if (strcmp(fn->fname[level], fnn->fname[level]))
2248 2250 break;
2249 2251 }
2250 2252 if (fn0->len && level != fn0->len - 1)
2251 2253 ls(fn0, fnn, level + 1);
2252 2254 else {
2253 2255 if (fn0 != filenames)
2254 2256 printf("\n");
2255 2257 print_path(fn0->fname, (int)(fn0->len - 1));
2256 2258 printf(":\n");
2257 2259 if (fn0->len == 0)
2258 2260 cmp_level = level;
2259 2261 else
2260 2262 cmp_level = level + 1;
2261 2263 qsort((char *)fn0, fnn - fn0 + 1,
2262 2264 sizeof (struct filenames), fcmp);
2263 2265 formatf(fn0, fnn);
2264 2266 nfiles -= fnn - fn0 + 1;
2265 2267 }
2266 2268 if (fn > fnlast)
2267 2269 return;
2268 2270 }
2269 2271 }
2270 2272
2271 2273 /*
2272 2274 * formatf - code lifted from ls.
2273 2275 */
2274 2276 static void
2275 2277 formatf(struct filenames *fn0, struct filenames *fnlast)
2276 2278 {
2277 2279 struct filenames *fn;
2278 2280 int width = 0, w, nentry = fnlast - fn0 + 1;
2279 2281 int i, j, columns, lines;
2280 2282 char *cp;
2281 2283
2282 2284 if (long_list) {
2283 2285 columns = 1;
2284 2286 } else {
2285 2287 for (fn = fn0; fn <= fnlast; fn++) {
2286 2288 int len = strlen(fn->fname[cmp_level]) + 2;
2287 2289
2288 2290 if (len > width)
2289 2291 width = len;
2290 2292 }
2291 2293 width = (width + 8) &~ 7;
2292 2294 columns = 80 / width;
2293 2295 if (columns == 0)
2294 2296 columns = 1;
2295 2297 }
2296 2298 lines = (nentry + columns - 1) / columns;
2297 2299 for (i = 0; i < lines; i++) {
2298 2300 for (j = 0; j < columns; j++) {
2299 2301 fn = fn0 + j * lines + i;
2300 2302 if (long_list) {
2301 2303 printf("i#: ");
2302 2304 print(fn->ino, 12, -8, 0);
2303 2305 }
2304 2306 if ((cp = fmtentry(fn)) == NULL) {
2305 2307 printf("cannot read inode %ld\n", fn->ino);
2306 2308 return;
2307 2309 }
2308 2310 printf("%s", cp);
2309 2311 if (fn + lines > fnlast) {
2310 2312 printf("\n");
2311 2313 break;
2312 2314 }
2313 2315 w = strlen(cp);
2314 2316 while (w < width) {
2315 2317 w = (w + 8) &~ 7;
2316 2318 (void) putchar('\t');
2317 2319 }
2318 2320 }
2319 2321 }
2320 2322 }
2321 2323
2322 2324 /*
2323 2325 * fmtentry - code lifted from ls.
2324 2326 */
2325 2327 static char *
2326 2328 fmtentry(struct filenames *fn)
2327 2329 {
2328 2330 static char fmtres[BUFSIZ];
2329 2331 struct dinode *ip;
2330 2332 char *cptr, *cp, *dp;
2331 2333
2332 2334 dp = &fmtres[0];
2333 2335 for (cp = fn->fname[cmp_level]; *cp; cp++) {
2334 2336 if (*cp < ' ' || *cp >= 0177)
2335 2337 *dp++ = '?';
2336 2338 else
2337 2339 *dp++ = *cp;
2338 2340 }
2339 2341 addr = itob(fn->ino);
2340 2342 if ((cptr = getblk(addr)) == 0)
2341 2343 return (NULL);
2342 2344 cptr += blkoff(fs, addr);
2343 2345 /*LINTED*/
2344 2346 ip = (struct dinode *)cptr;
2345 2347 switch (ip->di_mode & IFMT) {
2346 2348 case IFDIR:
2347 2349 *dp++ = '/';
2348 2350 break;
2349 2351 case IFLNK:
2350 2352 *dp++ = '@';
2351 2353 break;
2352 2354 case IFSOCK:
2353 2355 *dp++ = '=';
2354 2356 break;
2355 2357 #ifdef IFIFO
2356 2358 case IFIFO:
2357 2359 *dp++ = 'p';
2358 2360 break;
2359 2361 #endif
2360 2362 case IFCHR:
2361 2363 case IFBLK:
2362 2364 case IFREG:
2363 2365 if (ip->di_mode & 0111)
2364 2366 *dp++ = '*';
2365 2367 else
2366 2368 *dp++ = ' ';
2367 2369 break;
2368 2370 default:
2369 2371 *dp++ = '?';
2370 2372
2371 2373 }
2372 2374 *dp++ = 0;
2373 2375 return (fmtres);
2374 2376 }
2375 2377
2376 2378 /*
2377 2379 * fcmp - routine used by qsort. Will sort first by name, then
2378 2380 * then by pathname length if names are equal. Uses global
2379 2381 * cmp_level to tell what component of the path name we are comparing.
2380 2382 */
2381 2383 static int
2382 2384 fcmp(struct filenames *f1, struct filenames *f2)
2383 2385 {
2384 2386 int value;
2385 2387
2386 2388 if ((value = strcmp(f1->fname[cmp_level], f2->fname[cmp_level])))
2387 2389 return (value);
2388 2390 return (f1->len - f2->len);
2389 2391 }
2390 2392
2391 2393 /*
2392 2394 * ffcmp - routine used by qsort. Sort only by pathname length.
2393 2395 */
2394 2396 static int
2395 2397 ffcmp(struct filenames *f1, struct filenames *f2)
2396 2398 {
2397 2399 return (f1->len - f2->len);
2398 2400 }
2399 2401
2400 2402 /*
2401 2403 * parse - set up the call to follow_path.
2402 2404 */
2403 2405 static void
2404 2406 parse()
2405 2407 {
2406 2408 int i;
2407 2409 char c;
2408 2410
2409 2411 stack_pathp = input_pathp = -1;
2410 2412 if ((c = getachar()) == '/') {
2411 2413 while ((c = getachar()) == '/')
2412 2414 ;
2413 2415 ungetachar(c);
2414 2416 cur_inum = 2;
2415 2417 c = getachar();
2416 2418 if ((c == '\n') || ((doing_cd) && (c == ' '))) {
2417 2419 ungetachar(c);
2418 2420 if (doing_cd) {
2419 2421 top++;
2420 2422 top->ino = 2;
2421 2423 top->len = -1;
2422 2424 nfiles = 1;
2423 2425 return;
2424 2426 }
2425 2427 } else
2426 2428 ungetachar(c);
2427 2429 } else {
2428 2430 ungetachar(c);
2429 2431 stack_pathp = current_pathp;
2430 2432 if (!doing_find)
2431 2433 input_pathp = current_pathp;
2432 2434 for (i = 0; i <= current_pathp; i++) {
2433 2435 if (!doing_find)
2434 2436 (void) strcpy(input_path[i], current_path[i]);
2435 2437 (void) strcpy(stack_path[i], current_path[i]);
2436 2438 }
2437 2439 }
2438 2440 getname();
2439 2441 follow_path((long)(stack_pathp + 1), cur_inum);
2440 2442 }
2441 2443
2442 2444 /*
2443 2445 * follow_path - called by cd, find, and ls.
2444 2446 * input_path holds the name typed by the user.
2445 2447 * stack_path holds the name at the current depth.
2446 2448 */
2447 2449 static void
2448 2450 follow_path(long level, long inum)
2449 2451 {
2450 2452 struct direct *dirp;
2451 2453 char **ccptr, *cptr;
2452 2454 int i;
2453 2455 struct filenames *tos, *bos, *fn, *fnn, *fnnn;
2454 2456 long block;
2455 2457 short mode;
2456 2458
2457 2459 tos = top + 1;
2458 2460 restore_inode((ino_t)inum);
2459 2461 if ((mode = icheck(addr)) == 0)
2460 2462 return;
2461 2463 if ((mode & IFMT) != IFDIR)
2462 2464 return;
2463 2465 block = cur_bytes = 0;
2464 2466 while (cur_bytes < filesize) {
2465 2467 if (block == 0 || bcomp(addr)) {
2466 2468 error = 0;
2467 2469 if ((addr = ((u_offset_t)bmap(block++) <<
2468 2470 (u_offset_t)FRGSHIFT)) == 0)
2469 2471 break;
2470 2472 if ((cptr = getblk(addr)) == 0)
2471 2473 break;
2472 2474 cptr += blkoff(fs, addr);
2473 2475 }
2474 2476 /*LINTED*/
2475 2477 dirp = (struct direct *)cptr;
2476 2478 if (dirp->d_ino) {
2477 2479 if (level > input_pathp || doing_find ||
2478 2480 compare(input_path[level], &dirp->d_name[0], 1)) {
2479 2481 if ((doing_find) &&
2480 2482 ((strcmp(dirp->d_name, ".") == 0 ||
2481 2483 strcmp(dirp->d_name, "..") == 0)))
2482 2484 goto duplicate;
2483 2485 if (++top - filenames >= maxfiles) {
2484 2486 printf("too many files\n");
2485 2487 error++;
2486 2488 return;
2487 2489 }
2488 2490 top->fname = (char **)calloc(FIRST_DEPTH, sizeof (char **));
2489 2491 top->flag = 0;
2490 2492 if (top->fname == 0) {
2491 2493 printf("out of memory\n");
2492 2494 error++;
2493 2495 return;
2494 2496 }
2495 2497 nfiles++;
2496 2498 top->ino = dirp->d_ino;
2497 2499 top->len = stack_pathp;
2498 2500 top->find = 0;
2499 2501 if (doing_find) {
2500 2502 if (find_by_name) {
2501 2503 if (compare(input_path[0], &dirp->d_name[0], 1))
2502 2504 top->find = 1;
2503 2505 } else if (find_by_inode)
2504 2506 if (find_ino == dirp->d_ino)
2505 2507 top->find = 1;
2506 2508 }
2507 2509 if (top->len + 1 >= FIRST_DEPTH && top->flag == 0) {
2508 2510 ccptr = (char **)calloc(SECOND_DEPTH, sizeof (char **));
2509 2511 if (ccptr == 0) {
2510 2512 printf("out of memory\n");
2511 2513 error++;
2512 2514 return;
2513 2515 }
2514 2516 for (i = 0; i < FIRST_DEPTH; i++)
2515 2517 ccptr[i] = top->fname[i];
2516 2518 free((char *)top->fname);
2517 2519 top->fname = ccptr;
2518 2520 top->flag = 1;
2519 2521 }
2520 2522 if (top->len >= SECOND_DEPTH) {
2521 2523 printf("maximum depth exceeded, try to cd lower\n");
2522 2524 error++;
2523 2525 return;
2524 2526 }
2525 2527 /*
2526 2528 * Copy current depth.
2527 2529 */
2528 2530 for (i = 0; i <= stack_pathp; i++) {
2529 2531 top->fname[i] = calloc(1, strlen(stack_path[i])+1);
2530 2532 if (top->fname[i] == 0) {
2531 2533 printf("out of memory\n");
2532 2534 error++;
2533 2535 return;
2534 2536 }
2535 2537 (void) strcpy(top->fname[i], stack_path[i]);
2536 2538 }
2537 2539 /*
2538 2540 * Check for '.' or '..' typed.
2539 2541 */
2540 2542 if ((level <= input_pathp) &&
2541 2543 (strcmp(input_path[level], ".") == 0 ||
2542 2544 strcmp(input_path[level], "..") == 0)) {
2543 2545 if (strcmp(input_path[level], "..") == 0 &&
2544 2546 top->len >= 0) {
2545 2547 free(top->fname[top->len]);
2546 2548 top->len -= 1;
2547 2549 }
2548 2550 } else {
2549 2551 /*
2550 2552 * Check for duplicates.
2551 2553 */
2552 2554 if (!doing_cd && !doing_find) {
2553 2555 for (fn = filenames; fn < top; fn++) {
2554 2556 if (fn->ino == dirp->d_ino &&
2555 2557 fn->len == stack_pathp + 1) {
2556 2558 for (i = 0; i < fn->len; i++)
2557 2559 if (strcmp(fn->fname[i], stack_path[i]))
2558 2560 break;
2559 2561 if (i != fn->len ||
2560 2562 strcmp(fn->fname[i], dirp->d_name))
2561 2563 continue;
2562 2564 freemem(top, 1);
2563 2565 if (top == filenames)
2564 2566 top = NULL;
2565 2567 else
2566 2568 top--;
2567 2569 nfiles--;
2568 2570 goto duplicate;
2569 2571 }
2570 2572 }
2571 2573 }
2572 2574 top->len += 1;
2573 2575 top->fname[top->len] = calloc(1,
2574 2576 strlen(&dirp->d_name[0])+1);
2575 2577 if (top->fname[top->len] == 0) {
2576 2578 printf("out of memory\n");
2577 2579 error++;
2578 2580 return;
2579 2581 }
2580 2582 (void) strcpy(top->fname[top->len], &dirp->d_name[0]);
2581 2583 }
2582 2584 }
2583 2585 }
2584 2586 duplicate:
2585 2587 addr += dirp->d_reclen;
2586 2588 cptr += dirp->d_reclen;
2587 2589 cur_bytes += dirp->d_reclen;
2588 2590 }
2589 2591 if (top < filenames)
2590 2592 return;
2591 2593 if ((doing_cd && level == input_pathp) ||
2592 2594 (!recursive && !doing_find && level > input_pathp))
2593 2595 return;
2594 2596 bos = top;
2595 2597 /*
2596 2598 * Check newly added entries to determine if further expansion
2597 2599 * is required.
2598 2600 */
2599 2601 for (fn = tos; fn <= bos; fn++) {
2600 2602 /*
2601 2603 * Avoid '.' and '..' if beyond input.
2602 2604 */
2603 2605 if ((recursive || doing_find) && (level > input_pathp) &&
2604 2606 (strcmp(fn->fname[fn->len], ".") == 0 ||
2605 2607 strcmp(fn->fname[fn->len], "..") == 0))
2606 2608 continue;
2607 2609 restore_inode(fn->ino);
2608 2610 if ((mode = icheck(cur_ino)) == 0)
2609 2611 return;
2610 2612 if ((mode & IFMT) == IFDIR || level < input_pathp) {
2611 2613 /*
2612 2614 * Set up current depth, remove current entry and
2613 2615 * continue recursion.
2614 2616 */
2615 2617 for (i = 0; i <= fn->len; i++)
2616 2618 (void) strcpy(stack_path[i], fn->fname[i]);
2617 2619 stack_pathp = fn->len;
2618 2620 if (!doing_find &&
2619 2621 (!recursive || (recursive && level <= input_pathp))) {
2620 2622 /*
2621 2623 * Remove current entry by moving others up.
2622 2624 */
2623 2625 freemem(fn, 1);
2624 2626 fnn = fn;
2625 2627 for (fnnn = fnn, fnn++; fnn <= top; fnnn = fnn, fnn++) {
2626 2628 fnnn->ino = fnn->ino;
2627 2629 fnnn->len = fnn->len;
2628 2630 if (fnnn->len + 1 < FIRST_DEPTH) {
2629 2631 fnnn->fname = (char **)calloc(FIRST_DEPTH,
2630 2632 sizeof (char **));
2631 2633 fnnn->flag = 0;
2632 2634 } else if (fnnn->len < SECOND_DEPTH) {
2633 2635 fnnn->fname = (char **)calloc(SECOND_DEPTH,
2634 2636 sizeof (char **));
2635 2637 fnnn->flag = 1;
2636 2638 } else {
2637 2639 printf("maximum depth exceeded, ");
2638 2640 printf("try to cd lower\n");
2639 2641 error++;
2640 2642 return;
2641 2643 }
2642 2644 for (i = 0; i <= fnn->len; i++)
2643 2645 fnnn->fname[i] = fnn->fname[i];
2644 2646 }
2645 2647 if (fn == tos)
2646 2648 fn--;
2647 2649 top--;
2648 2650 bos--;
2649 2651 nfiles--;
2650 2652 }
2651 2653 follow_path(level + 1, cur_inum);
2652 2654 if (error)
2653 2655 return;
2654 2656 }
2655 2657 }
2656 2658 }
2657 2659
2658 2660 /*
2659 2661 * getname - break up the pathname entered by the user into components.
2660 2662 */
2661 2663 static void
2662 2664 getname()
2663 2665 {
2664 2666 int i;
2665 2667 char c;
2666 2668
2667 2669 if ((c = getachar()) == '\n') {
2668 2670 ungetachar(c);
2669 2671 return;
2670 2672 }
2671 2673 ungetachar(c);
2672 2674 input_pathp++;
2673 2675 clear:
2674 2676 for (i = 0; i < MAXNAMLEN; i++)
2675 2677 input_path[input_pathp][i] = '\0';
2676 2678 for (;;) {
2677 2679 c = getachar();
2678 2680 if (c == '\\') {
2679 2681 if ((int)strlen(input_path[input_pathp]) + 1 >= MAXNAMLEN) {
2680 2682 printf("maximum name length exceeded, ");
2681 2683 printf("truncating\n");
2682 2684 return;
2683 2685 }
2684 2686 input_path[input_pathp][strlen(input_path[input_pathp])] = c;
2685 2687 input_path[input_pathp][strlen(input_path[input_pathp])] =
2686 2688 getachar();
2687 2689 continue;
2688 2690 }
2689 2691 if (c == ' ' || c == '\n') {
2690 2692 ungetachar(c);
2691 2693 return;
2692 2694 }
2693 2695 if (!doing_find && c == '/') {
2694 2696 if (++input_pathp >= MAXPATHLEN) {
2695 2697 printf("maximum path length exceeded, ");
2696 2698 printf("truncating\n");
2697 2699 input_pathp--;
2698 2700 return;
2699 2701 }
2700 2702 goto clear;
2701 2703 }
2702 2704 if ((int)strlen(input_path[input_pathp]) >= MAXNAMLEN) {
2703 2705 printf("maximum name length exceeded, truncating\n");
2704 2706 return;
2705 2707 }
2706 2708 input_path[input_pathp][strlen(input_path[input_pathp])] = c;
2707 2709 }
2708 2710 }
2709 2711
2710 2712 /*
2711 2713 * compare - check if a filename matches the pattern entered by the user.
2712 2714 * Handles '*', '?', and '[]'.
2713 2715 */
2714 2716 static int
2715 2717 compare(char *s1, char *s2, short at_start)
2716 2718 {
2717 2719 char c, *s;
2718 2720
2719 2721 s = s2;
2720 2722 while ((c = *s1) != NULL) {
2721 2723 if (c == '*') {
2722 2724 if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
2723 2725 return (0);
2724 2726 if (*++s1 == 0)
2725 2727 return (1);
2726 2728 while (*s2) {
2727 2729 if (compare(s1, s2, 0))
2728 2730 return (1);
2729 2731 if (error)
2730 2732 return (0);
2731 2733 s2++;
2732 2734 }
2733 2735 }
2734 2736 if (*s2 == 0)
2735 2737 return (0);
2736 2738 if (c == '\\') {
2737 2739 s1++;
2738 2740 goto compare_chars;
2739 2741 }
2740 2742 if (c == '?') {
2741 2743 if (at_start && s == s2 && !letter(*s2) && !digit(*s2))
2742 2744 return (0);
2743 2745 s1++;
2744 2746 s2++;
2745 2747 continue;
2746 2748 }
2747 2749 if (c == '[') {
2748 2750 s1++;
2749 2751 if (*s2 >= *s1++) {
2750 2752 if (*s1++ != '-') {
2751 2753 printf("missing '-'\n");
2752 2754 error++;
2753 2755 return (0);
2754 2756 }
2755 2757 if (*s2 <= *s1++) {
2756 2758 if (*s1++ != ']') {
2757 2759 printf("missing ']'");
2758 2760 error++;
2759 2761 return (0);
2760 2762 }
2761 2763 s2++;
2762 2764 continue;
2763 2765 }
2764 2766 }
2765 2767 }
2766 2768 compare_chars:
2767 2769 if (*s1++ == *s2++)
2768 2770 continue;
2769 2771 else
2770 2772 return (0);
2771 2773 }
2772 2774 if (*s1 == *s2)
2773 2775 return (1);
2774 2776 return (0);
2775 2777 }
2776 2778
2777 2779 /*
2778 2780 * freemem - free the memory allocated to the filenames structure.
2779 2781 */
2780 2782 static void
2781 2783 freemem(struct filenames *p, int numb)
2782 2784 {
2783 2785 int i, j;
2784 2786
2785 2787 if (numb == 0)
2786 2788 return;
2787 2789 for (i = 0; i < numb; i++, p++) {
2788 2790 for (j = 0; j <= p->len; j++)
2789 2791 free(p->fname[j]);
2790 2792 free((char *)p->fname);
2791 2793 }
2792 2794 }
2793 2795
2794 2796 /*
2795 2797 * print_path - print the pathname held in p.
2796 2798 */
2797 2799 static void
2798 2800 print_path(char *p[], int pntr)
2799 2801 {
2800 2802 int i;
2801 2803
2802 2804 printf("/");
2803 2805 if (pntr >= 0) {
2804 2806 for (i = 0; i < pntr; i++)
2805 2807 printf("%s/", p[i]);
2806 2808 printf("%s", p[pntr]);
2807 2809 }
2808 2810 }
2809 2811
2810 2812 /*
2811 2813 * fill - fill a section with a value or string.
2812 2814 * addr,count:fill=[value, "string"].
2813 2815 */
2814 2816 static void
2815 2817 fill()
2816 2818 {
2817 2819 char *cptr;
2818 2820 int i;
2819 2821 short eof_flag, end = 0, eof = 0;
2820 2822 long temp, tcount;
2821 2823 u_offset_t taddr;
2822 2824
2823 2825 if (wrtflag == O_RDONLY) {
2824 2826 printf("not opened for write '-w'\n");
2825 2827 error++;
2826 2828 return;
2827 2829 }
2828 2830 temp = expr();
2829 2831 if (error)
2830 2832 return;
2831 2833 if ((cptr = getblk(addr)) == 0)
2832 2834 return;
2833 2835 if (type == NUMB)
2834 2836 eof_flag = 0;
2835 2837 else
2836 2838 eof_flag = 1;
2837 2839 taddr = addr;
2838 2840 switch (objsz) {
2839 2841 case LONG:
2840 2842 addr &= ~(LONG - 1);
2841 2843 break;
2842 2844 case SHORT:
2843 2845 addr &= ~(SHORT - 1);
2844 2846 temp &= 0177777L;
2845 2847 break;
2846 2848 case CHAR:
2847 2849 temp &= 0377;
2848 2850 }
2849 2851 cur_bytes -= taddr - addr;
2850 2852 cptr += blkoff(fs, addr);
2851 2853 tcount = check_addr(eof_flag, &end, &eof, 0);
2852 2854 for (i = 0; i < tcount; i++) {
2853 2855 switch (objsz) {
2854 2856 case LONG:
2855 2857 /*LINTED*/
2856 2858 *(long *)cptr = temp;
2857 2859 break;
2858 2860 case SHORT:
2859 2861 /*LINTED*/
2860 2862 *(short *)cptr = temp;
2861 2863 break;
2862 2864 case CHAR:
2863 2865 *cptr = temp;
2864 2866 }
2865 2867 cptr += objsz;
2866 2868 }
2867 2869 addr += (tcount - 1) * objsz;
2868 2870 cur_bytes += (tcount - 1) * objsz;
2869 2871 put((u_offset_t)temp, objsz);
2870 2872 if (eof) {
2871 2873 printf("end of file\n");
2872 2874 error++;
2873 2875 } else if (end) {
2874 2876 printf("end of block\n");
2875 2877 error++;
2876 2878 }
2877 2879 }
2878 2880
2879 2881 /*
2880 2882 * get - read a byte, short or long from the file system.
2881 2883 * The entire block containing the desired item is read
2882 2884 * and the appropriate data is extracted and returned.
2883 2885 */
2884 2886 static offset_t
2885 2887 get(short lngth)
2886 2888 {
2887 2889
2888 2890 char *bptr;
2889 2891 u_offset_t temp = addr;
2890 2892
2891 2893 objsz = lngth;
2892 2894 if (objsz == INODE || objsz == SHORT)
2893 2895 temp &= ~(SHORT - 1);
2894 2896 else if (objsz == DIRECTORY || objsz == LONG || objsz == SHADOW_DATA)
2895 2897 temp &= ~(LONG - 1);
2896 2898 if ((bptr = getblk(temp)) == 0)
2897 2899 return (-1);
2898 2900 bptr += blkoff(fs, temp);
2899 2901 switch (objsz) {
2900 2902 case CHAR:
2901 2903 return ((offset_t)*bptr);
2902 2904 case SHORT:
2903 2905 case INODE:
2904 2906 /*LINTED*/
2905 2907 return ((offset_t)(*(short *)bptr));
2906 2908 case LONG:
2907 2909 case DIRECTORY:
2908 2910 case SHADOW_DATA:
2909 2911 /*LINTED*/
2910 2912 return ((offset_t)(*(long *)bptr));
2911 2913 case U_OFFSET_T:
2912 2914 /*LINTED*/
2913 2915 return (*(offset_t *)bptr);
2914 2916 }
2915 2917 return (0);
2916 2918 }
2917 2919
2918 2920 /*
2919 2921 * cgrp_check - make sure that we don't bump the cylinder group
2920 2922 * beyond the total number of cylinder groups or before the start.
2921 2923 */
2922 2924 static int
2923 2925 cgrp_check(long cgrp)
2924 2926 {
2925 2927 if (cgrp < 0) {
2926 2928 if (objsz == CGRP)
2927 2929 printf("beginning of cylinder groups\n");
2928 2930 else
2929 2931 printf("beginning of super blocks\n");
2930 2932 error++;
2931 2933 return (0);
2932 2934 }
2933 2935 if (cgrp >= fs->fs_ncg) {
2934 2936 if (objsz == CGRP)
2935 2937 printf("end of cylinder groups\n");
2936 2938 else
2937 2939 printf("end of super blocks\n");
2938 2940 error++;
2939 2941 return (0);
2940 2942 }
2941 2943 if (objsz == CGRP)
2942 2944 return (cgtod(fs, cgrp) << FRGSHIFT);
2943 2945 else
2944 2946 return (cgsblock(fs, cgrp) << FRGSHIFT);
2945 2947 }
2946 2948
2947 2949 /*
2948 2950 * icheck - make sure we can read the block containing the inode
2949 2951 * and determine the filesize (0 if inode not allocated). Return
2950 2952 * 0 if error otherwise return the mode.
2951 2953 */
2952 2954 int
2953 2955 icheck(u_offset_t address)
2954 2956 {
2955 2957 char *cptr;
2956 2958 struct dinode *ip;
2957 2959
2958 2960 if ((cptr = getblk(address)) == 0)
2959 2961 return (0);
2960 2962 cptr += blkoff(fs, address);
2961 2963 /*LINTED*/
2962 2964 ip = (struct dinode *)cptr;
2963 2965 if ((ip->di_mode & IFMT) == 0) {
2964 2966 if (!override) {
2965 2967 printf("inode not allocated\n");
2966 2968 error++;
2967 2969 return (0);
2968 2970 }
2969 2971 blocksize = filesize = 0;
2970 2972 } else {
2971 2973 trapped++;
2972 2974 filesize = ip->di_size;
2973 2975 blocksize = filesize * 2;
2974 2976 }
2975 2977 return (ip->di_mode);
2976 2978 }
2977 2979
2978 2980 /*
2979 2981 * getdirslot - get the address of the directory slot desired.
2980 2982 */
2981 2983 static u_offset_t
2982 2984 getdirslot(long slot)
2983 2985 {
2984 2986 char *cptr;
2985 2987 struct direct *dirp;
2986 2988 short i;
2987 2989 char *string = &scratch[0];
2988 2990 short bod = 0, mode, temp;
2989 2991
2990 2992 if (slot < 0) {
2991 2993 slot = 0;
2992 2994 bod++;
2993 2995 }
2994 2996 if (type != DIRECTORY) {
2995 2997 if (type == BLOCK)
2996 2998 string = "block";
2997 2999 else
2998 3000 string = "fragment";
2999 3001 addr = bod_addr;
3000 3002 if ((cptr = getblk(addr)) == 0)
3001 3003 return (0);
3002 3004 cptr += blkoff(fs, addr);
3003 3005 cur_bytes = 0;
3004 3006 /*LINTED*/
3005 3007 dirp = (struct direct *)cptr;
3006 3008 for (dirslot = 0; dirslot < slot; dirslot++) {
3007 3009 /*LINTED*/
3008 3010 dirp = (struct direct *)cptr;
3009 3011 if (blocksize > filesize) {
3010 3012 if (cur_bytes + (long)dirp->d_reclen >=
3011 3013 filesize) {
3012 3014 printf("end of file\n");
3013 3015 erraddr = addr;
3014 3016 errcur_bytes = cur_bytes;
3015 3017 stringsize = STRINGSIZE(dirp);
3016 3018 error++;
3017 3019 return (addr);
3018 3020 }
3019 3021 } else {
3020 3022 if (cur_bytes + (long)dirp->d_reclen >=
3021 3023 blocksize) {
3022 3024 printf("end of %s\n", string);
3023 3025 erraddr = addr;
3024 3026 errcur_bytes = cur_bytes;
3025 3027 stringsize = STRINGSIZE(dirp);
3026 3028 error++;
3027 3029 return (addr);
3028 3030 }
3029 3031 }
3030 3032 cptr += dirp->d_reclen;
3031 3033 addr += dirp->d_reclen;
3032 3034 cur_bytes += dirp->d_reclen;
3033 3035 }
3034 3036 if (bod) {
3035 3037 if (blocksize > filesize)
3036 3038 printf("beginning of file\n");
3037 3039 else
3038 3040 printf("beginning of %s\n", string);
3039 3041 erraddr = addr;
3040 3042 errcur_bytes = cur_bytes;
3041 3043 error++;
3042 3044 }
3043 3045 stringsize = STRINGSIZE(dirp);
3044 3046 return (addr);
3045 3047 } else {
3046 3048 addr = cur_ino;
3047 3049 if ((mode = icheck(addr)) == 0)
3048 3050 return (0);
3049 3051 if (!override && (mode & IFDIR) == 0) {
3050 3052 printf("inode is not a directory\n");
3051 3053 error++;
3052 3054 return (0);
3053 3055 }
3054 3056 temp = slot;
3055 3057 i = cur_bytes = 0;
3056 3058 for (;;) {
3057 3059 if (i == 0 || bcomp(addr)) {
3058 3060 error = 0;
3059 3061 if ((addr = (bmap((long)i++) << FRGSHIFT)) == 0)
3060 3062 break;
3061 3063 if ((cptr = getblk(addr)) == 0)
3062 3064 break;
3063 3065 cptr += blkoff(fs, addr);
3064 3066 }
3065 3067 /*LINTED*/
3066 3068 dirp = (struct direct *)cptr;
3067 3069 value = dirp->d_ino;
3068 3070 if (!temp--)
3069 3071 break;
3070 3072 if (cur_bytes + (long)dirp->d_reclen >= filesize) {
3071 3073 printf("end of file\n");
3072 3074 dirslot = slot - temp - 1;
3073 3075 objsz = DIRECTORY;
3074 3076 erraddr = addr;
3075 3077 errcur_bytes = cur_bytes;
3076 3078 stringsize = STRINGSIZE(dirp);
3077 3079 error++;
3078 3080 return (addr);
3079 3081 }
3080 3082 addr += dirp->d_reclen;
3081 3083 cptr += dirp->d_reclen;
3082 3084 cur_bytes += dirp->d_reclen;
3083 3085 }
3084 3086 dirslot = slot;
3085 3087 objsz = DIRECTORY;
3086 3088 if (bod) {
3087 3089 printf("beginning of file\n");
3088 3090 erraddr = addr;
3089 3091 errcur_bytes = cur_bytes;
3090 3092 error++;
3091 3093 }
3092 3094 stringsize = STRINGSIZE(dirp);
3093 3095 return (addr);
3094 3096 }
3095 3097 }
3096 3098
3097 3099
3098 3100 /*
3099 3101 * getshadowslot - get the address of the shadow data desired
3100 3102 */
3101 3103 static int
3102 3104 getshadowslot(long shadow)
3103 3105 {
3104 3106 struct ufs_fsd fsd;
3105 3107 short bod = 0, mode;
3106 3108 long taddr, tcurbytes;
3107 3109
3108 3110 if (shadow < 0) {
3109 3111 shadow = 0;
3110 3112 bod++;
3111 3113 }
3112 3114 if (type != SHADOW_DATA) {
3113 3115 if (shadow < cur_shad) {
3114 3116 printf("can't scan shadow data in reverse\n");
3115 3117 error++;
3116 3118 return (0);
3117 3119 }
3118 3120 } else {
3119 3121 addr = cur_ino;
3120 3122 if ((mode = icheck(addr)) == 0)
3121 3123 return (0);
3122 3124 if (!override && (mode & IFMT) != IFSHAD) {
3123 3125 printf("inode is not a shadow\n");
3124 3126 error++;
3125 3127 return (0);
3126 3128 }
3127 3129 cur_bytes = 0;
3128 3130 cur_shad = 0;
3129 3131 syncshadowscan(1); /* force synchronization */
3130 3132 }
3131 3133
3132 3134 for (; cur_shad < shadow; cur_shad++) {
3133 3135 taddr = addr;
3134 3136 tcurbytes = cur_bytes;
3135 3137 getshadowdata((long *)&fsd, LONG + LONG);
3136 3138 addr = taddr;
3137 3139 cur_bytes = tcurbytes;
3138 3140 if (cur_bytes + (long)fsd.fsd_size > filesize) {
3139 3141 syncshadowscan(0);
3140 3142 printf("end of file\n");
3141 3143 erraddr = addr;
3142 3144 errcur_bytes = cur_bytes;
3143 3145 error++;
3144 3146 return (addr);
3145 3147 }
3146 3148 addr += fsd.fsd_size;
3147 3149 cur_bytes += fsd.fsd_size;
3148 3150 syncshadowscan(0);
3149 3151 }
3150 3152 if (type == SHADOW_DATA)
3151 3153 objsz = SHADOW_DATA;
3152 3154 if (bod) {
3153 3155 printf("beginning of file\n");
3154 3156 erraddr = addr;
3155 3157 errcur_bytes = cur_bytes;
3156 3158 error++;
3157 3159 }
3158 3160 return (addr);
3159 3161 }
3160 3162
3161 3163 static void
3162 3164 getshadowdata(long *buf, int len)
3163 3165 {
3164 3166 long tfsd;
3165 3167
3166 3168 len /= LONG;
3167 3169 for (tfsd = 0; tfsd < len; tfsd++) {
3168 3170 buf[tfsd] = get(SHADOW_DATA);
3169 3171 addr += LONG;
3170 3172 cur_bytes += LONG;
3171 3173 syncshadowscan(0);
3172 3174 }
3173 3175 }
3174 3176
3175 3177 static void
3176 3178 syncshadowscan(int force)
3177 3179 {
3178 3180 long curblkoff;
3179 3181 if (type == SHADOW_DATA && (force ||
3180 3182 lblkno(fs, addr) != (bhdr.fwd)->blkno)) {
3181 3183 curblkoff = blkoff(fs, cur_bytes);
3182 3184 addr = bmap(lblkno(fs, cur_bytes)) << FRGSHIFT;
3183 3185 addr += curblkoff;
3184 3186 cur_bytes += curblkoff;
3185 3187 (void) getblk(addr);
3186 3188 objsz = SHADOW_DATA;
3187 3189 }
3188 3190 }
3189 3191
3190 3192
3191 3193
3192 3194 /*
3193 3195 * putf - print a byte as an ascii character if possible.
3194 3196 * The exceptions are tabs, newlines, backslashes
3195 3197 * and nulls which are printed as the standard C
3196 3198 * language escapes. Characters which are not
3197 3199 * recognized are printed as \?.
3198 3200 */
3199 3201 static void
3200 3202 putf(char c)
3201 3203 {
3202 3204
3203 3205 if (c <= 037 || c >= 0177 || c == '\\') {
3204 3206 printf("\\");
3205 3207 switch (c) {
3206 3208 case '\\':
3207 3209 printf("\\");
3208 3210 break;
3209 3211 case '\t':
3210 3212 printf("t");
3211 3213 break;
3212 3214 case '\n':
3213 3215 printf("n");
3214 3216 break;
3215 3217 case '\0':
3216 3218 printf("0");
3217 3219 break;
3218 3220 default:
3219 3221 printf("?");
3220 3222 }
3221 3223 } else {
3222 3224 printf("%c", c);
3223 3225 printf(" ");
3224 3226 }
3225 3227 }
3226 3228
3227 3229 /*
3228 3230 * put - write an item into the buffer for the current address
3229 3231 * block. The value is checked to make sure that it will
3230 3232 * fit in the size given without truncation. If successful,
3231 3233 * the entire block is written back to the file system.
3232 3234 */
3233 3235 static void
3234 3236 put(u_offset_t item, short lngth)
3235 3237 {
3236 3238
3237 3239 char *bptr, *sbptr;
3238 3240 long s_err, nbytes;
3239 3241 long olditem;
3240 3242
3241 3243 if (wrtflag == O_RDONLY) {
3242 3244 printf("not opened for write '-w'\n");
3243 3245 error++;
3244 3246 return;
3245 3247 }
3246 3248 objsz = lngth;
3247 3249 if ((sbptr = getblk(addr)) == 0)
3248 3250 return;
3249 3251 bptr = sbptr + blkoff(fs, addr);
3250 3252 switch (objsz) {
3251 3253 case LONG:
3252 3254 case DIRECTORY:
3253 3255 /*LINTED*/
3254 3256 olditem = *(long *)bptr;
3255 3257 /*LINTED*/
3256 3258 *(long *)bptr = item;
3257 3259 break;
3258 3260 case SHORT:
3259 3261 case INODE:
3260 3262 /*LINTED*/
3261 3263 olditem = (long)*(short *)bptr;
3262 3264 item &= 0177777L;
3263 3265 /*LINTED*/
3264 3266 *(short *)bptr = item;
3265 3267 break;
3266 3268 case CHAR:
3267 3269 olditem = (long)*bptr;
3268 3270 item &= 0377;
3269 3271 *bptr = lobyte(loword(item));
3270 3272 break;
3271 3273 default:
3272 3274 error++;
3273 3275 return;
3274 3276 }
3275 3277 if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) {
3276 3278 error++;
3277 3279 printf("seek error : %" PRIx64 "\n", addr);
3278 3280 return;
3279 3281 }
3280 3282 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
3281 3283 error++;
3282 3284 printf("write error : addr = %" PRIx64 "\n", addr);
3283 3285 printf(" : s_err = %lx\n", s_err);
3284 3286 printf(" : nbytes = %lx\n", nbytes);
3285 3287 return;
3286 3288 }
3287 3289 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
3288 3290 index(base);
3289 3291 print(olditem, 8, -8, 0);
3290 3292 printf("\t=\t");
3291 3293 print(item, 8, -8, 0);
3292 3294 printf("\n");
3293 3295 } else {
3294 3296 if (objsz == DIRECTORY) {
3295 3297 addr = cur_dir;
3296 3298 fprnt('?', 'd');
3297 3299 } else {
3298 3300 addr = cur_ino;
3299 3301 objsz = INODE;
3300 3302 fprnt('?', 'i');
3301 3303 }
3302 3304 }
3303 3305 }
3304 3306
3305 3307 /*
3306 3308 * getblk - check if the desired block is in the file system.
3307 3309 * Search the incore buffers to see if the block is already
3308 3310 * available. If successful, unlink the buffer control block
3309 3311 * from its position in the buffer list and re-insert it at
3310 3312 * the head of the list. If failure, use the last buffer
3311 3313 * in the list for the desired block. Again, this control
3312 3314 * block is placed at the head of the list. This process
3313 3315 * will leave commonly requested blocks in the in-core buffers.
3314 3316 * Finally, a pointer to the buffer is returned.
3315 3317 */
3316 3318 static char *
3317 3319 getblk(u_offset_t address)
3318 3320 {
3319 3321
3320 3322 struct lbuf *bp;
3321 3323 long s_err, nbytes;
3322 3324 unsigned long block;
3323 3325
3324 3326 read_requests++;
3325 3327 block = lblkno(fs, address);
3326 3328 if (block >= fragstoblks(fs, fs->fs_size)) {
3327 3329 printf("cannot read block %lu\n", block);
3328 3330 error++;
3329 3331 return (0);
3330 3332 }
3331 3333 for (bp = bhdr.fwd; bp != &bhdr; bp = bp->fwd)
3332 3334 if (bp->valid && bp->blkno == block)
3333 3335 goto xit;
3334 3336 actual_disk_reads++;
3335 3337 bp = bhdr.back;
3336 3338 bp->blkno = block;
3337 3339 bp->valid = 0;
3338 3340 if ((s_err = llseek(fd, (offset_t)(address & fs->fs_bmask), 0)) == -1) {
3339 3341 error++;
3340 3342 printf("seek error : %" PRIx64 "\n", address);
3341 3343 return (0);
3342 3344 }
3343 3345 if ((nbytes = read(fd, bp->blkaddr, BLKSIZE)) != BLKSIZE) {
3344 3346 error++;
3345 3347 printf("read error : addr = %" PRIx64 "\n", address);
3346 3348 printf(" : s_err = %lx\n", s_err);
3347 3349 printf(" : nbytes = %lx\n", nbytes);
3348 3350 return (0);
3349 3351 }
3350 3352 bp->valid++;
3351 3353 xit: bp->back->fwd = bp->fwd;
3352 3354 bp->fwd->back = bp->back;
3353 3355 insert(bp);
3354 3356 return (bp->blkaddr);
3355 3357 }
3356 3358
3357 3359 /*
3358 3360 * insert - place the designated buffer control block
3359 3361 * at the head of the linked list of buffers.
3360 3362 */
3361 3363 static void
3362 3364 insert(struct lbuf *bp)
3363 3365 {
3364 3366
3365 3367 bp->back = &bhdr;
3366 3368 bp->fwd = bhdr.fwd;
3367 3369 bhdr.fwd->back = bp;
3368 3370 bhdr.fwd = bp;
3369 3371 }
3370 3372
3371 3373 /*
3372 3374 * err - called on interrupts. Set the current address
3373 3375 * back to the last address stored in erraddr. Reset all
3374 3376 * appropriate flags. A reset call is made to return
3375 3377 * to the main loop;
3376 3378 */
3377 3379 #ifdef sun
3378 3380 /*ARGSUSED*/
3379 3381 static void
3380 3382 err(int sig)
3381 3383 #else
3382 3384 err()
3383 3385 #endif /* sun */
3384 3386 {
3385 3387 freemem(filenames, nfiles);
3386 3388 nfiles = 0;
3387 3389 (void) signal(2, err);
3388 3390 addr = erraddr;
3389 3391 cur_ino = errino;
3390 3392 cur_inum = errinum;
3391 3393 cur_bytes = errcur_bytes;
3392 3394 error = 0;
3393 3395 c_count = 0;
3394 3396 printf("\n?\n");
3395 3397 (void) fseek(stdin, 0L, 2);
3396 3398 longjmp(env, 0);
3397 3399 }
3398 3400
3399 3401 /*
3400 3402 * devcheck - check that the given mode represents a
3401 3403 * special device. The IFCHR bit is on for both
3402 3404 * character and block devices.
3403 3405 */
3404 3406 static int
3405 3407 devcheck(short md)
3406 3408 {
3407 3409 if (override)
3408 3410 return (0);
3409 3411 switch (md & IFMT) {
3410 3412 case IFCHR:
3411 3413 case IFBLK:
3412 3414 return (0);
3413 3415 }
3414 3416
3415 3417 printf("not character or block device\n");
3416 3418 error++;
3417 3419 return (1);
3418 3420 }
3419 3421
3420 3422 /*
3421 3423 * nullblk - return error if address is zero. This is done
3422 3424 * to prevent block 0 from being used as an indirect block
3423 3425 * for a large file or as a data block for a small file.
3424 3426 */
3425 3427 static int
3426 3428 nullblk(long bn)
3427 3429 {
3428 3430 if (bn != 0)
3429 3431 return (0);
3430 3432 printf("non existent block\n");
3431 3433 error++;
3432 3434 return (1);
3433 3435 }
3434 3436
3435 3437 /*
3436 3438 * puta - put ascii characters into a buffer. The string
3437 3439 * terminates with a quote or newline. The leading quote,
3438 3440 * which is optional for directory names, was stripped off
3439 3441 * by the assignment case in the main loop.
3440 3442 */
3441 3443 static void
3442 3444 puta()
3443 3445 {
3444 3446 char *cptr, c;
3445 3447 int i;
3446 3448 char *sbptr;
3447 3449 short terror = 0;
3448 3450 long maxchars, s_err, nbytes, temp;
3449 3451 u_offset_t taddr = addr;
3450 3452 long tcount = 0, item, olditem = 0;
3451 3453
3452 3454 if (wrtflag == O_RDONLY) {
3453 3455 printf("not opened for write '-w'\n");
3454 3456 error++;
3455 3457 return;
3456 3458 }
3457 3459 if ((sbptr = getblk(addr)) == 0)
3458 3460 return;
3459 3461 cptr = sbptr + blkoff(fs, addr);
3460 3462 if (objsz == DIRECTORY) {
3461 3463 if (acting_on_directory)
3462 3464 maxchars = stringsize - 1;
3463 3465 else
3464 3466 maxchars = LONG;
3465 3467 } else if (objsz == INODE)
3466 3468 maxchars = objsz - (addr - cur_ino);
3467 3469 else
3468 3470 maxchars = min(blocksize - cur_bytes, filesize - cur_bytes);
3469 3471 while ((c = getachar()) != '"') {
3470 3472 if (tcount >= maxchars) {
3471 3473 printf("string too long\n");
3472 3474 if (objsz == DIRECTORY)
3473 3475 addr = cur_dir;
3474 3476 else if (acting_on_inode || objsz == INODE)
3475 3477 addr = cur_ino;
3476 3478 else
3477 3479 addr = taddr;
3478 3480 erraddr = addr;
3479 3481 errcur_bytes = cur_bytes;
3480 3482 terror++;
3481 3483 break;
3482 3484 }
3483 3485 tcount++;
3484 3486 if (c == '\n') {
3485 3487 ungetachar(c);
3486 3488 break;
3487 3489 }
3488 3490 temp = (long)*cptr;
3489 3491 olditem <<= BITSPERCHAR;
3490 3492 olditem += temp & 0xff;
3491 3493 if (c == '\\') {
3492 3494 switch (c = getachar()) {
3493 3495 case 't':
3494 3496 *cptr++ = '\t';
3495 3497 break;
3496 3498 case 'n':
3497 3499 *cptr++ = '\n';
3498 3500 break;
3499 3501 case '0':
3500 3502 *cptr++ = '\0';
3501 3503 break;
3502 3504 default:
3503 3505 *cptr++ = c;
3504 3506 break;
3505 3507 }
3506 3508 }
3507 3509 else
3508 3510 *cptr++ = c;
3509 3511 }
3510 3512 if (objsz == DIRECTORY && acting_on_directory)
3511 3513 for (i = tcount; i <= maxchars; i++)
3512 3514 *cptr++ = '\0';
3513 3515 if ((s_err = llseek(fd, (offset_t)(addr & fs->fs_bmask), 0)) == -1) {
3514 3516 error++;
3515 3517 printf("seek error : %" PRIx64 "\n", addr);
3516 3518 return;
3517 3519 }
3518 3520 if ((nbytes = write(fd, sbptr, BLKSIZE)) != BLKSIZE) {
3519 3521 error++;
3520 3522 printf("write error : addr = %" PRIx64 "\n", addr);
3521 3523 printf(" : s_err = %lx\n", s_err);
3522 3524 printf(" : nbytes = %lx\n", nbytes);
3523 3525 return;
3524 3526 }
3525 3527 if (!acting_on_inode && objsz != INODE && objsz != DIRECTORY) {
3526 3528 addr += tcount;
3527 3529 cur_bytes += tcount;
3528 3530 taddr = addr;
3529 3531 if (objsz != CHAR) {
3530 3532 addr &= ~(objsz - 1);
3531 3533 cur_bytes -= taddr - addr;
3532 3534 }
3533 3535 if (addr == taddr) {
3534 3536 addr -= objsz;
3535 3537 taddr = addr;
3536 3538 }
3537 3539 tcount = LONG - (taddr - addr);
3538 3540 index(base);
3539 3541 if ((cptr = getblk(addr)) == 0)
3540 3542 return;
3541 3543 cptr += blkoff(fs, addr);
3542 3544 switch (objsz) {
3543 3545 case LONG:
3544 3546 /*LINTED*/
3545 3547 item = *(long *)cptr;
3546 3548 if (tcount < LONG) {
3547 3549 olditem <<= tcount * BITSPERCHAR;
3548 3550 temp = 1;
3549 3551 for (i = 0; i < (tcount*BITSPERCHAR); i++)
3550 3552 temp <<= 1;
3551 3553 olditem += item & (temp - 1);
3552 3554 }
3553 3555 break;
3554 3556 case SHORT:
3555 3557 /*LINTED*/
3556 3558 item = (long)*(short *)cptr;
3557 3559 if (tcount < SHORT) {
3558 3560 olditem <<= tcount * BITSPERCHAR;
3559 3561 temp = 1;
3560 3562 for (i = 0; i < (tcount * BITSPERCHAR); i++)
3561 3563 temp <<= 1;
3562 3564 olditem += item & (temp - 1);
3563 3565 }
3564 3566 olditem &= 0177777L;
3565 3567 break;
3566 3568 case CHAR:
3567 3569 item = (long)*cptr;
3568 3570 olditem &= 0377;
3569 3571 }
3570 3572 print(olditem, 8, -8, 0);
3571 3573 printf("\t=\t");
3572 3574 print(item, 8, -8, 0);
3573 3575 printf("\n");
3574 3576 } else {
3575 3577 if (objsz == DIRECTORY) {
3576 3578 addr = cur_dir;
3577 3579 fprnt('?', 'd');
3578 3580 } else {
3579 3581 addr = cur_ino;
3580 3582 objsz = INODE;
3581 3583 fprnt('?', 'i');
3582 3584 }
3583 3585 }
3584 3586 if (terror)
3585 3587 error++;
3586 3588 }
3587 3589
3588 3590 /*
3589 3591 * fprnt - print data. 'count' elements are printed where '*' will
3590 3592 * print an entire blocks worth or up to the eof, whichever
3591 3593 * occurs first. An error will occur if crossing a block boundary
3592 3594 * is attempted since consecutive blocks don't usually have
3593 3595 * meaning. Current print types:
3594 3596 * / b - print as bytes (base sensitive)
3595 3597 * c - print as characters
3596 3598 * o O - print as octal shorts (longs)
3597 3599 * d D - print as decimal shorts (longs)
3598 3600 * x X - print as hexadecimal shorts (longs)
3599 3601 * ? c - print as cylinder groups
3600 3602 * d - print as directories
3601 3603 * i - print as inodes
3602 3604 * s - print as super blocks
3603 3605 * S - print as shadow data
3604 3606 */
3605 3607 static void
3606 3608 fprnt(char style, char po)
3607 3609 {
3608 3610 int i;
3609 3611 struct fs *sb;
3610 3612 struct cg *cg;
3611 3613 struct direct *dirp;
3612 3614 struct dinode *ip;
3613 3615 int tbase;
3614 3616 char c, *cptr, *p;
3615 3617 long tinode, tcount, temp;
3616 3618 u_offset_t taddr;
3617 3619 short offset, mode, end = 0, eof = 0, eof_flag;
3618 3620 unsigned short *sptr;
3619 3621 unsigned long *lptr;
3620 3622 offset_t curoff, curioff;
3621 3623
3622 3624 laststyle = style;
3623 3625 lastpo = po;
3624 3626 should_print = 0;
3625 3627 if (count != 1) {
3626 3628 if (clear) {
3627 3629 count = 1;
3628 3630 star = 0;
3629 3631 clear = 0;
3630 3632 } else
3631 3633 clear = 1;
3632 3634 }
3633 3635 tcount = count;
3634 3636 offset = blkoff(fs, addr);
3635 3637
3636 3638 if (style == '/') {
3637 3639 if (type == NUMB)
3638 3640 eof_flag = 0;
3639 3641 else
3640 3642 eof_flag = 1;
3641 3643 switch (po) {
3642 3644
3643 3645 case 'c': /* print as characters */
3644 3646 case 'b': /* or bytes */
3645 3647 if ((cptr = getblk(addr)) == 0)
3646 3648 return;
3647 3649 cptr += offset;
3648 3650 objsz = CHAR;
3649 3651 tcount = check_addr(eof_flag, &end, &eof, 0);
3650 3652 if (tcount) {
3651 3653 for (i = 0; tcount--; i++) {
3652 3654 if (i % 16 == 0) {
3653 3655 if (i)
3654 3656 printf("\n");
3655 3657 index(base);
3656 3658 }
3657 3659 if (po == 'c') {
3658 3660 putf(*cptr++);
3659 3661 if ((i + 1) % 16)
3660 3662 printf(" ");
3661 3663 } else {
3662 3664 if ((i + 1) % 16 == 0)
3663 3665 print(*cptr++ & 0377L,
3664 3666 2, -2, 0);
3665 3667 else
3666 3668 print(*cptr++ & 0377L,
3667 3669 4, -2, 0);
3668 3670 }
3669 3671 addr += CHAR;
3670 3672 cur_bytes += CHAR;
3671 3673 }
3672 3674 printf("\n");
3673 3675 }
3674 3676 addr -= CHAR;
3675 3677 erraddr = addr;
3676 3678 cur_bytes -= CHAR;
3677 3679 errcur_bytes = cur_bytes;
3678 3680 if (eof) {
3679 3681 printf("end of file\n");
3680 3682 error++;
3681 3683 } else if (end) {
3682 3684 if (type == BLOCK)
3683 3685 printf("end of block\n");
3684 3686 else
3685 3687 printf("end of fragment\n");
3686 3688 error++;
3687 3689 }
3688 3690 return;
3689 3691
3690 3692 case 'o': /* print as octal shorts */
3691 3693 tbase = OCTAL;
3692 3694 goto otx;
3693 3695 case 'd': /* print as decimal shorts */
3694 3696 tbase = DECIMAL;
3695 3697 goto otx;
3696 3698 case 'x': /* print as hex shorts */
3697 3699 tbase = HEX;
3698 3700 otx:
3699 3701 if ((cptr = getblk(addr)) == 0)
3700 3702 return;
3701 3703 taddr = addr;
3702 3704 addr &= ~(SHORT - 1);
3703 3705 cur_bytes -= taddr - addr;
3704 3706 cptr += blkoff(fs, addr);
3705 3707 /*LINTED*/
3706 3708 sptr = (unsigned short *)cptr;
3707 3709 objsz = SHORT;
3708 3710 tcount = check_addr(eof_flag, &end, &eof, 0);
3709 3711 if (tcount) {
3710 3712 for (i = 0; tcount--; i++) {
3711 3713 sptr = (unsigned short *)print_check(
3712 3714 /*LINTED*/
3713 3715 (unsigned long *)sptr,
3714 3716 &tcount, tbase, i);
3715 3717 switch (po) {
3716 3718 case 'o':
3717 3719 printf("%06o ", *sptr++);
3718 3720 break;
3719 3721 case 'd':
3720 3722 printf("%05d ", *sptr++);
3721 3723 break;
3722 3724 case 'x':
3723 3725 printf("%04x ", *sptr++);
3724 3726 }
3725 3727 addr += SHORT;
3726 3728 cur_bytes += SHORT;
3727 3729 }
3728 3730 printf("\n");
3729 3731 }
3730 3732 addr -= SHORT;
3731 3733 erraddr = addr;
3732 3734 cur_bytes -= SHORT;
3733 3735 errcur_bytes = cur_bytes;
3734 3736 if (eof) {
3735 3737 printf("end of file\n");
3736 3738 error++;
3737 3739 } else if (end) {
3738 3740 if (type == BLOCK)
3739 3741 printf("end of block\n");
3740 3742 else
3741 3743 printf("end of fragment\n");
3742 3744 error++;
3743 3745 }
3744 3746 return;
3745 3747
3746 3748 case 'O': /* print as octal longs */
3747 3749 tbase = OCTAL;
3748 3750 goto OTX;
3749 3751 case 'D': /* print as decimal longs */
3750 3752 tbase = DECIMAL;
3751 3753 goto OTX;
3752 3754 case 'X': /* print as hex longs */
3753 3755 tbase = HEX;
3754 3756 OTX:
3755 3757 if ((cptr = getblk(addr)) == 0)
3756 3758 return;
3757 3759 taddr = addr;
3758 3760 addr &= ~(LONG - 1);
3759 3761 cur_bytes -= taddr - addr;
3760 3762 cptr += blkoff(fs, addr);
3761 3763 /*LINTED*/
3762 3764 lptr = (unsigned long *)cptr;
3763 3765 objsz = LONG;
3764 3766 tcount = check_addr(eof_flag, &end, &eof, 0);
3765 3767 if (tcount) {
3766 3768 for (i = 0; tcount--; i++) {
3767 3769 lptr = print_check(lptr, &tcount,
3768 3770 tbase, i);
3769 3771 switch (po) {
3770 3772 case 'O':
3771 3773 printf("%011lo ", *lptr++);
3772 3774 break;
3773 3775 case 'D':
3774 3776 printf("%010lu ", *lptr++);
3775 3777 break;
3776 3778 case 'X':
3777 3779 printf("%08lx ", *lptr++);
3778 3780 }
3779 3781 addr += LONG;
3780 3782 cur_bytes += LONG;
3781 3783 }
3782 3784 printf("\n");
3783 3785 }
3784 3786 addr -= LONG;
3785 3787 erraddr = addr;
3786 3788 cur_bytes -= LONG;
3787 3789 errcur_bytes = cur_bytes;
3788 3790 if (eof) {
3789 3791 printf("end of file\n");
3790 3792 error++;
3791 3793 } else if (end) {
3792 3794 if (type == BLOCK)
3793 3795 printf("end of block\n");
3794 3796 else
3795 3797 printf("end of fragment\n");
3796 3798 error++;
3797 3799 }
3798 3800 return;
3799 3801
3800 3802 default:
3801 3803 error++;
3802 3804 printf("no such print option\n");
3803 3805 return;
3804 3806 }
3805 3807 } else
3806 3808 switch (po) {
3807 3809
3808 3810 case 'c': /* print as cylinder group */
3809 3811 if (type != NUMB)
3810 3812 if (cur_cgrp + count > fs->fs_ncg) {
3811 3813 tcount = fs->fs_ncg - cur_cgrp;
3812 3814 if (!star)
3813 3815 end++;
3814 3816 }
3815 3817 addr &= ~(LONG - 1);
3816 3818 for (/* void */; tcount--; /* void */) {
3817 3819 erraddr = addr;
3818 3820 errcur_bytes = cur_bytes;
3819 3821 if (type != NUMB) {
3820 3822 addr = cgtod(fs, cur_cgrp)
3821 3823 << FRGSHIFT;
3822 3824 cur_cgrp++;
3823 3825 }
3824 3826 if ((cptr = getblk(addr)) == 0) {
3825 3827 if (cur_cgrp)
3826 3828 cur_cgrp--;
3827 3829 return;
3828 3830 }
3829 3831 cptr += blkoff(fs, addr);
3830 3832 /*LINTED*/
3831 3833 cg = (struct cg *)cptr;
3832 3834 if (type == NUMB) {
3833 3835 cur_cgrp = cg->cg_cgx + 1;
3834 3836 type = objsz = CGRP;
3835 3837 if (cur_cgrp + count - 1 > fs->fs_ncg) {
3836 3838 tcount = fs->fs_ncg - cur_cgrp;
3837 3839 if (!star)
3838 3840 end++;
3839 3841 }
3840 3842 }
3841 3843 if (! override && !cg_chkmagic(cg)) {
3842 3844 printf("invalid cylinder group ");
3843 3845 printf("magic word\n");
3844 3846 if (cur_cgrp)
3845 3847 cur_cgrp--;
3846 3848 error++;
3847 3849 return;
3848 3850 }
3849 3851 printcg(cg);
3850 3852 if (tcount)
3851 3853 printf("\n");
3852 3854 }
3853 3855 cur_cgrp--;
3854 3856 if (end) {
3855 3857 printf("end of cylinder groups\n");
3856 3858 error++;
3857 3859 }
3858 3860 return;
3859 3861
3860 3862 case 'd': /* print as directories */
3861 3863 if ((cptr = getblk(addr)) == 0)
3862 3864 return;
3863 3865 if (type == NUMB) {
3864 3866 if (fragoff(fs, addr)) {
3865 3867 printf("address must be at the ");
3866 3868 printf("beginning of a fragment\n");
3867 3869 error++;
3868 3870 return;
3869 3871 }
3870 3872 bod_addr = addr;
3871 3873 type = FRAGMENT;
3872 3874 dirslot = 0;
3873 3875 cur_bytes = 0;
3874 3876 blocksize = FRGSIZE;
3875 3877 filesize = FRGSIZE * 2;
3876 3878 }
3877 3879 cptr += offset;
3878 3880 objsz = DIRECTORY;
3879 3881 while (tcount-- && cur_bytes < filesize &&
3880 3882 cur_bytes < blocksize && !bcomp(addr)) {
3881 3883 /*LINTED*/
3882 3884 dirp = (struct direct *)cptr;
3883 3885 tinode = dirp->d_ino;
3884 3886 printf("i#: ");
3885 3887 if (tinode == 0)
3886 3888 printf("free\t");
3887 3889 else
3888 3890 print(tinode, 12, -8, 0);
3889 3891 printf("%s\n", &dirp->d_name[0]);
3890 3892 erraddr = addr;
3891 3893 errcur_bytes = cur_bytes;
3892 3894 addr += dirp->d_reclen;
3893 3895 cptr += dirp->d_reclen;
3894 3896 cur_bytes += dirp->d_reclen;
3895 3897 dirslot++;
3896 3898 stringsize = STRINGSIZE(dirp);
3897 3899 }
3898 3900 addr = erraddr;
3899 3901 cur_dir = addr;
3900 3902 cur_bytes = errcur_bytes;
3901 3903 dirslot--;
3902 3904 if (tcount >= 0 && !star) {
3903 3905 switch (type) {
3904 3906 case FRAGMENT:
3905 3907 printf("end of fragment\n");
3906 3908 break;
3907 3909 case BLOCK:
3908 3910 printf("end of block\n");
3909 3911 break;
3910 3912 default:
3911 3913 printf("end of directory\n");
3912 3914 }
3913 3915 error++;
3914 3916 } else
3915 3917 error = 0;
3916 3918 return;
3917 3919
3918 3920 case 'i': /* print as inodes */
3919 3921 /*LINTED*/
3920 3922 if ((ip = (struct dinode *)getblk(addr)) == 0)
3921 3923 return;
3922 3924 for (i = 1; i < fs->fs_ncg; i++)
3923 3925 if (addr < (cgimin(fs, i) << FRGSHIFT))
3924 3926 break;
3925 3927 i--;
3926 3928 offset /= INODE;
3927 3929 temp = (addr - (cgimin(fs, i) << FRGSHIFT)) >> FRGSHIFT;
3928 3930 temp = (i * fs->fs_ipg) + fragstoblks(fs, temp) *
3929 3931 INOPB(fs) + offset;
3930 3932 if (count + offset > INOPB(fs)) {
3931 3933 tcount = INOPB(fs) - offset;
3932 3934 if (!star)
3933 3935 end++;
3934 3936 }
3935 3937 objsz = INODE;
3936 3938 ip += offset;
3937 3939 for (i = 0; tcount--; ip++, temp++) {
3938 3940 if ((mode = icheck(addr)) == 0)
3939 3941 if (!override)
3940 3942 continue;
3941 3943 p = " ugtrwxrwxrwx";
3942 3944
3943 3945 switch (mode & IFMT) {
3944 3946 case IFDIR:
3945 3947 c = 'd';
3946 3948 break;
3947 3949 case IFCHR:
3948 3950 c = 'c';
3949 3951 break;
3950 3952 case IFBLK:
3951 3953 c = 'b';
3952 3954 break;
3953 3955 case IFREG:
3954 3956 c = '-';
3955 3957 break;
3956 3958 case IFLNK:
3957 3959 c = 'l';
3958 3960 break;
3959 3961 case IFSOCK:
3960 3962 c = 's';
3961 3963 break;
3962 3964 case IFSHAD:
3963 3965 c = 'S';
3964 3966 break;
3965 3967 case IFATTRDIR:
3966 3968 c = 'A';
3967 3969 break;
3968 3970 default:
3969 3971 c = '?';
3970 3972 if (!override)
3971 3973 goto empty;
3972 3974
3973 3975 }
3974 3976 printf("i#: ");
3975 3977 print(temp, 12, -8, 0);
3976 3978 printf(" md: ");
3977 3979 printf("%c", c);
3978 3980 for (mode = mode << 4; *++p; mode = mode << 1) {
3979 3981 if (mode & IFREG)
3980 3982 printf("%c", *p);
3981 3983 else
3982 3984 printf("-");
3983 3985 }
3984 3986 printf(" uid: ");
3985 3987 print(ip->di_uid, 8, -4, 0);
3986 3988 printf(" gid: ");
3987 3989 print(ip->di_gid, 8, -4, 0);
3988 3990 printf("\n");
3989 3991 printf("ln: ");
3990 3992 print((long)ip->di_nlink, 8, -4, 0);
3991 3993 printf(" bs: ");
3992 3994 print(ip->di_blocks, 12, -8, 0);
3993 3995 printf("c_flags : ");
3994 3996 print(ip->di_cflags, 12, -8, 0);
3995 3997 printf(" sz : ");
3996 3998 #ifdef _LARGEFILE64_SOURCE
3997 3999 printll(ip->di_size, 20, -16, 0);
3998 4000 #else /* !_LARGEFILE64_SOURCE */
3999 4001 print(ip->di_size, 12, -8, 0);
4000 4002 #endif /* _LARGEFILE64_SOURCE */
4001 4003 if (ip->di_shadow) {
4002 4004 printf(" si: ");
4003 4005 print(ip->di_shadow, 12, -8, 0);
4004 4006 }
4005 4007 printf("\n");
4006 4008 if (ip->di_oeftflag) {
4007 4009 printf("ai: ");
4008 4010 print(ip->di_oeftflag, 12, -8, 0);
4009 4011 printf("\n");
4010 4012 }
4011 4013 printf("\n");
4012 4014 switch (ip->di_mode & IFMT) {
4013 4015 case IFBLK:
4014 4016 case IFCHR:
4015 4017 printf("maj: ");
4016 4018 print(major(ip->di_ordev), 4, -2, 0);
4017 4019 printf(" min: ");
4018 4020 print(minor(ip->di_ordev), 4, -2, 0);
4019 4021 printf("\n");
4020 4022 break;
4021 4023 default:
4022 4024 /*
4023 4025 * only display blocks below the
4024 4026 * current file size
4025 4027 */
4026 4028 curoff = 0LL;
4027 4029 for (i = 0; i < NDADDR; ) {
4028 4030 if (ip->di_size <= curoff)
4029 4031 break;
4030 4032 printf("db#%x: ", i);
4031 4033 print(ip->di_db[i], 11, -8, 0);
4032 4034
4033 4035 if (++i % 4 == 0)
4034 4036 printf("\n");
4035 4037 else
4036 4038 printf(" ");
4037 4039 curoff += fs->fs_bsize;
4038 4040 }
4039 4041 if (i % 4)
4040 4042 printf("\n");
4041 4043
4042 4044 /*
4043 4045 * curioff keeps track of the number
4044 4046 * of bytes covered by each indirect
4045 4047 * pointer in the inode, and is added
4046 4048 * to curoff each time to get the
4047 4049 * actual offset into the file.
4048 4050 */
4049 4051 curioff = fs->fs_bsize *
4050 4052 (fs->fs_bsize / sizeof (daddr_t));
4051 4053 for (i = 0; i < NIADDR; i++) {
4052 4054 if (ip->di_size <= curoff)
4053 4055 break;
4054 4056 printf("ib#%x: ", i);
4055 4057 print(ip->di_ib[i], 11, -8, 0);
4056 4058 printf(" ");
4057 4059 curoff += curioff;
4058 4060 curioff *= (fs->fs_bsize /
4059 4061 sizeof (daddr_t));
4060 4062 }
4061 4063 if (i)
4062 4064 printf("\n");
4063 4065 break;
4064 4066 }
4065 4067 if (count == 1) {
4066 4068 time_t t;
4067 4069
4068 4070 t = ip->di_atime;
4069 4071 printf("\taccessed: %s", ctime(&t));
4070 4072 t = ip->di_mtime;
4071 4073 printf("\tmodified: %s", ctime(&t));
4072 4074 t = ip->di_ctime;
4073 4075 printf("\tcreated : %s", ctime(&t));
4074 4076 }
4075 4077 if (tcount)
4076 4078 printf("\n");
4077 4079 empty:
4078 4080 if (c == '?' && !override) {
4079 4081 printf("i#: ");
4080 4082 print(temp, 12, -8, 0);
4081 4083 printf(" is unallocated\n");
4082 4084 if (count != 1)
4083 4085 printf("\n");
4084 4086 }
4085 4087 cur_ino = erraddr = addr;
4086 4088 errcur_bytes = cur_bytes;
4087 4089 cur_inum++;
4088 4090 addr = addr + INODE;
4089 4091 }
4090 4092 addr = erraddr;
4091 4093 cur_bytes = errcur_bytes;
4092 4094 cur_inum--;
4093 4095 if (end) {
4094 4096 printf("end of block\n");
4095 4097 error++;
4096 4098 }
4097 4099 return;
4098 4100
4099 4101 case 's': /* print as super block */
4100 4102 if (cur_cgrp == -1) {
4101 4103 addr = SBLOCK * DEV_BSIZE;
4102 4104 type = NUMB;
4103 4105 }
4104 4106 addr &= ~(LONG - 1);
4105 4107 if (type != NUMB)
4106 4108 if (cur_cgrp + count > fs->fs_ncg) {
4107 4109 tcount = fs->fs_ncg - cur_cgrp;
4108 4110 if (!star)
4109 4111 end++;
4110 4112 }
4111 4113 for (/* void */; tcount--; /* void */) {
4112 4114 erraddr = addr;
4113 4115 cur_bytes = errcur_bytes;
4114 4116 if (type != NUMB) {
4115 4117 addr = cgsblock(fs, cur_cgrp)
4116 4118 << FRGSHIFT;
4117 4119 cur_cgrp++;
4118 4120 }
4119 4121 if ((cptr = getblk(addr)) == 0) {
4120 4122 if (cur_cgrp)
4121 4123 cur_cgrp--;
4122 4124 return;
4123 4125 }
4124 4126 cptr += blkoff(fs, addr);
4125 4127 /*LINTED*/
4126 4128 sb = (struct fs *)cptr;
4127 4129 if (type == NUMB) {
4128 4130 for (i = 0; i < fs->fs_ncg; i++)
4129 4131 if (addr == cgsblock(fs, i) <<
4130 4132 FRGSHIFT)
4131 4133 break;
4132 4134 if (i == fs->fs_ncg)
4133 4135 cur_cgrp = 0;
4134 4136 else
4135 4137 cur_cgrp = i + 1;
4136 4138 type = objsz = SB;
4137 4139 if (cur_cgrp + count - 1 > fs->fs_ncg) {
4138 4140 tcount = fs->fs_ncg - cur_cgrp;
4139 4141 if (!star)
4140 4142 end++;
4141 4143 }
4142 4144 }
4143 4145 if ((sb->fs_magic != FS_MAGIC) &&
4144 4146 (sb->fs_magic != MTB_UFS_MAGIC)) {
4145 4147 cur_cgrp = 0;
4146 4148 if (!override) {
4147 4149 printf("invalid super block ");
4148 4150 printf("magic word\n");
4149 4151 cur_cgrp--;
4150 4152 error++;
4151 4153 return;
4152 4154 }
4153 4155 }
4154 4156 if (sb->fs_magic == FS_MAGIC &&
4155 4157 (sb->fs_version !=
4156 4158 UFS_EFISTYLE4NONEFI_VERSION_2 &&
4157 4159 sb->fs_version != UFS_VERSION_MIN)) {
4158 4160 cur_cgrp = 0;
4159 4161 if (!override) {
4160 4162 printf("invalid super block ");
4161 4163 printf("version number\n");
4162 4164 cur_cgrp--;
4163 4165 error++;
4164 4166 return;
4165 4167 }
4166 4168 }
4167 4169 if (sb->fs_magic == MTB_UFS_MAGIC &&
4168 4170 (sb->fs_version > MTB_UFS_VERSION_1 ||
4169 4171 sb->fs_version < MTB_UFS_VERSION_MIN)) {
4170 4172 cur_cgrp = 0;
4171 4173 if (!override) {
4172 4174 printf("invalid super block ");
4173 4175 printf("version number\n");
4174 4176 cur_cgrp--;
4175 4177 error++;
4176 4178 return;
4177 4179 }
4178 4180 }
4179 4181 if (cur_cgrp == 0)
4180 4182 printf("\tsuper block:\n");
4181 4183 else {
4182 4184 printf("\tsuper block in cylinder ");
4183 4185 printf("group ");
4184 4186 print(cur_cgrp - 1, 0, 0, 0);
4185 4187 printf(":\n");
4186 4188 }
4187 4189 printsb(sb);
4188 4190 if (tcount)
4189 4191 printf("\n");
4190 4192 }
4191 4193 cur_cgrp--;
4192 4194 if (end) {
4193 4195 printf("end of super blocks\n");
4194 4196 error++;
4195 4197 }
4196 4198 return;
4197 4199
4198 4200 case 'S': /* print as shadow data */
4199 4201 if (type == NUMB) {
4200 4202 type = FRAGMENT;
4201 4203 cur_shad = 0;
4202 4204 cur_bytes = fragoff(fs, addr);
4203 4205 bod_addr = addr - cur_bytes;
4204 4206 /* no more than two fragments */
4205 4207 filesize = fragroundup(fs,
4206 4208 bod_addr + FRGSIZE + 1);
4207 4209 }
4208 4210 objsz = SHADOW_DATA;
4209 4211 while (tcount-- &&
4210 4212 (cur_bytes + SHADOW_DATA) <= filesize &&
4211 4213 (type != SHADOW_DATA ||
4212 4214 (cur_bytes + SHADOW_DATA)) <= blocksize) {
4213 4215 /*LINTED*/
4214 4216 struct ufs_fsd fsd;
4215 4217 long tcur_bytes;
4216 4218
4217 4219 taddr = addr;
4218 4220 tcur_bytes = cur_bytes;
4219 4221 index(base);
4220 4222 getshadowdata((long *)&fsd, LONG + LONG);
4221 4223 printf(" type: ");
4222 4224 print((long)fsd.fsd_type, 8, -8, 0);
4223 4225 printf(" size: ");
4224 4226 print((long)fsd.fsd_size, 8, -8, 0);
4225 4227 tbase = fsd.fsd_size - LONG - LONG;
4226 4228 if (tbase > 256)
4227 4229 tbase = 256;
4228 4230 for (i = 0; i < tbase; i++) {
4229 4231 if (i % LONG == 0) {
4230 4232 if (i % 16 == 0) {
4231 4233 printf("\n");
4232 4234 index(base);
4233 4235 } else
4234 4236 printf(" ");
4235 4237 getshadowdata(&temp, LONG);
4236 4238 p = (char *)&temp;
4237 4239 } else
4238 4240 printf(" ");
4239 4241 printf("%02x", (int)(*p++ & 0377L));
4240 4242 }
4241 4243 printf("\n");
4242 4244 addr = taddr;
4243 4245 cur_bytes = tcur_bytes;
4244 4246 erraddr = addr;
4245 4247 errcur_bytes = cur_bytes;
4246 4248 addr += FSD_RECSZ((&fsd), fsd.fsd_size);
4247 4249 cur_bytes += FSD_RECSZ((&fsd), fsd.fsd_size);
4248 4250 cur_shad++;
4249 4251 syncshadowscan(0);
4250 4252 }
4251 4253 addr = erraddr;
4252 4254 cur_bytes = errcur_bytes;
4253 4255 cur_shad--;
4254 4256 if (tcount >= 0 && !star) {
4255 4257 switch (type) {
4256 4258 case FRAGMENT:
4257 4259 printf("end of fragment\n");
4258 4260 break;
4259 4261 default:
4260 4262 printf("end of shadow data\n");
4261 4263 }
4262 4264 error++;
4263 4265 } else
4264 4266 error = 0;
4265 4267 return;
4266 4268 default:
4267 4269 error++;
4268 4270 printf("no such print option\n");
4269 4271 return;
4270 4272 }
4271 4273 }
4272 4274
4273 4275 /*
4274 4276 * valid_addr - call check_addr to validate the current address.
4275 4277 */
4276 4278 static int
4277 4279 valid_addr()
4278 4280 {
4279 4281 short end = 0, eof = 0;
4280 4282 long tcount = count;
4281 4283
4282 4284 if (!trapped)
4283 4285 return (1);
4284 4286 if (cur_bytes < 0) {
4285 4287 cur_bytes = 0;
4286 4288 if (blocksize > filesize) {
4287 4289 printf("beginning of file\n");
4288 4290 } else {
4289 4291 if (type == BLOCK)
4290 4292 printf("beginning of block\n");
4291 4293 else
4292 4294 printf("beginning of fragment\n");
4293 4295 }
4294 4296 error++;
4295 4297 return (0);
4296 4298 }
4297 4299 count = 1;
4298 4300 (void) check_addr(1, &end, &eof, (filesize < blocksize));
4299 4301 count = tcount;
4300 4302 if (eof) {
4301 4303 printf("end of file\n");
4302 4304 error++;
4303 4305 return (0);
4304 4306 }
4305 4307 if (end == 2) {
4306 4308 if (erraddr > addr) {
4307 4309 if (type == BLOCK)
4308 4310 printf("beginning of block\n");
4309 4311 else
4310 4312 printf("beginning of fragment\n");
4311 4313 error++;
4312 4314 return (0);
4313 4315 }
4314 4316 }
4315 4317 if (end) {
4316 4318 if (type == BLOCK)
4317 4319 printf("end of block\n");
4318 4320 else
4319 4321 printf("end of fragment\n");
4320 4322 error++;
4321 4323 return (0);
4322 4324 }
4323 4325 return (1);
4324 4326 }
4325 4327
4326 4328 /*
4327 4329 * check_addr - check if the address crosses the end of block or
4328 4330 * end of file. Return the proper count.
4329 4331 */
4330 4332 static int
4331 4333 check_addr(short eof_flag, short *end, short *eof, short keep_on)
4332 4334 {
4333 4335 long temp, tcount = count, tcur_bytes = cur_bytes;
4334 4336 u_offset_t taddr = addr;
4335 4337
4336 4338 if (bcomp(addr + count * objsz - 1) ||
4337 4339 (keep_on && taddr < (bmap(cur_block) << FRGSHIFT))) {
4338 4340 error = 0;
4339 4341 addr = taddr;
4340 4342 cur_bytes = tcur_bytes;
4341 4343 if (keep_on) {
4342 4344 if (addr < erraddr) {
4343 4345 if (cur_bytes < 0) {
4344 4346 (*end) = 2;
4345 4347 return (0); /* Value ignored */
4346 4348 }
4347 4349 temp = cur_block - lblkno(fs, cur_bytes);
4348 4350 cur_block -= temp;
4349 4351 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
4350 4352 cur_block += temp;
4351 4353 return (0); /* Value ignored */
4352 4354 }
4353 4355 temp = tcur_bytes - cur_bytes;
4354 4356 addr += temp;
4355 4357 cur_bytes += temp;
4356 4358 return (0); /* Value ignored */
4357 4359 } else {
4358 4360 if (cur_bytes >= filesize) {
4359 4361 (*eof)++;
4360 4362 return (0); /* Value ignored */
4361 4363 }
4362 4364 temp = lblkno(fs, cur_bytes) - cur_block;
4363 4365 cur_block += temp;
4364 4366 if ((addr = bmap(cur_block) << FRGSHIFT) == 0) {
4365 4367 cur_block -= temp;
4366 4368 return (0); /* Value ignored */
4367 4369 }
4368 4370 temp = tcur_bytes - cur_bytes;
4369 4371 addr += temp;
4370 4372 cur_bytes += temp;
4371 4373 return (0); /* Value ignored */
4372 4374 }
4373 4375 }
4374 4376 tcount = (blkroundup(fs, addr+1)-addr) / objsz;
4375 4377 if (!star)
4376 4378 (*end) = 2;
4377 4379 }
4378 4380 addr = taddr;
4379 4381 cur_bytes = tcur_bytes;
4380 4382 if (eof_flag) {
4381 4383 if (blocksize > filesize) {
4382 4384 if (cur_bytes >= filesize) {
4383 4385 tcount = 0;
4384 4386 (*eof)++;
4385 4387 } else if (tcount > (filesize - cur_bytes) / objsz) {
4386 4388 tcount = (filesize - cur_bytes) / objsz;
4387 4389 if (!star || tcount == 0)
4388 4390 (*eof)++;
4389 4391 }
4390 4392 } else {
4391 4393 if (cur_bytes >= blocksize) {
4392 4394 tcount = 0;
4393 4395 (*end)++;
4394 4396 } else if (tcount > (blocksize - cur_bytes) / objsz) {
4395 4397 tcount = (blocksize - cur_bytes) / objsz;
4396 4398 if (!star || tcount == 0)
4397 4399 (*end)++;
4398 4400 }
4399 4401 }
4400 4402 }
4401 4403 return (tcount);
4402 4404 }
4403 4405
4404 4406 /*
4405 4407 * print_check - check if the index needs to be printed and delete
4406 4408 * rows of zeros from the output.
4407 4409 */
4408 4410 unsigned long *
4409 4411 print_check(unsigned long *lptr, long *tcount, short tbase, int i)
4410 4412 {
4411 4413 int j, k, temp = BYTESPERLINE / objsz;
4412 4414 short first_time = 0;
4413 4415 unsigned long *tlptr;
4414 4416 unsigned short *tsptr, *sptr;
4415 4417
4416 4418 sptr = (unsigned short *)lptr;
4417 4419 if (i == 0)
4418 4420 first_time = 1;
4419 4421 if (i % temp == 0) {
4420 4422 if (*tcount >= temp - 1) {
4421 4423 if (objsz == SHORT)
4422 4424 tsptr = sptr;
4423 4425 else
4424 4426 tlptr = lptr;
4425 4427 k = *tcount - 1;
4426 4428 for (j = i; k--; j++)
4427 4429 if (objsz == SHORT) {
4428 4430 if (*tsptr++ != 0)
4429 4431 break;
4430 4432 } else {
4431 4433 if (*tlptr++ != 0)
4432 4434 break;
4433 4435 }
4434 4436 if (j > (i + temp - 1)) {
4435 4437 j = (j - i) / temp;
4436 4438 while (j-- > 0) {
4437 4439 if (objsz == SHORT)
4438 4440 sptr += temp;
4439 4441 else
4440 4442 lptr += temp;
4441 4443 *tcount -= temp;
4442 4444 i += temp;
4443 4445 addr += BYTESPERLINE;
4444 4446 cur_bytes += BYTESPERLINE;
4445 4447 }
4446 4448 if (first_time)
4447 4449 printf("*");
4448 4450 else
4449 4451 printf("\n*");
4450 4452 }
4451 4453 if (i)
4452 4454 printf("\n");
4453 4455 index(tbase);
4454 4456 } else {
4455 4457 if (i)
4456 4458 printf("\n");
4457 4459 index(tbase);
4458 4460 }
4459 4461 }
4460 4462 if (objsz == SHORT)
4461 4463 /*LINTED*/
4462 4464 return ((unsigned long *)sptr);
4463 4465 else
4464 4466 return (lptr);
4465 4467 }
4466 4468
4467 4469 /*
4468 4470 * index - print a byte index for the printout in base b
4469 4471 * with leading zeros.
4470 4472 */
4471 4473 static void
4472 4474 index(int b)
4473 4475 {
4474 4476 int tbase = base;
4475 4477
4476 4478 base = b;
4477 4479 print(addr, 8, 8, 1);
4478 4480 printf(":\t");
4479 4481 base = tbase;
4480 4482 }
4481 4483
4482 4484 /*
4483 4485 * print - print out the value to digits places with/without
4484 4486 * leading zeros and right/left justified in the current base.
4485 4487 */
4486 4488 static void
4487 4489 #ifdef _LARGEFILE64_SOURCE
4488 4490 printll(u_offset_t value, int fieldsz, int digits, int lead)
4489 4491 #else /* !_LARGEFILE64_SOURCE */
4490 4492 print(long value, int fieldsz, int digits, int lead)
4491 4493 #endif /* _LARGEFILE64_SOURCE */
4492 4494 {
4493 4495 int i, left = 0;
4494 4496 char mode = BASE[base - OCTAL];
4495 4497 char *string = &scratch[0];
4496 4498
4497 4499 if (digits < 0) {
4498 4500 left = 1;
4499 4501 digits *= -1;
4500 4502 }
4501 4503 if (base != HEX)
4502 4504 if (digits)
4503 4505 digits = digits + (digits - 1)/((base >> 1) - 1) + 1;
4504 4506 else
4505 4507 digits = 1;
4506 4508 if (lead) {
4507 4509 if (left)
4508 4510 (void) sprintf(string, "%%%c%d%d.%d"
4509 4511 #ifdef _LARGEFILE64_SOURCE
4510 4512 "ll"
4511 4513 #endif /* _LARGEFILE64_SOURCE */
4512 4514 "%c", '-', 0, digits, lead, mode);
4513 4515 else
4514 4516 (void) sprintf(string, "%%%d%d.%d"
4515 4517 #ifdef _LARGEFILE64_SOURCE
4516 4518 "ll"
4517 4519 #endif /* _LARGEFILE64_SOURCE */
4518 4520 "%c", 0, digits, lead, mode);
4519 4521 } else {
4520 4522 if (left)
4521 4523 (void) sprintf(string, "%%%c%d"
4522 4524 #ifdef _LARGEFILE64_SOURCE
4523 4525 "ll"
4524 4526 #endif /* _LARGEFILE64_SOURCE */
4525 4527 "%c", '-', digits, mode);
4526 4528 else
4527 4529 (void) sprintf(string, "%%%d"
4528 4530 #ifdef _LARGEFILE64_SOURCE
4529 4531 "ll"
4530 4532 #endif /* _LARGEFILE64_SOURCE */
4531 4533 "%c", digits, mode);
4532 4534 }
4533 4535 printf(string, value);
4534 4536 for (i = 0; i < fieldsz - digits; i++)
4535 4537 printf(" ");
4536 4538 }
4537 4539
4538 4540 /*
4539 4541 * Print out the contents of a superblock.
4540 4542 */
4541 4543 static void
4542 4544 printsb(struct fs *fs)
4543 4545 {
4544 4546 int c, i, j, k, size;
4545 4547 caddr_t sip;
4546 4548 time_t t;
4547 4549
4548 4550 t = fs->fs_time;
4549 4551 #ifdef FS_42POSTBLFMT
4550 4552 if (fs->fs_postblformat == FS_42POSTBLFMT)
4551 4553 fs->fs_nrpos = 8;
4552 4554 printf("magic\t%lx\tformat\t%s\ttime\t%s", fs->fs_magic,
4553 4555 fs->fs_postblformat == FS_42POSTBLFMT ? "static" : "dynamic",
4554 4556 ctime(&t));
4555 4557 #else
4556 4558 printf("magic\t%x\ttime\t%s",
4557 4559 fs->fs_magic, ctime(&t));
4558 4560 #endif
4559 4561 printf("version\t%x\n", fs->fs_version);
4560 4562 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4561 4563 fs->fs_cstotal.cs_nbfree, fs->fs_cstotal.cs_ndir,
4562 4564 fs->fs_cstotal.cs_nifree, fs->fs_cstotal.cs_nffree);
4563 4565 printf("ncg\t%ld\tncyl\t%ld\tsize\t%ld\tblocks\t%ld\n",
4564 4566 fs->fs_ncg, fs->fs_ncyl, fs->fs_size, fs->fs_dsize);
4565 4567 printf("bsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4566 4568 fs->fs_bsize, fs->fs_bshift, fs->fs_bmask);
4567 4569 printf("fsize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4568 4570 fs->fs_fsize, fs->fs_fshift, fs->fs_fmask);
4569 4571 printf("frag\t%ld\tshift\t%ld\tfsbtodb\t%ld\n",
4570 4572 fs->fs_frag, fs->fs_fragshift, fs->fs_fsbtodb);
4571 4573 printf("cpg\t%ld\tbpg\t%ld\tfpg\t%ld\tipg\t%ld\n",
4572 4574 fs->fs_cpg, fs->fs_fpg / fs->fs_frag, fs->fs_fpg, fs->fs_ipg);
4573 4575 printf("minfree\t%ld%%\toptim\t%s\tmaxcontig %ld\tmaxbpg\t%ld\n",
4574 4576 fs->fs_minfree, fs->fs_optim == FS_OPTSPACE ? "space" : "time",
4575 4577 fs->fs_maxcontig, fs->fs_maxbpg);
4576 4578 #ifdef FS_42POSTBLFMT
4577 4579 #ifdef sun
4578 4580 printf("rotdelay %ldms\tfs_id[0] 0x%lx\tfs_id[1] 0x%lx\trps\t%ld\n",
4579 4581 fs->fs_rotdelay, fs->fs_id[0], fs->fs_id[1], fs->fs_rps);
4580 4582 #else
4581 4583 printf("rotdelay %dms\theadswitch %dus\ttrackseek %dus\trps\t%d\n",
4582 4584 fs->fs_rotdelay, fs->fs_headswitch, fs->fs_trkseek, fs->fs_rps);
4583 4585 #endif /* sun */
4584 4586 printf("ntrak\t%ld\tnsect\t%ld\tnpsect\t%ld\tspc\t%ld\n",
4585 4587 fs->fs_ntrak, fs->fs_nsect, fs->fs_npsect, fs->fs_spc);
4586 4588 printf("trackskew %ld\n", fs->fs_trackskew);
4587 4589 #else
4588 4590 printf("rotdelay %ldms\trps\t%ld\n",
4589 4591 fs->fs_rotdelay, fs->fs_rps);
4590 4592 printf("ntrak\t%ld\tnsect\t%ld\tspc\t%ld\n",
4591 4593 fs->fs_ntrak, fs->fs_nsect, fs->fs_spc);
4592 4594 #endif
4593 4595 printf("si %ld\n", fs->fs_si);
4594 4596 printf("nindir\t%ld\tinopb\t%ld\tnspf\t%ld\n",
4595 4597 fs->fs_nindir, fs->fs_inopb, fs->fs_nspf);
4596 4598 printf("sblkno\t%ld\tcblkno\t%ld\tiblkno\t%ld\tdblkno\t%ld\n",
4597 4599 fs->fs_sblkno, fs->fs_cblkno, fs->fs_iblkno, fs->fs_dblkno);
4598 4600 printf("sbsize\t%ld\tcgsize\t%ld\tcgoffset %ld\tcgmask\t0x%08lx\n",
4599 4601 fs->fs_sbsize, fs->fs_cgsize, fs->fs_cgoffset, fs->fs_cgmask);
4600 4602 printf("csaddr\t%ld\tcssize\t%ld\tshift\t%ld\tmask\t0x%08lx\n",
4601 4603 fs->fs_csaddr, fs->fs_cssize, fs->fs_csshift, fs->fs_csmask);
4602 4604 printf("cgrotor\t%ld\tfmod\t%d\tronly\t%d\n",
4603 4605 fs->fs_cgrotor, fs->fs_fmod, fs->fs_ronly);
4604 4606 #ifdef FS_42POSTBLFMT
4605 4607 if (fs->fs_cpc != 0)
4606 4608 printf("blocks available in each of %ld rotational positions",
4607 4609 fs->fs_nrpos);
4608 4610 else
4609 4611 printf("insufficient space to maintain rotational tables\n");
4610 4612 #endif
4611 4613 for (c = 0; c < fs->fs_cpc; c++) {
4612 4614 printf("\ncylinder number %d:", c);
4613 4615 #ifdef FS_42POSTBLFMT
4614 4616 for (i = 0; i < fs->fs_nrpos; i++) {
4615 4617 /*LINTED*/
4616 4618 if (fs_postbl(fs, c)[i] == -1)
4617 4619 continue;
4618 4620 printf("\n position %d:\t", i);
4619 4621 /*LINTED*/
4620 4622 for (j = fs_postbl(fs, c)[i], k = 1; /* void */;
4621 4623 j += fs_rotbl(fs)[j], k++) {
4622 4624 printf("%5d", j);
4623 4625 if (k % 12 == 0)
4624 4626 printf("\n\t\t");
4625 4627 if (fs_rotbl(fs)[j] == 0)
4626 4628 break;
4627 4629 }
4628 4630 }
4629 4631 #else
4630 4632 for (i = 0; i < NRPOS; i++) {
4631 4633 if (fs->fs_postbl[c][i] == -1)
4632 4634 continue;
4633 4635 printf("\n position %d:\t", i);
4634 4636 for (j = fs->fs_postbl[c][i], k = 1; /* void */;
4635 4637 j += fs->fs_rotbl[j], k++) {
4636 4638 printf("%5d", j);
4637 4639 if (k % 12 == 0)
4638 4640 printf("\n\t\t");
4639 4641 if (fs->fs_rotbl[j] == 0)
4640 4642 break;
4641 4643 }
4642 4644 }
4643 4645 #endif
4644 4646 }
4645 4647 printf("\ncs[].cs_(nbfree, ndir, nifree, nffree):");
4646 4648 sip = calloc(1, fs->fs_cssize);
4647 4649 fs->fs_u.fs_csp = (struct csum *)sip;
4648 4650 for (i = 0, j = 0; i < fs->fs_cssize; i += fs->fs_bsize, j++) {
4649 4651 size = fs->fs_cssize - i < fs->fs_bsize ?
4650 4652 fs->fs_cssize - i : fs->fs_bsize;
4651 4653 (void) llseek(fd,
4652 4654 (offset_t)fsbtodb(fs, (fs->fs_csaddr + j * fs->fs_frag))
4653 4655 * fs->fs_fsize / fsbtodb(fs, 1), 0);
4654 4656 if (read(fd, sip, size) != size) {
4655 4657 free(fs->fs_u.fs_csp);
4656 4658 return;
4657 4659 }
4658 4660 sip += size;
4659 4661 }
4660 4662 for (i = 0; i < fs->fs_ncg; i++) {
4661 4663 struct csum *cs = &fs->fs_cs(fs, i);
4662 4664 if (i % 4 == 0)
4663 4665 printf("\n ");
4664 4666 printf("%d:(%ld,%ld,%ld,%ld) ", i, cs->cs_nbfree, cs->cs_ndir,
4665 4667 cs->cs_nifree, cs->cs_nffree);
4666 4668 }
4667 4669 free(fs->fs_u.fs_csp);
4668 4670 printf("\n");
4669 4671 if (fs->fs_ncyl % fs->fs_cpg) {
4670 4672 printf("cylinders in last group %d\n",
4671 4673 i = fs->fs_ncyl % fs->fs_cpg);
4672 4674 printf("blocks in last group %ld\n",
4673 4675 i * fs->fs_spc / NSPB(fs));
4674 4676 }
4675 4677 }
4676 4678
4677 4679 /*
4678 4680 * Print out the contents of a cylinder group.
4679 4681 */
4680 4682 static void
4681 4683 printcg(struct cg *cg)
4682 4684 {
4683 4685 int i, j;
4684 4686 time_t t;
4685 4687
4686 4688 printf("\ncg %ld:\n", cg->cg_cgx);
4687 4689 t = cg->cg_time;
4688 4690 #ifdef FS_42POSTBLFMT
4689 4691 printf("magic\t%lx\ttell\t%llx\ttime\t%s",
4690 4692 fs->fs_postblformat == FS_42POSTBLFMT ?
4691 4693 ((struct ocg *)cg)->cg_magic : cg->cg_magic,
4692 4694 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
4693 4695 ctime(&t));
4694 4696 #else
4695 4697 printf("magic\t%x\ttell\t%llx\ttime\t%s",
4696 4698 cg->cg_magic,
4697 4699 fsbtodb(fs, cgtod(fs, cg->cg_cgx)) * fs->fs_fsize / fsbtodb(fs, 1),
4698 4700 ctime(&t));
4699 4701 #endif
4700 4702 printf("cgx\t%ld\tncyl\t%d\tniblk\t%d\tndblk\t%ld\n",
4701 4703 cg->cg_cgx, cg->cg_ncyl, cg->cg_niblk, cg->cg_ndblk);
4702 4704 printf("nbfree\t%ld\tndir\t%ld\tnifree\t%ld\tnffree\t%ld\n",
4703 4705 cg->cg_cs.cs_nbfree, cg->cg_cs.cs_ndir,
4704 4706 cg->cg_cs.cs_nifree, cg->cg_cs.cs_nffree);
4705 4707 printf("rotor\t%ld\tirotor\t%ld\tfrotor\t%ld\nfrsum",
4706 4708 cg->cg_rotor, cg->cg_irotor, cg->cg_frotor);
4707 4709 for (i = 1, j = 0; i < fs->fs_frag; i++) {
4708 4710 printf("\t%ld", cg->cg_frsum[i]);
4709 4711 j += i * cg->cg_frsum[i];
4710 4712 }
4711 4713 printf("\nsum of frsum: %d\niused:\t", j);
4712 4714 pbits((unsigned char *)cg_inosused(cg), fs->fs_ipg);
4713 4715 printf("free:\t");
4714 4716 pbits(cg_blksfree(cg), fs->fs_fpg);
4715 4717 printf("b:\n");
4716 4718 for (i = 0; i < fs->fs_cpg; i++) {
4717 4719 /*LINTED*/
4718 4720 if (cg_blktot(cg)[i] == 0)
4719 4721 continue;
4720 4722 /*LINTED*/
4721 4723 printf(" c%d:\t(%ld)\t", i, cg_blktot(cg)[i]);
4722 4724 #ifdef FS_42POSTBLFMT
4723 4725 for (j = 0; j < fs->fs_nrpos; j++) {
4724 4726 if (fs->fs_cpc == 0 ||
4725 4727 /*LINTED*/
4726 4728 fs_postbl(fs, i % fs->fs_cpc)[j] == -1)
4727 4729 continue;
4728 4730 /*LINTED*/
4729 4731 printf(" %d", cg_blks(fs, cg, i)[j]);
4730 4732 }
4731 4733 #else
4732 4734 for (j = 0; j < NRPOS; j++) {
4733 4735 if (fs->fs_cpc == 0 ||
4734 4736 fs->fs_postbl[i % fs->fs_cpc][j] == -1)
4735 4737 continue;
4736 4738 printf(" %d", cg->cg_b[i][j]);
4737 4739 }
4738 4740 #endif
4739 4741 printf("\n");
4740 4742 }
4741 4743 }
4742 4744
4743 4745 /*
4744 4746 * Print out the contents of a bit array.
4745 4747 */
4746 4748 static void
4747 4749 pbits(unsigned char *cp, int max)
4748 4750 {
4749 4751 int i;
4750 4752 int count = 0, j;
4751 4753
4752 4754 for (i = 0; i < max; i++)
4753 4755 if (isset(cp, i)) {
4754 4756 if (count)
4755 4757 printf(",%s", count % 6 ? " " : "\n\t");
4756 4758 count++;
4757 4759 printf("%d", i);
4758 4760 j = i;
4759 4761 while ((i+1) < max && isset(cp, i+1))
4760 4762 i++;
4761 4763 if (i != j)
4762 4764 printf("-%d", i);
4763 4765 }
4764 4766 printf("\n");
4765 4767 }
4766 4768
4767 4769 /*
4768 4770 * bcomp - used to check for block over/under flows when stepping through
4769 4771 * a file system.
4770 4772 */
4771 4773 static int
4772 4774 bcomp(addr)
4773 4775 u_offset_t addr;
4774 4776 {
4775 4777 if (override)
4776 4778 return (0);
4777 4779
4778 4780 if (lblkno(fs, addr) == (bhdr.fwd)->blkno)
4779 4781 return (0);
4780 4782 error++;
4781 4783 return (1);
4782 4784 }
4783 4785
4784 4786 /*
4785 4787 * bmap - maps the logical block number of a file into
4786 4788 * the corresponding physical block on the file
4787 4789 * system.
4788 4790 */
4789 4791 static long
4790 4792 bmap(long bn)
4791 4793 {
4792 4794 int j;
4793 4795 struct dinode *ip;
4794 4796 int sh;
4795 4797 long nb;
4796 4798 char *cptr;
4797 4799
4798 4800 if ((cptr = getblk(cur_ino)) == 0)
4799 4801 return (0);
4800 4802
4801 4803 cptr += blkoff(fs, cur_ino);
4802 4804
4803 4805 /*LINTED*/
4804 4806 ip = (struct dinode *)cptr;
4805 4807
4806 4808 if (bn < NDADDR) {
4807 4809 nb = ip->di_db[bn];
4808 4810 return (nullblk(nb) ? 0L : nb);
4809 4811 }
4810 4812
4811 4813 sh = 1;
4812 4814 bn -= NDADDR;
4813 4815 for (j = NIADDR; j > 0; j--) {
4814 4816 sh *= NINDIR(fs);
4815 4817 if (bn < sh)
4816 4818 break;
4817 4819 bn -= sh;
4818 4820 }
4819 4821 if (j == 0) {
4820 4822 printf("file too big\n");
4821 4823 error++;
4822 4824 return (0L);
4823 4825 }
4824 4826 addr = (uintptr_t)&ip->di_ib[NIADDR - j];
4825 4827 nb = get(LONG);
4826 4828 if (nb == 0)
4827 4829 return (0L);
4828 4830 for (; j <= NIADDR; j++) {
4829 4831 sh /= NINDIR(fs);
4830 4832 addr = (nb << FRGSHIFT) + ((bn / sh) % NINDIR(fs)) * LONG;
4831 4833 if (nullblk(nb = get(LONG)))
4832 4834 return (0L);
4833 4835 }
4834 4836 return (nb);
4835 4837 }
4836 4838
4837 4839 #if defined(OLD_FSDB_COMPATIBILITY)
4838 4840
4839 4841 /*
4840 4842 * The following are "tacked on" to support the old fsdb functionality
4841 4843 * of clearing an inode. (All together now...) "It's better to use clri".
4842 4844 */
4843 4845
4844 4846 #define ISIZE (sizeof (struct dinode))
4845 4847 #define NI (MAXBSIZE/ISIZE)
4846 4848
4847 4849
4848 4850 static struct dinode di_buf[NI];
4849 4851
4850 4852 static union {
4851 4853 char dummy[SBSIZE];
4852 4854 struct fs sblk;
4853 4855 } sb_un;
4854 4856
4855 4857 #define sblock sb_un.sblk
4856 4858
4857 4859 static void
4858 4860 old_fsdb(int inum, char *special)
4859 4861 {
4860 4862 int f; /* File descriptor for "special" */
4861 4863 int j;
4862 4864 int status = 0;
4863 4865 u_offset_t off;
4864 4866 long gen;
4865 4867 time_t t;
4866 4868
4867 4869 f = open(special, 2);
4868 4870 if (f < 0) {
4869 4871 perror("open");
4870 4872 printf("cannot open %s\n", special);
4871 4873 exit(31+4);
4872 4874 }
4873 4875 (void) llseek(f, (offset_t)SBLOCK * DEV_BSIZE, 0);
4874 4876 if (read(f, &sblock, SBSIZE) != SBSIZE) {
4875 4877 printf("cannot read %s\n", special);
4876 4878 exit(31+4);
4877 4879 }
4878 4880 if (sblock.fs_magic != FS_MAGIC) {
4879 4881 printf("bad super block magic number\n");
4880 4882 exit(31+4);
4881 4883 }
4882 4884 if (inum == 0) {
4883 4885 printf("%d: is zero\n", inum);
4884 4886 exit(31+1);
4885 4887 }
4886 4888 off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE;
4887 4889 (void) llseek(f, off, 0);
4888 4890 if (read(f, (char *)di_buf, sblock.fs_bsize) != sblock.fs_bsize) {
4889 4891 printf("%s: read error\n", special);
4890 4892 status = 1;
4891 4893 }
4892 4894 if (status)
4893 4895 exit(31+status);
4894 4896
4895 4897 /*
4896 4898 * Update the time in superblock, so fsck will check this filesystem.
4897 4899 */
4898 4900 (void) llseek(f, (offset_t)(SBLOCK * DEV_BSIZE), 0);
4899 4901 (void) time(&t);
4900 4902 sblock.fs_time = (time32_t)t;
4901 4903 if (write(f, &sblock, SBSIZE) != SBSIZE) {
4902 4904 printf("cannot update %s\n", special);
4903 4905 exit(35);
4904 4906 }
4905 4907
4906 4908 printf("clearing %u\n", inum);
4907 4909 off = (u_offset_t)fsbtodb(&sblock, itod(&sblock, inum)) * DEV_BSIZE;
4908 4910 (void) llseek(f, off, 0);
4909 4911 read(f, (char *)di_buf, sblock.fs_bsize);
4910 4912 j = itoo(&sblock, inum);
4911 4913 gen = di_buf[j].di_gen;
4912 4914 (void) memset((caddr_t)&di_buf[j], 0, ISIZE);
4913 4915 di_buf[j].di_gen = gen + 1;
4914 4916 (void) llseek(f, off, 0);
4915 4917 write(f, (char *)di_buf, sblock.fs_bsize);
4916 4918 exit(31+status);
4917 4919 }
4918 4920
4919 4921 static int
4920 4922 isnumber(char *s)
4921 4923 {
4922 4924 register int c;
4923 4925
4924 4926 if (s == NULL)
4925 4927 return (0);
4926 4928 while ((c = *s++) != NULL)
4927 4929 if (c < '0' || c > '9')
4928 4930 return (0);
4929 4931 return (1);
4930 4932 }
4931 4933 #endif /* OLD_FSDB_COMPATIBILITY */
4932 4934
4933 4935 enum boolean { True, False };
4934 4936 extent_block_t *log_eb;
4935 4937 ml_odunit_t *log_odi;
4936 4938 int lufs_tid; /* last valid TID seen */
4937 4939
4938 4940 /*
4939 4941 * no single value is safe to use to indicate
4940 4942 * lufs_tid being invalid so we need a
4941 4943 * seperate variable.
4942 4944 */
4943 4945 enum boolean lufs_tid_valid;
4944 4946
4945 4947 /*
4946 4948 * log_get_header_info - get the basic info of the logging filesystem
4947 4949 */
4948 4950 int
4949 4951 log_get_header_info(void)
4950 4952 {
4951 4953 char *b;
4952 4954 int nb;
4953 4955
4954 4956 /*
4955 4957 * Mark the global tid as invalid everytime we're called to
4956 4958 * prevent any false positive responses.
4957 4959 */
4958 4960 lufs_tid_valid = False;
4959 4961
4960 4962 /*
4961 4963 * See if we've already set up the header areas. The only problem
4962 4964 * with this approach is we don't reread the on disk data though
4963 4965 * it shouldn't matter since we don't operate on a live disk.
4964 4966 */
4965 4967 if ((log_eb != NULL) && (log_odi != NULL))
4966 4968 return (1);
4967 4969
4968 4970 /*
4969 4971 * Either logging is disabled or we've not running 2.7.
4970 4972 */
4971 4973 if (fs->fs_logbno == 0) {
4972 4974 printf("Logging doesn't appear to be enabled on this disk\n");
4973 4975 return (0);
4974 4976 }
4975 4977
4976 4978 /*
4977 4979 * To find the log we need to first pick up the block allocation
4978 4980 * data. The block number for that data is fs_logbno in the
4979 4981 * super block.
4980 4982 */
4981 4983 if ((b = getblk((u_offset_t)ldbtob(logbtodb(fs, fs->fs_logbno))))
4982 4984 == 0) {
4983 4985 printf("getblk() indicates an error with logging block\n");
4984 4986 return (0);
4985 4987 }
4986 4988
4987 4989 /*
4988 4990 * Next we need to figure out how big the extent data structure
4989 4991 * really is. It can't be more then fs_bsize and you could just
4990 4992 * allocate that but, why get sloppy.
4991 4993 * 1 is subtracted from nextents because extent_block_t contains
4992 4994 * a single extent_t itself.
4993 4995 */
4994 4996 log_eb = (extent_block_t *)b;
4995 4997 if (log_eb->type != LUFS_EXTENTS) {
4996 4998 printf("Extents block has invalid type (0x%x)\n",
4997 4999 log_eb->type);
4998 5000 return (0);
4999 5001 }
5000 5002 nb = sizeof (extent_block_t) +
5001 5003 (sizeof (extent_t) * (log_eb->nextents - 1));
5002 5004
5003 5005 log_eb = (extent_block_t *)malloc(nb);
5004 5006 if (log_eb == NULL) {
5005 5007 printf("Failed to allocate memory for extent block log\n");
5006 5008 return (0);
5007 5009 }
5008 5010 memcpy(log_eb, b, nb);
5009 5011
5010 5012 if (log_eb->nextbno != 0)
5011 5013 /*
5012 5014 * Currently, as of 11-Dec-1997 the field nextbno isn't
5013 5015 * implemented. If someone starts using this sucker we'd
5014 5016 * better warn somebody.
5015 5017 */
5016 5018 printf("WARNING: extent block field nextbno is non-zero!\n");
5017 5019
5018 5020 /*
5019 5021 * Now read in the on disk log structure. This is always in the
5020 5022 * first block of the first extent.
5021 5023 */
5022 5024 b = getblk((u_offset_t)ldbtob(logbtodb(fs, log_eb->extents[0].pbno)));
5023 5025 log_odi = (ml_odunit_t *)malloc(sizeof (ml_odunit_t));
5024 5026 if (log_odi == NULL) {
5025 5027 free(log_eb);
5026 5028 log_eb = NULL;
5027 5029 printf("Failed to allocate memory for ondisk structure\n");
5028 5030 return (0);
5029 5031 }
5030 5032 memcpy(log_odi, b, sizeof (ml_odunit_t));
5031 5033
5032 5034 /*
5033 5035 * Consistency checks.
5034 5036 */
5035 5037 if (log_odi->od_version != LUFS_VERSION_LATEST) {
5036 5038 free(log_eb);
5037 5039 log_eb = NULL;
5038 5040 free(log_odi);
5039 5041 log_odi = NULL;
5040 5042 printf("Version mismatch in on-disk version of log data\n");
5041 5043 return (0);
5042 5044 } else if (log_odi->od_badlog) {
5043 5045 printf("WARNING: Log was marked as bad\n");
5044 5046 }
5045 5047
5046 5048 return (1);
5047 5049 }
5048 5050
5049 5051 static void
5050 5052 log_display_header(void)
5051 5053 {
5052 5054 int x;
5053 5055 if (!log_get_header_info())
5054 5056 /*
5055 5057 * No need to display anything here. The previous routine
5056 5058 * has already done so.
5057 5059 */
5058 5060 return;
5059 5061
5060 5062 if (fs->fs_magic == FS_MAGIC)
5061 5063 printf("Log block number: 0x%x\n------------------\n",
5062 5064 fs->fs_logbno);
5063 5065 else
5064 5066 printf("Log frag number: 0x%x\n------------------\n",
5065 5067 fs->fs_logbno);
5066 5068 printf("Extent Info\n\t# Extents : %d\n\t# Bytes : 0x%x\n",
5067 5069 log_eb->nextents, log_eb->nbytes);
5068 5070 printf("\tNext Block : 0x%x\n\tExtent List\n\t--------\n",
5069 5071 log_eb->nextbno);
5070 5072 for (x = 0; x < log_eb->nextents; x++)
5071 5073 printf("\t [%d] lbno 0x%08x pbno 0x%08x nbno 0x%08x\n",
5072 5074 x, log_eb->extents[x].lbno, log_eb->extents[x].pbno,
5073 5075 log_eb->extents[x].nbno);
5074 5076 printf("\nOn Disk Info\n\tbol_lof : 0x%08x\n\teol_lof : 0x%08x\n",
5075 5077 log_odi->od_bol_lof, log_odi->od_eol_lof);
5076 5078 printf("\tlog_size : 0x%08x\n",
5077 5079 log_odi->od_logsize);
5078 5080 printf("\thead_lof : 0x%08x\tident : 0x%x\n",
5079 5081 log_odi->od_head_lof, log_odi->od_head_ident);
5080 5082 printf("\ttail_lof : 0x%08x\tident : 0x%x\n\thead_tid : 0x%08x\n",
5081 5083 log_odi->od_tail_lof, log_odi->od_tail_ident, log_odi->od_head_tid);
5082 5084 printf("\tcheck sum : 0x%08x\n", log_odi->od_chksum);
5083 5085 if (log_odi->od_chksum !=
5084 5086 (log_odi->od_head_ident + log_odi->od_tail_ident))
5085 5087 printf("bad checksum: found 0x%08x, should be 0x%08x\n",
5086 5088 log_odi->od_chksum,
5087 5089 log_odi->od_head_ident + log_odi->od_tail_ident);
5088 5090 if (log_odi->od_head_lof == log_odi->od_tail_lof)
5089 5091 printf("\t --- Log is empty ---\n");
5090 5092 }
5091 5093
5092 5094 /*
5093 5095 * log_lodb -- logical log offset to disk block number
5094 5096 */
5095 5097 int
5096 5098 log_lodb(u_offset_t off, diskaddr_t *pblk)
5097 5099 {
5098 5100 uint32_t lblk = (uint32_t)btodb(off);
5099 5101 int x;
5100 5102
5101 5103 if (!log_get_header_info())
5102 5104 /*
5103 5105 * No need to display anything here. The previous routine
5104 5106 * has already done so.
5105 5107 */
5106 5108 return (0);
5107 5109
5108 5110 for (x = 0; x < log_eb->nextents; x++)
5109 5111 if ((lblk >= log_eb->extents[x].lbno) &&
5110 5112 (lblk < (log_eb->extents[x].lbno +
5111 5113 log_eb->extents[x].nbno))) {
5112 5114 *pblk = (diskaddr_t)lblk - log_eb->extents[x].lbno +
5113 5115 logbtodb(fs, log_eb->extents[x].pbno);
5114 5116 return (1);
5115 5117 }
5116 5118 return (0);
5117 5119 }
5118 5120
5119 5121 /*
5120 5122 * String names for the enumerated types. These are only used
5121 5123 * for display purposes.
5122 5124 */
5123 5125 char *dt_str[] = {
5124 5126 "DT_NONE", "DT_SB", "DT_CG", "DT_SI", "DT_AB",
5125 5127 "DT_ABZERO", "DT_DIR", "DT_INODE", "DT_FBI",
5126 5128 "DT_QR", "DT_COMMIT", "DT_CANCEL", "DT_BOT",
5127 5129 "DT_EOT", "DT_UD", "DT_SUD", "DT_SHAD", "DT_MAX"
5128 5130 };
5129 5131
5130 5132 /*
5131 5133 * log_read_log -- transfer information from the log and adjust offset
5132 5134 */
5133 5135 int
5134 5136 log_read_log(u_offset_t *addr, caddr_t va, int nb, uint32_t *chk)
5135 5137 {
5136 5138 int xfer;
5137 5139 caddr_t bp;
5138 5140 diskaddr_t pblk;
5139 5141 sect_trailer_t *st;
5140 5142
5141 5143 while (nb) {
5142 5144 if (!log_lodb(*addr, &pblk)) {
5143 5145 printf("Invalid log offset\n");
5144 5146 return (0);
5145 5147 }
5146 5148
5147 5149 /*
5148 5150 * fsdb getblk() expects offsets not block number.
5149 5151 */
5150 5152 if ((bp = getblk((u_offset_t)dbtob(pblk))) == NULL)
5151 5153 return (0);
5152 5154
5153 5155 xfer = MIN(NB_LEFT_IN_SECTOR(*addr), nb);
5154 5156 if (va != NULL) {
5155 5157 memcpy(va, bp + blkoff(fs, *addr), xfer);
5156 5158 va += xfer;
5157 5159 }
5158 5160 nb -= xfer;
5159 5161 *addr += xfer;
5160 5162
5161 5163 /*
5162 5164 * If the log offset is now at a sector trailer
5163 5165 * run the checks if requested.
5164 5166 */
5165 5167 if (NB_LEFT_IN_SECTOR(*addr) == 0) {
5166 5168 if (chk != NULL) {
5167 5169 st = (sect_trailer_t *)
5168 5170 (bp + blkoff(fs, *addr));
5169 5171 if (*chk != st->st_ident) {
5170 5172 printf(
5171 5173 "Expected sector trailer id 0x%08x, but saw 0x%08x\n",
5172 5174 *chk, st->st_ident);
5173 5175 return (0);
5174 5176 } else {
5175 5177 *chk = st->st_ident + 1;
5176 5178 /*
5177 5179 * We update the on disk structure
5178 5180 * transaction ID each time we see
5179 5181 * one. By comparing this value
5180 5182 * to the last valid DT_COMMIT record
5181 5183 * we can determine if our log is
5182 5184 * completely valid.
5183 5185 */
5184 5186 log_odi->od_head_tid = st->st_tid;
5185 5187 }
5186 5188 }
5187 5189 *addr += sizeof (sect_trailer_t);
5188 5190 }
5189 5191 if ((int32_t)*addr == log_odi->od_eol_lof)
5190 5192 *addr = log_odi->od_bol_lof;
5191 5193 }
5192 5194 return (1);
5193 5195 }
5194 5196
5195 5197 u_offset_t
5196 5198 log_nbcommit(u_offset_t a)
5197 5199 {
5198 5200 /*
5199 5201 * Comments are straight from ufs_log.c
5200 5202 *
5201 5203 * log is the offset following the commit header. However,
5202 5204 * if the commit header fell on the end-of-sector, then lof
5203 5205 * has already been advanced to the beginning of the next
5204 5206 * sector. So do nothgin. Otherwise, return the remaining
5205 5207 * bytes in the sector.
5206 5208 */
5207 5209 if ((a & (DEV_BSIZE - 1)) == 0)
5208 5210 return (0);
5209 5211 else
5210 5212 return (NB_LEFT_IN_SECTOR(a));
5211 5213 }
5212 5214
5213 5215 /*
5214 5216 * log_show -- pretty print the deltas. The number of which is determined
5215 5217 * by the log_enum arg. If LOG_ALLDELTAS the routine, as the
5216 5218 * name implies dumps everything. If LOG_NDELTAS, the routine
5217 5219 * will print out "count" deltas starting at "addr". If
5218 5220 * LOG_CHECKSCAN then run through the log checking the st_ident
5219 5221 * for valid data.
5220 5222 */
5221 5223 static void
5222 5224 log_show(enum log_enum l)
5223 5225 {
5224 5226 struct delta d;
5225 5227 int32_t bol, eol;
5226 5228 int x = 0;
5227 5229 uint32_t chk;
5228 5230
5229 5231 if (!log_get_header_info())
5230 5232 /*
5231 5233 * No need to display any error messages here. The previous
5232 5234 * routine has already done so.
5233 5235 */
5234 5236 return;
5235 5237
5236 5238 bol = log_odi->od_head_lof;
5237 5239 eol = log_odi->od_tail_lof;
5238 5240 chk = log_odi->od_head_ident;
5239 5241
5240 5242 if (bol == eol) {
5241 5243 if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) {
5242 5244 printf("Empty log.\n");
5243 5245 return;
5244 5246 } else
5245 5247 printf("WARNING: empty log. addr may generate bogus"
5246 5248 " information");
5247 5249 }
5248 5250
5249 5251 /*
5250 5252 * Only reset the "addr" if we've been requested to show all
5251 5253 * deltas in the log.
5252 5254 */
5253 5255 if ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN))
5254 5256 addr = (u_offset_t)bol;
5255 5257
5256 5258 if (l != LOG_CHECKSCAN) {
5257 5259 printf(" Log Offset Delta Count Type\n");
5258 5260 printf("-----------------------------------------"
5259 5261 "-----------------\n");
5260 5262 }
5261 5263
5262 5264 while ((bol != eol) && ((l == LOG_ALLDELTAS) ||
5263 5265 (l == LOG_CHECKSCAN) || count--)) {
5264 5266 if (!log_read_log(&addr, (caddr_t)&d, sizeof (d),
5265 5267 ((l == LOG_ALLDELTAS) || (l == LOG_CHECKSCAN)) ?
5266 5268 &chk : NULL))
5267 5269 /*
5268 5270 * Two failures are possible. One from getblk()
5269 5271 * which prints out a message or when we've hit
5270 5272 * an invalid block which may or may not indicate
5271 5273 * an error
5272 5274 */
5273 5275 goto end_scan;
5274 5276
5275 5277 if ((uint32_t)d.d_nb > log_odi->od_logsize) {
5276 5278 printf("Bad delta entry. size out of bounds\n");
5277 5279 return;
5278 5280 }
5279 5281 if (l != LOG_CHECKSCAN)
5280 5282 printf("[%04d] %08x %08x.%08x %08x %s\n", x++, bol,
5281 5283 d.d_mof, d.d_nb,
5282 5284 dt_str[d.d_typ >= DT_MAX ? DT_MAX : d.d_typ]);
5283 5285
5284 5286 switch (d.d_typ) {
5285 5287 case DT_CANCEL:
5286 5288 case DT_ABZERO:
5287 5289 /*
5288 5290 * These two deltas don't have log space
5289 5291 * associated with the entry even though
5290 5292 * d_nb is non-zero.
5291 5293 */
5292 5294 break;
5293 5295
5294 5296 case DT_COMMIT:
5295 5297 /*
5296 5298 * Commit records have zero size yet, the
5297 5299 * rest of the current disk block is avoided.
5298 5300 */
5299 5301 addr += log_nbcommit(addr);
5300 5302 lufs_tid = log_odi->od_head_tid;
5301 5303 lufs_tid_valid = True;
5302 5304 break;
5303 5305
5304 5306 default:
5305 5307 if (!log_read_log(&addr, NULL, d.d_nb,
5306 5308 ((l == LOG_ALLDELTAS) ||
5307 5309 (l == LOG_CHECKSCAN)) ? &chk : NULL))
5308 5310 goto end_scan;
5309 5311 break;
5310 5312 }
5311 5313 bol = (int32_t)addr;
5312 5314 }
5313 5315
5314 5316 end_scan:
5315 5317 if (lufs_tid_valid == True) {
5316 5318 if (lufs_tid == log_odi->od_head_tid)
5317 5319 printf("scan -- okay\n");
5318 5320 else
5319 5321 printf("scan -- some transactions have been lost\n");
5320 5322 } else {
5321 5323 printf("scan -- failed to find a single valid transaction\n");
5322 5324 printf(" (possibly due to an empty log)\n");
5323 5325 }
5324 5326 }
↓ open down ↓ |
4928 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX