diff options
Diffstat (limited to 'sbin/fsdb/fsdb.c')
-rw-r--r-- | sbin/fsdb/fsdb.c | 160 |
1 files changed, 99 insertions, 61 deletions
diff --git a/sbin/fsdb/fsdb.c b/sbin/fsdb/fsdb.c index c935f88952b4..48526ad4044b 100644 --- a/sbin/fsdb/fsdb.c +++ b/sbin/fsdb/fsdb.c @@ -30,11 +30,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#ifndef lint -static const char rcsid[] = - "$FreeBSD$"; -#endif /* not lint */ - #include <sys/param.h> #include <ctype.h> #include <err.h> @@ -63,6 +58,23 @@ static int find_blks64(uint64_t *buf, int size, uint64_t *blknum); static int find_indirblks32(uint32_t blk, int ind_level, uint32_t *blknum); static int find_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum); +/* + * Track modifications to the filesystem. Two types of changes are tracked. + * The first type of changes are those that are not critical to the integrity + * of the filesystem such as owner, group, time stamps, access mode, and + * generation number. The second type of changes are those that do affect + * the integrity of the filesystem including zeroing inodes, changing block + * pointers, directory entries, link counts, file lengths, file types and + * file flags. + * + * When quitting having made no changes or only changes to data that is not + * critical to filesystem integrity, the clean state of the filesystem is + * left unchanged. But if filesystem critical data are changed then fsdb + * will set the unclean flag which will require a full fsck to be run + * before the filesystem can be mounted. + */ +static int fsnoncritmodified; /* filesystem non-critical modifications */ +static int fscritmodified; /* filesystem integrity critical mods */ struct inode curip; union dinode *curinode; ino_t curinum, ocurrent; @@ -111,7 +123,7 @@ main(int argc, char *argv[]) fsys = argv[0]; sblock_init(); - if (openfilesys(fsys) == 0 || readsb(0) == 0 || setup(fsys) == 0) + if (openfilesys(fsys) == 0 || readsb() == 0 || setup(fsys) == 0) errx(1, "cannot set up file system `%s'", fsys); if (fswritefd < 0) nflag++; @@ -119,9 +131,13 @@ main(int argc, char *argv[]) nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt); rval = cmdloop(); if (!nflag) { - sblock.fs_clean = 0; /* mark it dirty */ - sbdirty(); - ckfini(0); + if (fscritmodified != 0) { + sblock.fs_clean = 0; /* mark it dirty */ + sbdirty(); + } + ckfini(fscritmodified ? 0 : sblock.fs_clean); + if (fscritmodified == 0) + exit(0); printf("*** FILE SYSTEM MARKED DIRTY\n"); printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); printf("*** IF IT IS MOUNTED, RE-MOUNT WITH -u -o reload\n"); @@ -142,6 +158,7 @@ CMDFUNC(uplink); /* incr link */ CMDFUNC(downlink); /* decr link */ CMDFUNC(linkcount); /* set link count */ CMDFUNC(quit); /* quit */ +CMDFUNC(quitclean); /* quit with filesystem marked clean */ CMDFUNC(findblk); /* find block */ CMDFUNC(ls); /* list directory */ CMDFUNC(rm); /* remove name */ @@ -161,40 +178,42 @@ CMDFUNC(chatime); /* Change atime */ CMDFUNC(chinum); /* Change inode # of dirent */ CMDFUNC(chname); /* Change dirname of dirent */ CMDFUNC(chsize); /* Change size */ +CMDFUNC(chdb); /* Change direct block pointer */ struct cmdtable cmds[] = { { "help", "Print out help", 1, 1, FL_RO, helpfn }, { "?", "Print out help", 1, 1, FL_RO, helpfn }, { "inode", "Set active inode to INUM", 2, 2, FL_RO, focus }, - { "clri", "Clear inode INUM", 2, 2, FL_WR, zapi }, + { "clri", "Clear inode INUM", 2, 2, FL_CWR, zapi }, { "lookup", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname }, { "cd", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname }, { "back", "Go to previous active inode", 1, 1, FL_RO, back }, { "active", "Print active inode", 1, 1, FL_RO, active }, { "print", "Print active inode", 1, 1, FL_RO, active }, { "blocks", "Print block numbers of active inode", 1, 1, FL_RO, blocks }, - { "uplink", "Increment link count", 1, 1, FL_WR, uplink }, - { "downlink", "Decrement link count", 1, 1, FL_WR, downlink }, - { "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount }, + { "uplink", "Increment link count", 1, 1, FL_CWR, uplink }, + { "downlink", "Decrement link count", 1, 1, FL_CWR, downlink }, + { "linkcount", "Set link count to COUNT", 2, 2, FL_CWR, linkcount }, { "findblk", "Find inode owning disk block(s)", 2, 33, FL_RO, findblk}, { "ls", "List current inode as directory", 1, 1, FL_RO, ls }, - { "rm", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm }, - { "del", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm }, - { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_WR | FL_ST, ln }, - { "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_WR, chinum }, + { "rm", "Remove NAME from current inode directory", 2, 2, FL_CWR | FL_ST, rm }, + { "del", "Remove NAME from current inode directory", 2, 2, FL_CWR | FL_ST, rm }, + { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_CWR | FL_ST, ln }, + { "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_CWR, chinum }, { "chname", "Change dir entry number INDEX to NAME", 3, 3, FL_WR | FL_ST, chname }, - { "chtype", "Change type of current inode to TYPE", 2, 2, FL_WR, newtype }, + { "chtype", "Change type of current inode to TYPE", 2, 2, FL_CWR, newtype }, { "chmod", "Change mode of current inode to MODE", 2, 2, FL_WR, chmode }, - { "chlen", "Change length of current inode to LENGTH", 2, 2, FL_WR, chlen }, { "chown", "Change owner of current inode to OWNER", 2, 2, FL_WR, chowner }, { "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup }, - { "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_WR, chaflags }, + { "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_CWR, chaflags }, { "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen }, - { "chsize", "Change size of current inode to SIZE", 2, 2, FL_WR, chsize }, + { "chsize", "Change size of current inode to SIZE", 2, 2, FL_CWR, chsize }, { "btime", "Change btime of current inode to BTIME", 2, 2, FL_WR, chbtime }, { "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime }, { "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime }, { "atime", "Change atime of current inode to ATIME", 2, 2, FL_WR, chatime }, + { "chdb", "Change db pointer N of current inode to BLKNO", 3, 3, FL_CWR, chdb }, + { "quitclean", "Exit with filesystem marked clean", 1, 1, FL_RO, quitclean }, { "quit", "Exit", 1, 1, FL_RO, quit }, { "q", "Exit", 1, 1, FL_RO, quit }, { "exit", "Exit", 1, 1, FL_RO, quit }, @@ -278,7 +297,7 @@ cmdloop(void) known = 0; for (cmdp = cmds; cmdp->cmd; cmdp++) { if (!strcmp(cmdp->cmd, cmd_argv[0])) { - if ((cmdp->flags & FL_WR) == FL_WR && nflag) + if ((cmdp->flags & (FL_CWR | FL_WR)) != 0 && nflag) warnx("`%s' requires write access", cmd_argv[0]), rval = 1; else if (cmd_argc >= cmdp->minargc && @@ -292,6 +311,12 @@ cmdloop(void) } else rval = argcount(cmdp, cmd_argc, cmd_argv); known = 1; + if (rval == 0) { + if ((cmdp->flags & FL_WR) != 0) + fsnoncritmodified = 1; + if ((cmdp->flags & FL_CWR) != 0) + fscritmodified = 1; + } break; } } @@ -306,7 +331,7 @@ cmdloop(void) return 0; } if (rval) - warnx("rval was %d", rval); + warnx("command failed, return value was %d", rval); } el_end(elptr); history_end(hist); @@ -374,6 +399,16 @@ CMDFUNCSTART(quit) return -1; } +CMDFUNCSTART(quitclean) +{ + if (fscritmodified) { + printf("Warning: modified filesystem marked clean\n"); + fscritmodified = 0; + sblock.fs_clean = 1; + } + return -1; +} + CMDFUNCSTART(uplink) { if (!checkactive()) @@ -781,7 +816,7 @@ CMDFUNCSTART(rm) if (!checkactivedir()) return 1; - rval = changeino(curinum, argv[1], 0); + rval = changeino(curinum, argv[1], 0, 0); if (rval & ALTERED) { printf("Name `%s' removed\n", argv[1]); return 0; @@ -928,30 +963,8 @@ CMDFUNCSTART(newtype) return 0; } -CMDFUNCSTART(chlen) -{ - int rval = 1; - long len; - char *cp; - - if (!checkactive()) - return 1; - - len = strtol(argv[1], &cp, 0); - if (cp == argv[1] || *cp != '\0' || len < 0) { - warnx("bad length `%s'", argv[1]); - return 1; - } - - DIP_SET(curinode, di_size, len); - inodirty(&curip); - printactive(0); - return rval; -} - CMDFUNCSTART(chmode) { - int rval = 1; long modebits; char *cp; @@ -968,12 +981,11 @@ CMDFUNCSTART(chmode) DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits); inodirty(&curip); printactive(0); - return rval; + return 0; } CMDFUNCSTART(chaflags) { - int rval = 1; u_long flags; char *cp; @@ -993,12 +1005,11 @@ CMDFUNCSTART(chaflags) DIP_SET(curinode, di_flags, flags); inodirty(&curip); printactive(0); - return rval; + return 0; } CMDFUNCSTART(chgen) { - int rval = 1; long gen; char *cp; @@ -1011,19 +1022,19 @@ CMDFUNCSTART(chgen) return 1; } - if (gen > INT_MAX || gen < INT_MIN) { - warnx("gen set beyond 32-bit range of field (%lx)\n", gen); + if (gen > UINT_MAX) { + warnx("gen set beyond 32-bit range of field (0x%lx), max is 0x%x\n", + gen, UINT_MAX); return(1); } DIP_SET(curinode, di_gen, gen); inodirty(&curip); printactive(0); - return rval; + return 0; } CMDFUNCSTART(chsize) { - int rval = 1; off_t size; char *cp; @@ -1043,12 +1054,41 @@ CMDFUNCSTART(chsize) DIP_SET(curinode, di_size, size); inodirty(&curip); printactive(0); - return rval; + return 0; +} + +CMDFUNC(chdb) +{ + unsigned int idx; + daddr_t bno; + char *cp; + + if (!checkactive()) + return 1; + + idx = strtoull(argv[1], &cp, 0); + if (cp == argv[1] || *cp != '\0') { + warnx("bad pointer idx `%s'", argv[1]); + return 1; + } + bno = strtoll(argv[2], &cp, 0); + if (cp == argv[2] || *cp != '\0') { + warnx("bad block number `%s'", argv[2]); + return 1; + } + if (idx >= UFS_NDADDR) { + warnx("pointer index %d is out of range", idx); + return 1; + } + + DIP_SET(curinode, di_db[idx], bno); + inodirty(&curip); + printactive(0); + return 0; } CMDFUNCSTART(linkcount) { - int rval = 1; int lcnt; char *cp; @@ -1068,12 +1108,11 @@ CMDFUNCSTART(linkcount) DIP_SET(curinode, di_nlink, lcnt); inodirty(&curip); printactive(0); - return rval; + return 0; } CMDFUNCSTART(chowner) { - int rval = 1; unsigned long uid; char *cp; struct passwd *pwd; @@ -1095,12 +1134,11 @@ CMDFUNCSTART(chowner) DIP_SET(curinode, di_uid, uid); inodirty(&curip); printactive(0); - return rval; + return 0; } CMDFUNCSTART(chgroup) { - int rval = 1; unsigned long gid; char *cp; struct group *grp; @@ -1121,7 +1159,7 @@ CMDFUNCSTART(chgroup) DIP_SET(curinode, di_gid, gid); inodirty(&curip); printactive(0); - return rval; + return 0; } int |