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 <string.h> 42 #include <time.h> 43 44 #include <ufs/ufs/dinode.h> 45 #include <ufs/ffs/fs.h> 46 47 #include <sys/ioctl.h> 48 49 #include "fsdb.h" 50 #include "fsck.h" 51 52 static int charsperline(void); 53 static int printindir(ufs2_daddr_t blk, int level, char *bufp); 54 static void printblocks(ino_t inum, union dinode *dp); 55 56 char ** 57 crack(char *line, int *argc) 58 { 59 static char *argv[8]; 60 int i; 61 char *p, *val; 62 for (p = line, i = 0; p != NULL && i < 8; i++) { 63 while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 64 /**/; 65 if (val) 66 argv[i] = val; 67 else 68 break; 69 } 70 *argc = i; 71 return argv; 72 } 73 74 char ** 75 recrack(char *line, int *argc, int argc_max) 76 { 77 static char *argv[8]; 78 int i; 79 char *p, *val; 80 for (p = line, i = 0; p != NULL && i < 8 && i < argc_max - 1; i++) { 81 while ((val = strsep(&p, " \t\n")) != NULL && *val == '\0') 82 /**/; 83 if (val) 84 argv[i] = val; 85 else 86 break; 87 } 88 argv[i] = argv[i - 1] + strlen(argv[i - 1]) + 1; 89 argv[i][strcspn(argv[i], "\n")] = '\0'; 90 *argc = i + 1; 91 return argv; 92 } 93 94 int 95 argcount(struct cmdtable *cmdp, int argc, char *argv[]) 96 { 97 if (cmdp->minargc == cmdp->maxargc) 98 warnx("command `%s' takes %u arguments, got %u", cmdp->cmd, 99 cmdp->minargc-1, argc); 100 else 101 warnx("command `%s' takes from %u to %u arguments", 102 cmdp->cmd, cmdp->minargc-1, cmdp->maxargc-1); 103 104 warnx("usage: %s: %s", cmdp->cmd, cmdp->helptxt); 105 return 1; 106 } 107 108 void 109 printstat(const char *cp, ino_t inum, union dinode *dp) 110 { 111 struct group *grp; 112 struct passwd *pw; 113 ufs2_daddr_t blocks; 114 int64_t gen; 115 char *p; 116 time_t t; 117 118 printf("%s: ", cp); 119 switch (DIP(dp, di_mode) & IFMT) { 120 case IFDIR: 121 puts("directory"); 122 break; 123 case IFREG: 124 puts("regular file"); 125 break; 126 case IFBLK: 127 printf("block special (%d,%d)", 128 major(DIP(dp, di_rdev)), minor(DIP(dp, di_rdev))); 129 break; 130 case IFCHR: 131 printf("character special (%d,%d)", 132 major(DIP(dp, di_rdev)), minor(DIP(dp, di_rdev))); 133 break; 134 case IFLNK: 135 fputs("symlink",stdout); 136 if (DIP(dp, di_size) > 0 && 137 DIP(dp, di_size) < sblock.fs_maxsymlinklen && 138 DIP(dp, di_blocks) == 0) { 139 if (sblock.fs_magic == FS_UFS1_MAGIC) 140 p = (caddr_t)dp->dp1.di_db; 141 else 142 p = (caddr_t)dp->dp2.di_db; 143 printf(" to `%.*s'\n", (int) DIP(dp, di_size), p); 144 } else { 145 putchar('\n'); 146 } 147 break; 148 case IFSOCK: 149 puts("socket"); 150 break; 151 case IFIFO: 152 puts("fifo"); 153 break; 154 } 155 printf("I=%lu MODE=%o SIZE=%qu", (u_long)inum, DIP(dp, di_mode), 156 DIP(dp, di_size)); 157 if (sblock.fs_magic == FS_UFS1_MAGIC) 158 t = _time32_to_time(dp->dp1.di_mtime); 159 else 160 t = _time64_to_time(dp->dp2.di_mtime); 161 p = ctime(&t); 162 printf("\n\tMTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 163 DIP(dp, di_mtimensec)); 164 if (sblock.fs_magic == FS_UFS1_MAGIC) 165 t = _time32_to_time(dp->dp1.di_ctime); 166 else 167 t = _time64_to_time(dp->dp2.di_ctime); 168 p = ctime(&t); 169 printf("\n\tCTIME=%15.15s %4.4s [%d nsec]", &p[4], &p[20], 170 DIP(dp, di_ctimensec)); 171 if (sblock.fs_magic == FS_UFS1_MAGIC) 172 t = _time32_to_time(dp->dp1.di_atime); 173 else 174 t = _time64_to_time(dp->dp2.di_atime); 175 p = ctime(&t); 176 printf("\n\tATIME=%15.15s %4.4s [%d nsec]\n", &p[4], &p[20], 177 DIP(dp, di_atimensec)); 178 179 if ((pw = getpwuid(DIP(dp, di_uid)))) 180 printf("OWNER=%s ", pw->pw_name); 181 else 182 printf("OWNUID=%u ", DIP(dp, di_uid)); 183 if ((grp = getgrgid(DIP(dp, di_gid)))) 184 printf("GRP=%s ", grp->gr_name); 185 else 186 printf("GID=%u ", DIP(dp, di_gid)); 187 188 blocks = DIP(dp, di_blocks); 189 gen = DIP(dp, di_gen); 190 printf("LINKCNT=%hd FLAGS=%#x BLKCNT=%qx GEN=%qx\n", DIP(dp, di_nlink), 191 DIP(dp, di_flags), blocks, gen); 192 } 193 194 195 /* 196 * Determine the number of characters in a 197 * single line. 198 */ 199 200 static int 201 charsperline(void) 202 { 203 int columns; 204 char *cp; 205 struct winsize ws; 206 207 columns = 0; 208 if (ioctl(0, TIOCGWINSZ, &ws) != -1) 209 columns = ws.ws_col; 210 if (columns == 0 && (cp = getenv("COLUMNS"))) 211 columns = atoi(cp); 212 if (columns == 0) 213 columns = 80; /* last resort */ 214 return (columns); 215 } 216 217 218 /* 219 * Recursively print a list of indirect blocks. 220 */ 221 static int 222 printindir(ufs2_daddr_t blk, int level, char *bufp) 223 { 224 struct bufarea buf, *bp; 225 char tempbuf[32]; /* enough to print an ufs2_daddr_t */ 226 int i, j, cpl, charssofar; 227 ufs2_daddr_t blkno; 228 229 if (level == 0) { 230 /* for the final indirect level, don't use the cache */ 231 bp = &buf; 232 bp->b_un.b_buf = bufp; 233 bp->b_prev = bp->b_next = bp; 234 initbarea(bp); 235 236 getblk(bp, blk, sblock.fs_bsize); 237 } else 238 bp = getdatablk(blk, sblock.fs_bsize); 239 240 cpl = charsperline(); 241 for (i = charssofar = 0; i < NINDIR(&sblock); i++) { 242 if (sblock.fs_magic == FS_UFS1_MAGIC) 243 blkno = bp->b_un.b_indir1[i]; 244 else 245 blkno = bp->b_un.b_indir2[i]; 246 if (blkno == 0) { 247 if (level == 0) 248 putchar('\n'); 249 return 0; 250 } 251 j = sprintf(tempbuf, "%qd", blkno); 252 if (level == 0) { 253 charssofar += j; 254 if (charssofar >= cpl - 2) { 255 putchar('\n'); 256 charssofar = j; 257 } 258 } 259 fputs(tempbuf, stdout); 260 if (level == 0) { 261 printf(", "); 262 charssofar += 2; 263 } else { 264 printf(" =>\n"); 265 if (printindir(blkno, level - 1, bufp) == 0) 266 return 0; 267 } 268 } 269 if (level == 0) 270 putchar('\n'); 271 return 1; 272 } 273 274 275 /* 276 * Print the block pointers for one inode. 277 */ 278 static void 279 printblocks(ino_t inum, union dinode *dp) 280 { 281 char *bufp; 282 int i, j, nfrags; 283 long ndb, offset; 284 ufs2_daddr_t blkno; 285 286 printf("Blocks for inode %d:\n", inum); 287 printf("Direct blocks:\n"); 288 ndb = howmany(DIP(dp, di_size), sblock.fs_bsize); 289 for (i = 0; i < NDADDR; i++) { 290 if (DIP(dp, di_db[i]) == 0) { 291 putchar('\n'); 292 return; 293 } 294 if (i > 0) 295 printf(", "); 296 blkno = DIP(dp, di_db[i]); 297 printf("%qd", blkno); 298 if (--ndb == 0 && (offset = blkoff(&sblock, DIP(dp, di_size))) != 0) { 299 nfrags = numfrags(&sblock, fragroundup(&sblock, offset)); 300 printf(" (%d frag%s)", nfrags, nfrags > 1? "s": ""); 301 } 302 } 303 putchar('\n'); 304 if (DIP(dp, di_ib[0]) == 0) 305 return; 306 307 bufp = malloc((unsigned int)sblock.fs_bsize); 308 if (bufp == 0) 309 errx(EEXIT, "cannot allocate indirect block buffer"); 310 printf("Indirect blocks:\n"); 311 for (i = 0; i < NIADDR; i++) 312 if (printindir(DIP(dp, di_ib[i]), i, bufp) == 0) 313 break; 314 free(bufp); 315 } 316 317 318 int 319 checkactive(void) 320 { 321 if (!curinode) { 322 warnx("no current inode\n"); 323 return 0; 324 } 325 return 1; 326 } 327 328 int 329 checkactivedir(void) 330 { 331 if (!curinode) { 332 warnx("no current inode\n"); 333 return 0; 334 } 335 if ((DIP(curinode, di_mode) & IFMT) != IFDIR) { 336 warnx("inode %d not a directory", curinum); 337 return 0; 338 } 339 return 1; 340 } 341 342 int 343 printactive(int doblocks) 344 { 345 if (!checkactive()) 346 return 1; 347 switch (DIP(curinode, di_mode) & IFMT) { 348 case IFDIR: 349 case IFREG: 350 case IFBLK: 351 case IFCHR: 352 case IFLNK: 353 case IFSOCK: 354 case IFIFO: 355 if (doblocks) 356 printblocks(curinum, curinode); 357 else 358 printstat("current inode", curinum, curinode); 359 break; 360 case 0: 361 printf("current inode %d: unallocated inode\n", curinum); 362 break; 363 default: 364 printf("current inode %d: screwy itype 0%o (mode 0%o)?\n", 365 curinum, DIP(curinode, di_mode) & IFMT, DIP(curinode, di_mode)); 366 break; 367 } 368 return 0; 369 } 370