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