1 /* $NetBSD: fsdbutil.c,v 1.2 1995/10/08 23:18:12 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1995 John T. Kohl 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. The name of the author may not be used to endorse or promote products 16 * derived from this software without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28 * POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 #ifndef lint 32 static const char rcsid[] = 33 "$FreeBSD$"; 34 #endif /* not lint */ 35 36 #include <sys/param.h> 37 #include <ctype.h> 38 #include <err.h> 39 #include <grp.h> 40 #include <pwd.h> 41 #include <stdint.h> 42 #include <string.h> 43 #include <time.h> 44 #include <timeconv.h> 45 46 #include <ufs/ufs/dinode.h> 47 #include <ufs/ffs/fs.h> 48 49 #include <sys/ioctl.h> 50 51 #include "fsdb.h" 52 #include "fsck.h" 53 54 static int charsperline(void); 55 static int printindir(ufs2_daddr_t blk, int level, char *bufp); 56 static void printblocks(ino_t inum, union dinode *dp); 57 58 char ** 59 crack(char *line, int *argc) 60 { 61 static char *argv[8]; 62 int i; 63 char *p, *val; 64 for (p = line, i = 0; p != NULL && i < 8; i++) { 65 while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 66 /**/; 67 if (val) 68 argv[i] = val; 69 else 70 break; 71 } 72 *argc = i; 73 return argv; 74 } 75 76 char ** 77 recrack(char *line, int *argc, int argc_max) 78 { 79 static char *argv[8]; 80 int i; 81 char *p, *val; 82 for (p = line, i = 0; p != NULL && i < 8 && i < argc_max - 1; i++) { 83 while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 84 /**/; 85 if (val) 86 argv[i] = val; 87 else 88 break; 89 } 90 argv[i] = argv[i - 1] + strlen(argv[i - 1]) + 1; 91 argv[i][strcspn(argv[i], "\n")] = '\0'; 92 *argc = i + 1; 93 return argv; 94 } 95 96 int 97 argcount(struct cmdtable *cmdp, int argc, char *argv[]) 98 { 99 if (cmdp->minargc == cmdp->maxargc) 100 warnx("command `%s' takes %u arguments, got %u", cmdp->cmd, 101 cmdp->minargc-1, argc-1); 102 else 103 warnx("command `%s' takes from %u to %u arguments", 104 cmdp->cmd, cmdp->minargc-1, cmdp->maxargc-1); 105 106 warnx("usage: %s: %s", cmdp->cmd, cmdp->helptxt); 107 return 1; 108 } 109 110 void 111 printstat(const char *cp, ino_t inum, union dinode *dp) 112 { 113 struct group *grp; 114 struct passwd *pw; 115 ufs2_daddr_t blocks; 116 int64_t gen; 117 char *p; 118 time_t t; 119 120 printf("%s: ", cp); 121 switch (DIP(dp, di_mode) & IFMT) { 122 case IFDIR: 123 puts("directory"); 124 break; 125 case IFREG: 126 puts("regular file"); 127 break; 128 case IFBLK: 129 printf("block special (%d,%d)", 130 major(DIP(dp, di_rdev)), minor(DIP(dp, di_rdev))); 131 break; 132 case IFCHR: 133 printf("character special (%d,%d)", 134 major(DIP(dp, di_rdev)), minor(DIP(dp, di_rdev))); 135 break; 136 case IFLNK: 137 fputs("symlink",stdout); 138 if (DIP(dp, di_size) > 0 && 139 DIP(dp, di_size) < sblock.fs_maxsymlinklen && 140 DIP(dp, di_blocks) == 0) { 141 if (sblock.fs_magic == FS_UFS1_MAGIC) 142 p = (caddr_t)dp->dp1.di_db; 143 else 144 p = (caddr_t)dp->dp2.di_db; 145 printf(" to `%.*s'\n", (int) DIP(dp, di_size), p); 146 } else { 147 putchar('\n'); 148 } 149 break; 150 case IFSOCK: 151 puts("socket"); 152 break; 153 case IFIFO: 154 puts("fifo"); 155 break; 156 } 157 printf("I=%lu MODE=%o SIZE=%ju", (u_long)inum, DIP(dp, di_mode), 158 (uintmax_t)DIP(dp, di_size)); 159 if (sblock.fs_magic != FS_UFS1_MAGIC) { 160 t = _time64_to_time(dp->dp2.di_birthtime); 161 p = ctime(&t); 162 printf("\n\tBTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 163 dp->dp2.di_birthnsec); 164 } 165 if (sblock.fs_magic == FS_UFS1_MAGIC) 166 t = _time32_to_time(dp->dp1.di_mtime); 167 else 168 t = _time64_to_time(dp->dp2.di_mtime); 169 p = ctime(&t); 170 printf("\n\tMTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 171 DIP(dp, di_mtimensec)); 172 if (sblock.fs_magic == FS_UFS1_MAGIC) 173 t = _time32_to_time(dp->dp1.di_ctime); 174 else 175 t = _time64_to_time(dp->dp2.di_ctime); 176 p = ctime(&t); 177 printf("\n\tCTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 178 DIP(dp, di_ctimensec)); 179 if (sblock.fs_magic == FS_UFS1_MAGIC) 180 t = _time32_to_time(dp->dp1.di_atime); 181 else 182 t = _time64_to_time(dp->dp2.di_atime); 183 p = ctime(&t); 184 printf("\n\tATIME=%15.15s %4.4s [%d nsec]\n", &p[4], &p[20], 185 DIP(dp, di_atimensec)); 186 187 if ((pw = getpwuid(DIP(dp, di_uid)))) 188 printf("OWNER=%s ", pw->pw_name); 189 else 190 printf("OWNUID=%u ", DIP(dp, di_uid)); 191 if ((grp = getgrgid(DIP(dp, di_gid)))) 192 printf("GRP=%s ", grp->gr_name); 193 else 194 printf("GID=%u ", DIP(dp, di_gid)); 195 196 blocks = DIP(dp, di_blocks); 197 gen = DIP(dp, di_gen); 198 printf("LINKCNT=%hd FLAGS=%#x BLKCNT=%jx GEN=%jx\n", DIP(dp, di_nlink), 199 DIP(dp, di_flags), (intmax_t)blocks, (intmax_t)gen); 200 } 201 202 203 /* 204 * Determine the number of characters in a 205 * single line. 206 */ 207 208 static int 209 charsperline(void) 210 { 211 int columns; 212 char *cp; 213 struct winsize ws; 214 215 columns = 0; 216 if (ioctl(0, TIOCGWINSZ, &ws) != -1) 217 columns = ws.ws_col; 218 if (columns == 0 && (cp = getenv("COLUMNS"))) 219 columns = atoi(cp); 220 if (columns == 0) 221 columns = 80; /* last resort */ 222 return (columns); 223 } 224 225 226 /* 227 * Recursively print a list of indirect blocks. 228 */ 229 static int 230 printindir(ufs2_daddr_t blk, int level, char *bufp) 231 { 232 struct bufarea buf, *bp; 233 char tempbuf[32]; /* enough to print an ufs2_daddr_t */ 234 int i, j, cpl, charssofar; 235 ufs2_daddr_t blkno; 236 237 if (level == 0) { 238 /* for the final indirect level, don't use the cache */ 239 bp = &buf; 240 bp->b_un.b_buf = bufp; 241 bp->b_prev = bp->b_next = bp; 242 initbarea(bp); 243 244 getblk(bp, blk, sblock.fs_bsize); 245 } else 246 bp = getdatablk(blk, sblock.fs_bsize); 247 248 cpl = charsperline(); 249 for (i = charssofar = 0; i < NINDIR(&sblock); i++) { 250 if (sblock.fs_magic == FS_UFS1_MAGIC) 251 blkno = bp->b_un.b_indir1[i]; 252 else 253 blkno = bp->b_un.b_indir2[i]; 254 if (blkno == 0) { 255 if (level == 0) 256 putchar('\n'); 257 return 0; 258 } 259 j = sprintf(tempbuf, "%jd", (intmax_t)blkno); 260 if (level == 0) { 261 charssofar += j; 262 if (charssofar >= cpl - 2) { 263 putchar('\n'); 264 charssofar = j; 265 } 266 } 267 fputs(tempbuf, stdout); 268 if (level == 0) { 269 printf(", "); 270 charssofar += 2; 271 } else { 272 printf(" =>\n"); 273 if (printindir(blkno, level - 1, bufp) == 0) 274 return 0; 275 } 276 } 277 if (level == 0) 278 putchar('\n'); 279 return 1; 280 } 281 282 283 /* 284 * Print the block pointers for one inode. 285 */ 286 static void 287 printblocks(ino_t inum, union dinode *dp) 288 { 289 char *bufp; 290 int i, nfrags; 291 long ndb, offset; 292 ufs2_daddr_t blkno; 293 294 printf("Blocks for inode %d:\n", inum); 295 printf("Direct blocks:\n"); 296 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 297 for (i = 0; i < NDADDR; i++) { 298 if (DIP(dp, di_db[i]) == 0) { 299 putchar('\n'); 300 return; 301 } 302 if (i > 0) 303 printf(", "); 304 blkno = DIP(dp, di_db[i]); 305 printf("%jd", (intmax_t)blkno); 306 if (--ndb == 0 && (offset = blkoff(&sblock, DIP(dp, di_size))) != 0) { 307 nfrags = numfrags(&sblock, fragroundup(&sblock, offset)); 308 printf(" (%d frag%s)", nfrags, nfrags > 1? "s": ""); 309 } 310 } 311 putchar('\n'); 312 if (DIP(dp, di_ib[0]) == 0) 313 return; 314 315 bufp = malloc((unsigned int)sblock.fs_bsize); 316 if (bufp == 0) 317 errx(EEXIT, "cannot allocate indirect block buffer"); 318 printf("Indirect blocks:\n"); 319 for (i = 0; i < NIADDR; i++) 320 if (printindir(DIP(dp, di_ib[i]), i, bufp) == 0) 321 break; 322 free(bufp); 323 } 324 325 326 int 327 checkactive(void) 328 { 329 if (!curinode) { 330 warnx("no current inode\n"); 331 return 0; 332 } 333 return 1; 334 } 335 336 int 337 checkactivedir(void) 338 { 339 if (!curinode) { 340 warnx("no current inode\n"); 341 return 0; 342 } 343 if ((DIP(curinode, di_mode) & IFMT) != IFDIR) { 344 warnx("inode %d not a directory", curinum); 345 return 0; 346 } 347 return 1; 348 } 349 350 int 351 printactive(int doblocks) 352 { 353 if (!checkactive()) 354 return 1; 355 switch (DIP(curinode, di_mode) & IFMT) { 356 case IFDIR: 357 case IFREG: 358 case IFBLK: 359 case IFCHR: 360 case IFLNK: 361 case IFSOCK: 362 case IFIFO: 363 if (doblocks) 364 printblocks(curinum, curinode); 365 else 366 printstat("current inode", curinum, curinode); 367 break; 368 case 0: 369 printf("current inode %d: unallocated inode\n", curinum); 370 break; 371 default: 372 printf("current inode %d: screwy itype 0%o (mode 0%o)?\n", 373 curinum, DIP(curinode, di_mode) & IFMT, DIP(curinode, di_mode)); 374 break; 375 } 376 return 0; 377 } 378