112048Speter/* $NetBSD: fsdb.c,v 1.2 1995/10/08 23:18:10 thorpej Exp $ */ 212048Speter 312048Speter/* 412048Speter * Copyright (c) 1995 John T. Kohl 512048Speter * All rights reserved. 612048Speter * 712048Speter * Redistribution and use in source and binary forms, with or without 812048Speter * modification, are permitted provided that the following conditions 912048Speter * are met: 1012048Speter * 1. Redistributions of source code must retain the above copyright 1112048Speter * notice, this list of conditions and the following disclaimer. 1212048Speter * 2. Redistributions in binary form must reproduce the above copyright 1312048Speter * notice, this list of conditions and the following disclaimer in the 1412048Speter * documentation and/or other materials provided with the distribution. 1512048Speter * 3. The name of the author may not be used to endorse or promote products 1612048Speter * derived from this software without specific prior written permission. 1712048Speter * 1812048Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 1912048Speter * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 2012048Speter * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 2112048Speter * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 2212048Speter * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 2312048Speter * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 2412048Speter * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2512048Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 2612048Speter * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 2712048Speter * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 2812048Speter * POSSIBILITY OF SUCH DAMAGE. 2912048Speter */ 3012048Speter 3112048Speter#ifndef lint 3237001Scharnierstatic const char rcsid[] = 3350476Speter "$FreeBSD$"; 3412048Speter#endif /* not lint */ 3512048Speter 3612048Speter#include <sys/param.h> 3712048Speter#include <ctype.h> 3837001Scharnier#include <err.h> 3912048Speter#include <grp.h> 4012048Speter#include <histedit.h> 4112048Speter#include <pwd.h> 4212048Speter#include <string.h> 43217769Smckusick#include <time.h> 44122621Sjohan#include <timeconv.h> 4512048Speter 4612048Speter#include <ufs/ufs/dinode.h> 4712048Speter#include <ufs/ufs/dir.h> 4812048Speter#include <ufs/ffs/fs.h> 4912048Speter 5012048Speter#include "fsdb.h" 5112048Speter#include "fsck.h" 5212048Speter 5392881Simpstatic void usage(void) __dead2; 5492881Simpint cmdloop(void); 55159169Smaximstatic int compare_blk32(uint32_t *wantedblk, uint32_t curblk); 56159169Smaximstatic int compare_blk64(uint64_t *wantedblk, uint64_t curblk); 57159169Smaximstatic int founddatablk(uint64_t blk); 58159169Smaximstatic int find_blks32(uint32_t *buf, int size, uint32_t *blknum); 59159169Smaximstatic int find_blks64(uint64_t *buf, int size, uint64_t *blknum); 60159169Smaximstatic int find_indirblks32(uint32_t blk, int ind_level, uint32_t *blknum); 61159169Smaximstatic int find_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum); 6212048Speter 6326557Scharnierstatic void 6492881Simpusage(void) 6512048Speter{ 6626557Scharnier fprintf(stderr, "usage: fsdb [-d] [-f] [-r] fsname\n"); 6726557Scharnier exit(1); 6812048Speter} 6912048Speter 7089826Sjoergint returntosingle; 7189826Sjoergchar nflag; 7212048Speter 7312048Speter/* 7412048Speter * We suck in lots of fsck code, and just pick & choose the stuff we want. 7512048Speter * 76102231Strhodes * fsreadfd is set up to read from the file system, fswritefd to write to 77102231Strhodes * the file system. 7812048Speter */ 7946080Simpint 8092881Simpmain(int argc, char *argv[]) 8112048Speter{ 8212048Speter int ch, rval; 8312048Speter char *fsys = NULL; 8412048Speter 8526557Scharnier while (-1 != (ch = getopt(argc, argv, "fdr"))) { 8612048Speter switch (ch) { 8712048Speter case 'f': 8826557Scharnier /* The -f option is left for historical 8926557Scharnier * reasons and has no meaning. 9026557Scharnier */ 9112048Speter break; 9212048Speter case 'd': 9312048Speter debug++; 9412048Speter break; 9524956Sjoerg case 'r': 9624956Sjoerg nflag++; /* "no" in fsck, readonly for us */ 9724956Sjoerg break; 9812048Speter default: 9912048Speter usage(); 10012048Speter } 10112048Speter } 10218585Sguido argc -= optind; 10318585Sguido argv += optind; 10426557Scharnier if (argc != 1) 10526557Scharnier usage(); 10626557Scharnier else 10726557Scharnier fsys = argv[0]; 10818585Sguido 10975884Siedowse sblock_init(); 11012048Speter if (!setup(fsys)) 111102231Strhodes errx(1, "cannot set up file system `%s'", fsys); 112102231Strhodes printf("%s file system `%s'\nLast Mounted on %s\n", 11324956Sjoerg nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt); 11412048Speter rval = cmdloop(); 11524956Sjoerg if (!nflag) { 11624956Sjoerg sblock.fs_clean = 0; /* mark it dirty */ 11724956Sjoerg sbdirty(); 11824956Sjoerg ckfini(0); 11924956Sjoerg printf("*** FILE SYSTEM MARKED DIRTY\n"); 12024956Sjoerg printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); 12124956Sjoerg printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); 12224956Sjoerg } 12312048Speter exit(rval); 12412048Speter} 12512048Speter 12692881Simp#define CMDFUNC(func) int func(int argc, char *argv[]) 12792881Simp#define CMDFUNCSTART(func) int func(int argc, char *argv[]) 12812048Speter 12912048SpeterCMDFUNC(helpfn); 13012048SpeterCMDFUNC(focus); /* focus on inode */ 13112048SpeterCMDFUNC(active); /* print active inode */ 13289827SjoergCMDFUNC(blocks); /* print blocks for active inode */ 13312048SpeterCMDFUNC(focusname); /* focus by name */ 13412048SpeterCMDFUNC(zapi); /* clear inode */ 13512048SpeterCMDFUNC(uplink); /* incr link */ 13612048SpeterCMDFUNC(downlink); /* decr link */ 13712048SpeterCMDFUNC(linkcount); /* set link count */ 13812048SpeterCMDFUNC(quit); /* quit */ 139159169SmaximCMDFUNC(findblk); /* find block */ 14012048SpeterCMDFUNC(ls); /* list directory */ 14112048SpeterCMDFUNC(rm); /* remove name */ 14212048SpeterCMDFUNC(ln); /* add name */ 14312048SpeterCMDFUNC(newtype); /* change type */ 14412048SpeterCMDFUNC(chmode); /* change mode */ 14518498SguidoCMDFUNC(chlen); /* change length */ 14612048SpeterCMDFUNC(chaflags); /* change flags */ 14712048SpeterCMDFUNC(chgen); /* change generation */ 14812048SpeterCMDFUNC(chowner); /* change owner */ 14912048SpeterCMDFUNC(chgroup); /* Change group */ 15012048SpeterCMDFUNC(back); /* pop back to last ino */ 151161558SceriCMDFUNC(chbtime); /* Change btime */ 15212048SpeterCMDFUNC(chmtime); /* Change mtime */ 15312048SpeterCMDFUNC(chctime); /* Change ctime */ 15412048SpeterCMDFUNC(chatime); /* Change atime */ 15512048SpeterCMDFUNC(chinum); /* Change inode # of dirent */ 15612048SpeterCMDFUNC(chname); /* Change dirname of dirent */ 15712048Speter 15812048Speterstruct cmdtable cmds[] = { 15924956Sjoerg { "help", "Print out help", 1, 1, FL_RO, helpfn }, 16024956Sjoerg { "?", "Print out help", 1, 1, FL_RO, helpfn }, 16124956Sjoerg { "inode", "Set active inode to INUM", 2, 2, FL_RO, focus }, 16224956Sjoerg { "clri", "Clear inode INUM", 2, 2, FL_WR, zapi }, 163157950Smaxim { "lookup", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname }, 164157950Smaxim { "cd", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname }, 16524956Sjoerg { "back", "Go to previous active inode", 1, 1, FL_RO, back }, 16624956Sjoerg { "active", "Print active inode", 1, 1, FL_RO, active }, 16724956Sjoerg { "print", "Print active inode", 1, 1, FL_RO, active }, 16889827Sjoerg { "blocks", "Print block numbers of active inode", 1, 1, FL_RO, blocks }, 16924956Sjoerg { "uplink", "Increment link count", 1, 1, FL_WR, uplink }, 17024956Sjoerg { "downlink", "Decrement link count", 1, 1, FL_WR, downlink }, 17124956Sjoerg { "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount }, 172159169Smaxim { "findblk", "Find inode owning disk block(s)", 2, 33, FL_RO, findblk}, 17324956Sjoerg { "ls", "List current inode as directory", 1, 1, FL_RO, ls }, 174157950Smaxim { "rm", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm }, 175157950Smaxim { "del", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm }, 176157950Smaxim { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_WR | FL_ST, ln }, 17724956Sjoerg { "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_WR, chinum }, 178157950Smaxim { "chname", "Change dir entry number INDEX to NAME", 3, 3, FL_WR | FL_ST, chname }, 17924956Sjoerg { "chtype", "Change type of current inode to TYPE", 2, 2, FL_WR, newtype }, 18024956Sjoerg { "chmod", "Change mode of current inode to MODE", 2, 2, FL_WR, chmode }, 18124956Sjoerg { "chlen", "Change length of current inode to LENGTH", 2, 2, FL_WR, chlen }, 18224956Sjoerg { "chown", "Change owner of current inode to OWNER", 2, 2, FL_WR, chowner }, 18324956Sjoerg { "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup }, 18424956Sjoerg { "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_WR, chaflags }, 18524956Sjoerg { "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen }, 186161558Sceri { "btime", "Change btime of current inode to BTIME", 2, 2, FL_WR, chbtime }, 18724956Sjoerg { "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime }, 18824956Sjoerg { "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime }, 18924956Sjoerg { "atime", "Change atime of current inode to ATIME", 2, 2, FL_WR, chatime }, 19024956Sjoerg { "quit", "Exit", 1, 1, FL_RO, quit }, 19124956Sjoerg { "q", "Exit", 1, 1, FL_RO, quit }, 19224956Sjoerg { "exit", "Exit", 1, 1, FL_RO, quit }, 193136322Sle { NULL, 0, 0, 0, 0, NULL }, 19412048Speter}; 19512048Speter 19612048Speterint 19792881Simphelpfn(int argc, char *argv[]) 19812048Speter{ 19992806Sobrien struct cmdtable *cmdtp; 20012048Speter 20112048Speter printf("Commands are:\n%-10s %5s %5s %s\n", 202157950Smaxim "command", "min args", "max args", "what"); 20312048Speter 20412048Speter for (cmdtp = cmds; cmdtp->cmd; cmdtp++) 20512048Speter printf("%-10s %5u %5u %s\n", 206157950Smaxim cmdtp->cmd, cmdtp->minargc-1, cmdtp->maxargc-1, cmdtp->helptxt); 20712048Speter return 0; 20812048Speter} 20912048Speter 21012048Speterchar * 21192881Simpprompt(EditLine *el) 21212048Speter{ 21312048Speter static char pstring[64]; 21412048Speter snprintf(pstring, sizeof(pstring), "fsdb (inum: %d)> ", curinum); 21512048Speter return pstring; 21612048Speter} 21712048Speter 21812048Speter 21912048Speterint 22092881Simpcmdloop(void) 22112048Speter{ 22212048Speter char *line; 22312048Speter const char *elline; 22412048Speter int cmd_argc, rval = 0, known; 22512048Speter#define scratch known 22612048Speter char **cmd_argv; 22712048Speter struct cmdtable *cmdp; 22812048Speter History *hist; 22912048Speter EditLine *elptr; 23084261Sobrien HistEvent he; 23112048Speter 23212048Speter curinode = ginode(ROOTINO); 23312048Speter curinum = ROOTINO; 23489827Sjoerg printactive(0); 23512048Speter 23612048Speter hist = history_init(); 237151471Sstefanf history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */ 23812048Speter 23984261Sobrien elptr = el_init("fsdb", stdin, stdout, stderr); 24012048Speter el_set(elptr, EL_EDITOR, "emacs"); 24112048Speter el_set(elptr, EL_PROMPT, prompt); 24212048Speter el_set(elptr, EL_HIST, history, hist); 24312048Speter el_source(elptr, NULL); 24412048Speter 24512048Speter while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) { 24612048Speter if (debug) 24737001Scharnier printf("command `%s'\n", elline); 24812048Speter 24984261Sobrien history(hist, &he, H_ENTER, elline); 25012048Speter 25112048Speter line = strdup(elline); 25212048Speter cmd_argv = crack(line, &cmd_argc); 25312048Speter /* 25412048Speter * el_parse returns -1 to signal that it's not been handled 25512048Speter * internally. 25612048Speter */ 257148833Sstefanf if (el_parse(elptr, cmd_argc, (const char **)cmd_argv) != -1) 25812048Speter continue; 25912048Speter if (cmd_argc) { 26012048Speter known = 0; 26112048Speter for (cmdp = cmds; cmdp->cmd; cmdp++) { 26212048Speter if (!strcmp(cmdp->cmd, cmd_argv[0])) { 26324956Sjoerg if ((cmdp->flags & FL_WR) == FL_WR && nflag) 26424956Sjoerg warnx("`%s' requires write access", cmd_argv[0]), 26524956Sjoerg rval = 1; 26624956Sjoerg else if (cmd_argc >= cmdp->minargc && 26712048Speter cmd_argc <= cmdp->maxargc) 26812048Speter rval = (*cmdp->handler)(cmd_argc, cmd_argv); 269157950Smaxim else if (cmd_argc >= cmdp->minargc && 270157950Smaxim (cmdp->flags & FL_ST) == FL_ST) { 27189791Sgreen strcpy(line, elline); 27289791Sgreen cmd_argv = recrack(line, &cmd_argc, cmdp->maxargc); 27389791Sgreen rval = (*cmdp->handler)(cmd_argc, cmd_argv); 27489791Sgreen } else 27512048Speter rval = argcount(cmdp, cmd_argc, cmd_argv); 27612048Speter known = 1; 27712048Speter break; 27812048Speter } 27912048Speter } 28012048Speter if (!known) 28112048Speter warnx("unknown command `%s'", cmd_argv[0]), rval = 1; 28212048Speter } else 28312048Speter rval = 0; 28412048Speter free(line); 28512048Speter if (rval < 0) 28689810Sjoerg /* user typed "quit" */ 28789810Sjoerg return 0; 28812048Speter if (rval) 28912048Speter warnx("rval was %d", rval); 29012048Speter } 29112048Speter el_end(elptr); 29212048Speter history_end(hist); 29312048Speter return rval; 29412048Speter} 29512048Speter 29698542Smckusickunion dinode *curinode; 29712048Speterino_t curinum, ocurrent; 29812048Speter 29912048Speter#define GETINUM(ac,inum) inum = strtoul(argv[ac], &cp, 0); \ 30012048Speter if (inum < ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \ 30112048Speter printf("inode %d out of range; range is [%d,%d]\n", \ 30212048Speter inum, ROOTINO, maxino); \ 30312048Speter return 1; \ 30412048Speter } 30512048Speter 30612048Speter/* 30712048Speter * Focus on given inode number 30812048Speter */ 30912048SpeterCMDFUNCSTART(focus) 31012048Speter{ 31112048Speter ino_t inum; 31212048Speter char *cp; 31312048Speter 31412048Speter GETINUM(1,inum); 31512048Speter curinode = ginode(inum); 31612048Speter ocurrent = curinum; 31712048Speter curinum = inum; 31889827Sjoerg printactive(0); 31912048Speter return 0; 32012048Speter} 32112048Speter 32212048SpeterCMDFUNCSTART(back) 32312048Speter{ 32412048Speter curinum = ocurrent; 32512048Speter curinode = ginode(curinum); 32689827Sjoerg printactive(0); 32712048Speter return 0; 32812048Speter} 32912048Speter 33012048SpeterCMDFUNCSTART(zapi) 33112048Speter{ 33212048Speter ino_t inum; 33398542Smckusick union dinode *dp; 33412048Speter char *cp; 33512048Speter 33612048Speter GETINUM(1,inum); 33712048Speter dp = ginode(inum); 33812048Speter clearinode(dp); 33912048Speter inodirty(); 34012048Speter if (curinode) /* re-set after potential change */ 34112048Speter curinode = ginode(curinum); 34212048Speter return 0; 34312048Speter} 34412048Speter 34512048SpeterCMDFUNCSTART(active) 34612048Speter{ 34789827Sjoerg printactive(0); 34812048Speter return 0; 34912048Speter} 35012048Speter 35189827SjoergCMDFUNCSTART(blocks) 35289827Sjoerg{ 35389827Sjoerg printactive(1); 35489827Sjoerg return 0; 35589827Sjoerg} 35612048Speter 35712048SpeterCMDFUNCSTART(quit) 35812048Speter{ 35912048Speter return -1; 36012048Speter} 36112048Speter 36212048SpeterCMDFUNCSTART(uplink) 36312048Speter{ 36412048Speter if (!checkactive()) 36512048Speter return 1; 366136322Sle DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1); 36798542Smckusick printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink)); 36812048Speter inodirty(); 36912048Speter return 0; 37012048Speter} 37112048Speter 37212048SpeterCMDFUNCSTART(downlink) 37312048Speter{ 37412048Speter if (!checkactive()) 37512048Speter return 1; 376136322Sle DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1); 37798542Smckusick printf("inode %d link count now %d\n", curinum, DIP(curinode, di_nlink)); 37812048Speter inodirty(); 37912048Speter return 0; 38012048Speter} 38112048Speter 38212048Speterconst char *typename[] = { 38312048Speter "unknown", 38412048Speter "fifo", 38512048Speter "char special", 38612048Speter "unregistered #3", 38712048Speter "directory", 38812048Speter "unregistered #5", 38912048Speter "blk special", 39012048Speter "unregistered #7", 39112048Speter "regular", 39212048Speter "unregistered #9", 39312048Speter "symlink", 39412048Speter "unregistered #11", 39512048Speter "socket", 39612048Speter "unregistered #13", 39712048Speter "whiteout", 39812048Speter}; 399207141Sjeff 400207141Sjeffint diroff; 40112048Speterint slot; 40212048Speter 40312048Speterint 40492881Simpscannames(struct inodesc *idesc) 40512048Speter{ 40692806Sobrien struct direct *dirp = idesc->id_dirp; 40712048Speter 408207141Sjeff printf("slot %d off %d ino %d reclen %d: %s, `%.*s'\n", 409207141Sjeff slot++, diroff, dirp->d_ino, dirp->d_reclen, 410207141Sjeff typename[dirp->d_type], dirp->d_namlen, dirp->d_name); 411207141Sjeff diroff += dirp->d_reclen; 41212048Speter return (KEEPON); 41312048Speter} 41412048Speter 41512048SpeterCMDFUNCSTART(ls) 41612048Speter{ 41712048Speter struct inodesc idesc; 41812048Speter checkactivedir(); /* let it go on anyway */ 41912048Speter 42012048Speter slot = 0; 421207141Sjeff diroff = 0; 42212048Speter idesc.id_number = curinum; 42312048Speter idesc.id_func = scannames; 42412048Speter idesc.id_type = DATA; 42512048Speter idesc.id_fix = IGNORE; 42612048Speter ckinode(curinode, &idesc); 42712048Speter curinode = ginode(curinum); 42812048Speter 42912048Speter return 0; 43012048Speter} 43112048Speter 432159169Smaximstatic int findblk_numtofind; 433159169Smaximstatic int wantedblksize; 434159169Smaxim 435159169SmaximCMDFUNCSTART(findblk) 436159169Smaxim{ 437159169Smaxim ino_t inum, inosused; 438159169Smaxim uint32_t *wantedblk32; 439159169Smaxim uint64_t *wantedblk64; 440249788Smckusick struct bufarea *cgbp; 441249788Smckusick struct cg *cgp; 442159169Smaxim int c, i, is_ufs2; 443159169Smaxim 444159169Smaxim wantedblksize = (argc - 1); 445159169Smaxim is_ufs2 = sblock.fs_magic == FS_UFS2_MAGIC; 446159169Smaxim ocurrent = curinum; 447159169Smaxim 448159169Smaxim if (is_ufs2) { 449159169Smaxim wantedblk64 = calloc(wantedblksize, sizeof(uint64_t)); 450159169Smaxim if (wantedblk64 == NULL) 451159169Smaxim err(1, "malloc"); 452159169Smaxim for (i = 1; i < argc; i++) 453159169Smaxim wantedblk64[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0)); 454159169Smaxim } else { 455159169Smaxim wantedblk32 = calloc(wantedblksize, sizeof(uint32_t)); 456159169Smaxim if (wantedblk32 == NULL) 457159169Smaxim err(1, "malloc"); 458159169Smaxim for (i = 1; i < argc; i++) 459159169Smaxim wantedblk32[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0)); 460159169Smaxim } 461159169Smaxim findblk_numtofind = wantedblksize; 462159169Smaxim /* 463159169Smaxim * sblock.fs_ncg holds a number of cylinder groups. 464159169Smaxim * Iterate over all cylinder groups. 465159169Smaxim */ 466159169Smaxim for (c = 0; c < sblock.fs_ncg; c++) { 467159169Smaxim /* 468159169Smaxim * sblock.fs_ipg holds a number of inodes per cylinder group. 469159169Smaxim * Calculate a highest inode number for a given cylinder group. 470159169Smaxim */ 471159169Smaxim inum = c * sblock.fs_ipg; 472159169Smaxim /* Read cylinder group. */ 473249788Smckusick cgbp = cgget(c); 474249788Smckusick cgp = cgbp->b_un.b_cg; 475159169Smaxim /* 476159169Smaxim * Get a highest used inode number for a given cylinder group. 477159169Smaxim * For UFS1 all inodes initialized at the newfs stage. 478159169Smaxim */ 479159169Smaxim if (is_ufs2) 480159169Smaxim inosused = cgp->cg_initediblk; 481159169Smaxim else 482159169Smaxim inosused = sblock.fs_ipg; 483159169Smaxim 484159169Smaxim for (; inosused > 0; inum++, inosused--) { 485159169Smaxim /* Skip magic inodes: 0, WINO, ROOTINO. */ 486159169Smaxim if (inum < ROOTINO) 487159169Smaxim continue; 488159169Smaxim /* 489159169Smaxim * Check if the block we are looking for is just an inode block. 490159169Smaxim * 491159169Smaxim * ino_to_fsba() - get block containing inode from its number. 492159169Smaxim * INOPB() - get a number of inodes in one disk block. 493159169Smaxim */ 494159169Smaxim if (is_ufs2 ? 495159169Smaxim compare_blk64(wantedblk64, ino_to_fsba(&sblock, inum)) : 496159169Smaxim compare_blk32(wantedblk32, ino_to_fsba(&sblock, inum))) { 497159169Smaxim printf("block %llu: inode block (%d-%d)\n", 498159169Smaxim (unsigned long long)fsbtodb(&sblock, 499159169Smaxim ino_to_fsba(&sblock, inum)), 500159169Smaxim (inum / INOPB(&sblock)) * INOPB(&sblock), 501159169Smaxim (inum / INOPB(&sblock) + 1) * INOPB(&sblock)); 502159169Smaxim findblk_numtofind--; 503159169Smaxim if (findblk_numtofind == 0) 504159169Smaxim goto end; 505159169Smaxim } 506159169Smaxim /* Get on-disk inode aka dinode. */ 507159169Smaxim curinum = inum; 508159169Smaxim curinode = ginode(inum); 509159169Smaxim /* Find IFLNK dinode with allocated data blocks. */ 510159169Smaxim switch (DIP(curinode, di_mode) & IFMT) { 511159169Smaxim case IFDIR: 512159169Smaxim case IFREG: 513159169Smaxim if (DIP(curinode, di_blocks) == 0) 514159169Smaxim continue; 515159169Smaxim break; 516159169Smaxim case IFLNK: 517159169Smaxim { 518159169Smaxim uint64_t size = DIP(curinode, di_size); 519159169Smaxim if (size > 0 && size < sblock.fs_maxsymlinklen && 520159169Smaxim DIP(curinode, di_blocks) == 0) 521159169Smaxim continue; 522159169Smaxim else 523159169Smaxim break; 524159169Smaxim } 525159169Smaxim default: 526159169Smaxim continue; 527159169Smaxim } 528159169Smaxim /* Look through direct data blocks. */ 529159169Smaxim if (is_ufs2 ? 530159169Smaxim find_blks64(curinode->dp2.di_db, NDADDR, wantedblk64) : 531159169Smaxim find_blks32(curinode->dp1.di_db, NDADDR, wantedblk32)) 532159169Smaxim goto end; 533159169Smaxim for (i = 0; i < NIADDR; i++) { 534159169Smaxim /* 535159169Smaxim * Does the block we are looking for belongs to the 536159169Smaxim * indirect blocks? 537159169Smaxim */ 538159169Smaxim if (is_ufs2 ? 539159169Smaxim compare_blk64(wantedblk64, curinode->dp2.di_ib[i]) : 540159169Smaxim compare_blk32(wantedblk32, curinode->dp1.di_ib[i])) 541159169Smaxim if (founddatablk(is_ufs2 ? curinode->dp2.di_ib[i] : 542159169Smaxim curinode->dp1.di_ib[i])) 543159169Smaxim goto end; 544159169Smaxim /* 545159169Smaxim * Search through indirect, double and triple indirect 546159169Smaxim * data blocks. 547159169Smaxim */ 548159169Smaxim if (is_ufs2 ? (curinode->dp2.di_ib[i] != 0) : 549159169Smaxim (curinode->dp1.di_ib[i] != 0)) 550159169Smaxim if (is_ufs2 ? 551159169Smaxim find_indirblks64(curinode->dp2.di_ib[i], i, 552159169Smaxim wantedblk64) : 553159169Smaxim find_indirblks32(curinode->dp1.di_ib[i], i, 554159169Smaxim wantedblk32)) 555159169Smaxim goto end; 556159169Smaxim } 557159169Smaxim } 558159169Smaxim } 559159169Smaximend: 560159169Smaxim curinum = ocurrent; 561159169Smaxim curinode = ginode(curinum); 562159169Smaxim return 0; 563159169Smaxim} 564159169Smaxim 565159169Smaximstatic int 566159169Smaximcompare_blk32(uint32_t *wantedblk, uint32_t curblk) 567159169Smaxim{ 568159169Smaxim int i; 569159169Smaxim 570159169Smaxim for (i = 0; i < wantedblksize; i++) { 571159169Smaxim if (wantedblk[i] != 0 && wantedblk[i] == curblk) { 572159169Smaxim wantedblk[i] = 0; 573159169Smaxim return 1; 574159169Smaxim } 575159169Smaxim } 576159169Smaxim return 0; 577159169Smaxim} 578159169Smaxim 579159169Smaximstatic int 580159169Smaximcompare_blk64(uint64_t *wantedblk, uint64_t curblk) 581159169Smaxim{ 582159169Smaxim int i; 583159169Smaxim 584159169Smaxim for (i = 0; i < wantedblksize; i++) { 585159169Smaxim if (wantedblk[i] != 0 && wantedblk[i] == curblk) { 586159169Smaxim wantedblk[i] = 0; 587159169Smaxim return 1; 588159169Smaxim } 589159169Smaxim } 590159169Smaxim return 0; 591159169Smaxim} 592159169Smaxim 593159169Smaximstatic int 594159169Smaximfounddatablk(uint64_t blk) 595159169Smaxim{ 596159169Smaxim 597159169Smaxim printf("%llu: data block of inode %d\n", 598159169Smaxim (unsigned long long)fsbtodb(&sblock, blk), curinum); 599159169Smaxim findblk_numtofind--; 600159169Smaxim if (findblk_numtofind == 0) 601159169Smaxim return 1; 602159169Smaxim return 0; 603159169Smaxim} 604159169Smaxim 605159169Smaximstatic int 606159169Smaximfind_blks32(uint32_t *buf, int size, uint32_t *wantedblk) 607159169Smaxim{ 608159169Smaxim int blk; 609159169Smaxim for (blk = 0; blk < size; blk++) { 610159169Smaxim if (buf[blk] == 0) 611159169Smaxim continue; 612159169Smaxim if (compare_blk32(wantedblk, buf[blk])) { 613159169Smaxim if (founddatablk(buf[blk])) 614159169Smaxim return 1; 615159169Smaxim } 616159169Smaxim } 617159169Smaxim return 0; 618159169Smaxim} 619159169Smaxim 620159169Smaximstatic int 621159169Smaximfind_indirblks32(uint32_t blk, int ind_level, uint32_t *wantedblk) 622159169Smaxim{ 623159169Smaxim#define MAXNINDIR (MAXBSIZE / sizeof(uint32_t)) 624159169Smaxim uint32_t idblk[MAXNINDIR]; 625159169Smaxim int i; 626159169Smaxim 627163846Spjd blread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize); 628159169Smaxim if (ind_level <= 0) { 629159169Smaxim if (find_blks32(idblk, sblock.fs_bsize / sizeof(uint32_t), wantedblk)) 630159169Smaxim return 1; 631159169Smaxim } else { 632159169Smaxim ind_level--; 633159169Smaxim for (i = 0; i < sblock.fs_bsize / sizeof(uint32_t); i++) { 634159169Smaxim if (compare_blk32(wantedblk, idblk[i])) { 635159169Smaxim if (founddatablk(idblk[i])) 636159169Smaxim return 1; 637159169Smaxim } 638159169Smaxim if (idblk[i] != 0) 639159169Smaxim if (find_indirblks32(idblk[i], ind_level, wantedblk)) 640159169Smaxim return 1; 641159169Smaxim } 642159169Smaxim } 643159169Smaxim#undef MAXNINDIR 644159169Smaxim return 0; 645159169Smaxim} 646159169Smaxim 647159169Smaximstatic int 648159169Smaximfind_blks64(uint64_t *buf, int size, uint64_t *wantedblk) 649159169Smaxim{ 650159169Smaxim int blk; 651159169Smaxim for (blk = 0; blk < size; blk++) { 652159169Smaxim if (buf[blk] == 0) 653159169Smaxim continue; 654159169Smaxim if (compare_blk64(wantedblk, buf[blk])) { 655159169Smaxim if (founddatablk(buf[blk])) 656159169Smaxim return 1; 657159169Smaxim } 658159169Smaxim } 659159169Smaxim return 0; 660159169Smaxim} 661159169Smaxim 662159169Smaximstatic int 663159169Smaximfind_indirblks64(uint64_t blk, int ind_level, uint64_t *wantedblk) 664159169Smaxim{ 665159169Smaxim#define MAXNINDIR (MAXBSIZE / sizeof(uint64_t)) 666159169Smaxim uint64_t idblk[MAXNINDIR]; 667159169Smaxim int i; 668159169Smaxim 669163846Spjd blread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize); 670159169Smaxim if (ind_level <= 0) { 671159169Smaxim if (find_blks64(idblk, sblock.fs_bsize / sizeof(uint64_t), wantedblk)) 672159169Smaxim return 1; 673159169Smaxim } else { 674159169Smaxim ind_level--; 675159169Smaxim for (i = 0; i < sblock.fs_bsize / sizeof(uint64_t); i++) { 676159169Smaxim if (compare_blk64(wantedblk, idblk[i])) { 677159169Smaxim if (founddatablk(idblk[i])) 678159169Smaxim return 1; 679159169Smaxim } 680159169Smaxim if (idblk[i] != 0) 681159169Smaxim if (find_indirblks64(idblk[i], ind_level, wantedblk)) 682159169Smaxim return 1; 683159169Smaxim } 684159169Smaxim } 685159169Smaxim#undef MAXNINDIR 686159169Smaxim return 0; 687159169Smaxim} 688159169Smaxim 68992881Simpint findino(struct inodesc *idesc); /* from fsck */ 69092881Simpstatic int dolookup(char *name); 69112048Speter 69212048Speterstatic int 69392881Simpdolookup(char *name) 69412048Speter{ 69512048Speter struct inodesc idesc; 69612048Speter 69712048Speter if (!checkactivedir()) 69812048Speter return 0; 69912048Speter idesc.id_number = curinum; 70012048Speter idesc.id_func = findino; 70112048Speter idesc.id_name = name; 70212048Speter idesc.id_type = DATA; 70312048Speter idesc.id_fix = IGNORE; 70412048Speter if (ckinode(curinode, &idesc) & FOUND) { 70512048Speter curinum = idesc.id_parent; 70612048Speter curinode = ginode(curinum); 70789827Sjoerg printactive(0); 70812048Speter return 1; 70912048Speter } else { 71012048Speter warnx("name `%s' not found in current inode directory", name); 71112048Speter return 0; 71212048Speter } 71312048Speter} 71412048Speter 71512048SpeterCMDFUNCSTART(focusname) 71612048Speter{ 71712048Speter char *p, *val; 71812048Speter 71912048Speter if (!checkactive()) 72012048Speter return 1; 72112048Speter 72212048Speter ocurrent = curinum; 72312048Speter 72412048Speter if (argv[1][0] == '/') { 72512048Speter curinum = ROOTINO; 72612048Speter curinode = ginode(ROOTINO); 72712048Speter } else { 72812048Speter if (!checkactivedir()) 72912048Speter return 1; 73012048Speter } 73112048Speter for (p = argv[1]; p != NULL;) { 73212048Speter while ((val = strsep(&p, "/")) != NULL && *val == '\0'); 73312048Speter if (val) { 73412048Speter printf("component `%s': ", val); 73512048Speter fflush(stdout); 73612048Speter if (!dolookup(val)) { 73712048Speter curinode = ginode(curinum); 73812048Speter return(1); 73912048Speter } 74012048Speter } 74112048Speter } 74212048Speter return 0; 74312048Speter} 74412048Speter 74512048SpeterCMDFUNCSTART(ln) 74612048Speter{ 74712048Speter ino_t inum; 74812048Speter int rval; 74912048Speter char *cp; 75012048Speter 75112048Speter GETINUM(1,inum); 75212048Speter 75312048Speter if (!checkactivedir()) 75412048Speter return 1; 75512048Speter rval = makeentry(curinum, inum, argv[2]); 75612048Speter if (rval) 75712048Speter printf("Ino %d entered as `%s'\n", inum, argv[2]); 75812048Speter else 75912048Speter printf("could not enter name? weird.\n"); 76012048Speter curinode = ginode(curinum); 76112048Speter return rval; 76212048Speter} 76312048Speter 76412048SpeterCMDFUNCSTART(rm) 76512048Speter{ 76612048Speter int rval; 76712048Speter 76812048Speter if (!checkactivedir()) 76912048Speter return 1; 77012048Speter rval = changeino(curinum, argv[1], 0); 77112048Speter if (rval & ALTERED) { 77212048Speter printf("Name `%s' removed\n", argv[1]); 77312048Speter return 0; 77412048Speter } else { 77589791Sgreen printf("could not remove name ('%s')? weird.\n", argv[1]); 77612048Speter return 1; 77712048Speter } 77812048Speter} 77912048Speter 78012048Speterlong slotcount, desired; 78112048Speter 78212048Speterint 78392881Simpchinumfunc(struct inodesc *idesc) 78412048Speter{ 78592806Sobrien struct direct *dirp = idesc->id_dirp; 78612048Speter 78712048Speter if (slotcount++ == desired) { 78812048Speter dirp->d_ino = idesc->id_parent; 78912048Speter return STOP|ALTERED|FOUND; 79012048Speter } 79112048Speter return KEEPON; 79212048Speter} 79312048Speter 79412048SpeterCMDFUNCSTART(chinum) 79512048Speter{ 79612048Speter char *cp; 79712048Speter ino_t inum; 79812048Speter struct inodesc idesc; 79912048Speter 80012048Speter slotcount = 0; 80112048Speter if (!checkactivedir()) 80212048Speter return 1; 80312048Speter GETINUM(2,inum); 80412048Speter 80512048Speter desired = strtol(argv[1], &cp, 0); 80612048Speter if (cp == argv[1] || *cp != '\0' || desired < 0) { 80712048Speter printf("invalid slot number `%s'\n", argv[1]); 80812048Speter return 1; 80912048Speter } 81012048Speter 81112048Speter idesc.id_number = curinum; 81212048Speter idesc.id_func = chinumfunc; 81312048Speter idesc.id_fix = IGNORE; 81412048Speter idesc.id_type = DATA; 81512048Speter idesc.id_parent = inum; /* XXX convenient hiding place */ 81612048Speter 81712048Speter if (ckinode(curinode, &idesc) & FOUND) 81812048Speter return 0; 81912048Speter else { 82012048Speter warnx("no %sth slot in current directory", argv[1]); 82112048Speter return 1; 82212048Speter } 82312048Speter} 82412048Speter 82512048Speterint 82692881Simpchnamefunc(struct inodesc *idesc) 82712048Speter{ 82892806Sobrien struct direct *dirp = idesc->id_dirp; 82912048Speter struct direct testdir; 83012048Speter 83112048Speter if (slotcount++ == desired) { 83212048Speter /* will name fit? */ 83312048Speter testdir.d_namlen = strlen(idesc->id_name); 83412048Speter if (DIRSIZ(NEWDIRFMT, &testdir) <= dirp->d_reclen) { 83512048Speter dirp->d_namlen = testdir.d_namlen; 83612048Speter strcpy(dirp->d_name, idesc->id_name); 83712048Speter return STOP|ALTERED|FOUND; 83812048Speter } else 83912048Speter return STOP|FOUND; /* won't fit, so give up */ 84012048Speter } 84112048Speter return KEEPON; 84212048Speter} 84312048Speter 84412048SpeterCMDFUNCSTART(chname) 84512048Speter{ 84612048Speter int rval; 84712048Speter char *cp; 84812048Speter struct inodesc idesc; 84912048Speter 85012048Speter slotcount = 0; 85112048Speter if (!checkactivedir()) 85212048Speter return 1; 85312048Speter 85412048Speter desired = strtoul(argv[1], &cp, 0); 85512048Speter if (cp == argv[1] || *cp != '\0') { 85612048Speter printf("invalid slot number `%s'\n", argv[1]); 85712048Speter return 1; 85812048Speter } 85912048Speter 86012048Speter idesc.id_number = curinum; 86112048Speter idesc.id_func = chnamefunc; 86212048Speter idesc.id_fix = IGNORE; 86312048Speter idesc.id_type = DATA; 86412048Speter idesc.id_name = argv[2]; 86512048Speter 86612048Speter rval = ckinode(curinode, &idesc); 86712048Speter if ((rval & (FOUND|ALTERED)) == (FOUND|ALTERED)) 86812048Speter return 0; 86912048Speter else if (rval & FOUND) { 87012048Speter warnx("new name `%s' does not fit in slot %s\n", argv[2], argv[1]); 87112048Speter return 1; 87212048Speter } else { 87312048Speter warnx("no %sth slot in current directory", argv[1]); 87412048Speter return 1; 87512048Speter } 87612048Speter} 87712048Speter 87812048Speterstruct typemap { 87912048Speter const char *typename; 88012048Speter int typebits; 88112048Speter} typenamemap[] = { 88212048Speter {"file", IFREG}, 88312048Speter {"dir", IFDIR}, 88412048Speter {"socket", IFSOCK}, 88512048Speter {"fifo", IFIFO}, 88612048Speter}; 88712048Speter 88812048SpeterCMDFUNCSTART(newtype) 88912048Speter{ 89012048Speter int type; 89112048Speter struct typemap *tp; 89212048Speter 89312048Speter if (!checkactive()) 89412048Speter return 1; 89598542Smckusick type = DIP(curinode, di_mode) & IFMT; 89612048Speter for (tp = typenamemap; 89741023Struckman tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]; 89812048Speter tp++) { 89912048Speter if (!strcmp(argv[1], tp->typename)) { 90012048Speter printf("setting type to %s\n", tp->typename); 90112048Speter type = tp->typebits; 90212048Speter break; 90312048Speter } 90412048Speter } 90541023Struckman if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) { 90612048Speter warnx("type `%s' not known", argv[1]); 90712048Speter warnx("try one of `file', `dir', `socket', `fifo'"); 90812048Speter return 1; 90912048Speter } 910136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT); 911136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type); 91212048Speter inodirty(); 91389827Sjoerg printactive(0); 91412048Speter return 0; 91512048Speter} 91612048Speter 91718498SguidoCMDFUNCSTART(chlen) 91818498Sguido{ 91918498Sguido int rval = 1; 92018498Sguido long len; 92118498Sguido char *cp; 92218498Sguido 92318498Sguido if (!checkactive()) 92418498Sguido return 1; 92518498Sguido 92618498Sguido len = strtol(argv[1], &cp, 0); 92718498Sguido if (cp == argv[1] || *cp != '\0' || len < 0) { 92818498Sguido warnx("bad length `%s'", argv[1]); 92918498Sguido return 1; 93018498Sguido } 93118498Sguido 932136322Sle DIP_SET(curinode, di_size, len); 93318498Sguido inodirty(); 93489827Sjoerg printactive(0); 93518498Sguido return rval; 93618498Sguido} 93718498Sguido 93812048SpeterCMDFUNCSTART(chmode) 93912048Speter{ 94012048Speter int rval = 1; 94112048Speter long modebits; 94212048Speter char *cp; 94312048Speter 94412048Speter if (!checkactive()) 94512048Speter return 1; 94612048Speter 94712048Speter modebits = strtol(argv[1], &cp, 8); 94886258Siedowse if (cp == argv[1] || *cp != '\0' || (modebits & ~07777)) { 94912048Speter warnx("bad modebits `%s'", argv[1]); 95012048Speter return 1; 95112048Speter } 95212048Speter 953136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777); 954136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits); 95512048Speter inodirty(); 95689827Sjoerg printactive(0); 95712048Speter return rval; 95812048Speter} 95912048Speter 96012048SpeterCMDFUNCSTART(chaflags) 96112048Speter{ 96212048Speter int rval = 1; 96312048Speter u_long flags; 96412048Speter char *cp; 96512048Speter 96612048Speter if (!checkactive()) 96712048Speter return 1; 96812048Speter 96912048Speter flags = strtoul(argv[1], &cp, 0); 97012048Speter if (cp == argv[1] || *cp != '\0' ) { 97112048Speter warnx("bad flags `%s'", argv[1]); 97212048Speter return 1; 97312048Speter } 97412048Speter 97512048Speter if (flags > UINT_MAX) { 97612048Speter warnx("flags set beyond 32-bit range of field (%lx)\n", flags); 97712048Speter return(1); 97812048Speter } 979136322Sle DIP_SET(curinode, di_flags, flags); 98012048Speter inodirty(); 98189827Sjoerg printactive(0); 98212048Speter return rval; 98312048Speter} 98412048Speter 98512048SpeterCMDFUNCSTART(chgen) 98612048Speter{ 98712048Speter int rval = 1; 98812048Speter long gen; 98912048Speter char *cp; 99012048Speter 99112048Speter if (!checkactive()) 99212048Speter return 1; 99312048Speter 99412048Speter gen = strtol(argv[1], &cp, 0); 99512048Speter if (cp == argv[1] || *cp != '\0' ) { 99612048Speter warnx("bad gen `%s'", argv[1]); 99712048Speter return 1; 99812048Speter } 99912048Speter 100012048Speter if (gen > INT_MAX || gen < INT_MIN) { 100112048Speter warnx("gen set beyond 32-bit range of field (%lx)\n", gen); 100212048Speter return(1); 100312048Speter } 1004136322Sle DIP_SET(curinode, di_gen, gen); 100512048Speter inodirty(); 100689827Sjoerg printactive(0); 100712048Speter return rval; 100812048Speter} 100912048Speter 101012048SpeterCMDFUNCSTART(linkcount) 101112048Speter{ 101212048Speter int rval = 1; 101312048Speter int lcnt; 101412048Speter char *cp; 101512048Speter 101612048Speter if (!checkactive()) 101712048Speter return 1; 101812048Speter 101912048Speter lcnt = strtol(argv[1], &cp, 0); 102012048Speter if (cp == argv[1] || *cp != '\0' ) { 102112048Speter warnx("bad link count `%s'", argv[1]); 102212048Speter return 1; 102312048Speter } 102412048Speter if (lcnt > USHRT_MAX || lcnt < 0) { 102512048Speter warnx("max link count is %d\n", USHRT_MAX); 102612048Speter return 1; 102712048Speter } 102812048Speter 1029136322Sle DIP_SET(curinode, di_nlink, lcnt); 103012048Speter inodirty(); 103189827Sjoerg printactive(0); 103212048Speter return rval; 103312048Speter} 103412048Speter 103512048SpeterCMDFUNCSTART(chowner) 103612048Speter{ 103712048Speter int rval = 1; 103812048Speter unsigned long uid; 103912048Speter char *cp; 104012048Speter struct passwd *pwd; 104112048Speter 104212048Speter if (!checkactive()) 104312048Speter return 1; 104412048Speter 104512048Speter uid = strtoul(argv[1], &cp, 0); 104612048Speter if (cp == argv[1] || *cp != '\0' ) { 104712048Speter /* try looking up name */ 104837001Scharnier if ((pwd = getpwnam(argv[1]))) { 104912048Speter uid = pwd->pw_uid; 105012048Speter } else { 105112048Speter warnx("bad uid `%s'", argv[1]); 105212048Speter return 1; 105312048Speter } 105412048Speter } 105512048Speter 1056136322Sle DIP_SET(curinode, di_uid, uid); 105712048Speter inodirty(); 105889827Sjoerg printactive(0); 105912048Speter return rval; 106012048Speter} 106112048Speter 106212048SpeterCMDFUNCSTART(chgroup) 106312048Speter{ 106412048Speter int rval = 1; 106512048Speter unsigned long gid; 106612048Speter char *cp; 106712048Speter struct group *grp; 106812048Speter 106912048Speter if (!checkactive()) 107012048Speter return 1; 107112048Speter 107212048Speter gid = strtoul(argv[1], &cp, 0); 107312048Speter if (cp == argv[1] || *cp != '\0' ) { 107437001Scharnier if ((grp = getgrnam(argv[1]))) { 107512048Speter gid = grp->gr_gid; 107612048Speter } else { 107712048Speter warnx("bad gid `%s'", argv[1]); 107812048Speter return 1; 107912048Speter } 108012048Speter } 108112048Speter 1082136322Sle DIP_SET(curinode, di_gid, gid); 108312048Speter inodirty(); 108489827Sjoerg printactive(0); 108512048Speter return rval; 108612048Speter} 108712048Speter 108812048Speterint 108998542Smckusickdotime(char *name, time_t *secp, int32_t *nsecp) 109012048Speter{ 109112048Speter char *p, *val; 109212048Speter struct tm t; 109312048Speter int32_t nsec; 109412048Speter p = strchr(name, '.'); 109512048Speter if (p) { 109612048Speter *p = '\0'; 109712048Speter nsec = strtoul(++p, &val, 0); 109812048Speter if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) { 109912048Speter warnx("invalid nanoseconds"); 110012048Speter goto badformat; 110112048Speter } 110212048Speter } else 110312048Speter nsec = 0; 110412048Speter if (strlen(name) != 14) { 110512048Speterbadformat: 110612048Speter warnx("date format: YYYYMMDDHHMMSS[.nsec]"); 110712048Speter return 1; 110812048Speter } 110998542Smckusick *nsecp = nsec; 111012048Speter 111112048Speter for (p = name; *p; p++) 111212048Speter if (*p < '0' || *p > '9') 111312048Speter goto badformat; 111412048Speter 111512048Speter p = name; 111612048Speter#define VAL() ((*p++) - '0') 111712048Speter t.tm_year = VAL(); 111812048Speter t.tm_year = VAL() + t.tm_year * 10; 111912048Speter t.tm_year = VAL() + t.tm_year * 10; 112012048Speter t.tm_year = VAL() + t.tm_year * 10 - 1900; 112112048Speter t.tm_mon = VAL(); 112212048Speter t.tm_mon = VAL() + t.tm_mon * 10 - 1; 112312048Speter t.tm_mday = VAL(); 112412048Speter t.tm_mday = VAL() + t.tm_mday * 10; 112512048Speter t.tm_hour = VAL(); 112612048Speter t.tm_hour = VAL() + t.tm_hour * 10; 112712048Speter t.tm_min = VAL(); 112812048Speter t.tm_min = VAL() + t.tm_min * 10; 112912048Speter t.tm_sec = VAL(); 113012048Speter t.tm_sec = VAL() + t.tm_sec * 10; 113112048Speter t.tm_isdst = -1; 113212048Speter 113398542Smckusick *secp = mktime(&t); 113498542Smckusick if (*secp == -1) { 113512048Speter warnx("date/time out of range"); 113612048Speter return 1; 113712048Speter } 113812048Speter return 0; 113912048Speter} 114012048Speter 1141161558SceriCMDFUNCSTART(chbtime) 1142161558Sceri{ 1143161558Sceri time_t secs; 1144161558Sceri int32_t nsecs; 1145161558Sceri 1146161558Sceri if (dotime(argv[1], &secs, &nsecs)) 1147161558Sceri return 1; 1148161558Sceri if (sblock.fs_magic == FS_UFS1_MAGIC) 1149161558Sceri return 1; 1150161558Sceri curinode->dp2.di_birthtime = _time_to_time64(secs); 1151161558Sceri curinode->dp2.di_birthnsec = nsecs; 1152161558Sceri inodirty(); 1153161558Sceri printactive(0); 1154161558Sceri return 0; 1155161558Sceri} 1156161558Sceri 115712048SpeterCMDFUNCSTART(chmtime) 115812048Speter{ 115998542Smckusick time_t secs; 116098542Smckusick int32_t nsecs; 116198542Smckusick 116298542Smckusick if (dotime(argv[1], &secs, &nsecs)) 116312048Speter return 1; 116498542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 116598542Smckusick curinode->dp1.di_mtime = _time_to_time32(secs); 116698542Smckusick else 116798542Smckusick curinode->dp2.di_mtime = _time_to_time64(secs); 1168136322Sle DIP_SET(curinode, di_mtimensec, nsecs); 116912048Speter inodirty(); 117089827Sjoerg printactive(0); 117112048Speter return 0; 117212048Speter} 117312048Speter 117412048SpeterCMDFUNCSTART(chatime) 117512048Speter{ 117698542Smckusick time_t secs; 117798542Smckusick int32_t nsecs; 117898542Smckusick 117998542Smckusick if (dotime(argv[1], &secs, &nsecs)) 118012048Speter return 1; 118198542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 118298542Smckusick curinode->dp1.di_atime = _time_to_time32(secs); 118398542Smckusick else 118498542Smckusick curinode->dp2.di_atime = _time_to_time64(secs); 1185136322Sle DIP_SET(curinode, di_atimensec, nsecs); 118612048Speter inodirty(); 118789827Sjoerg printactive(0); 118812048Speter return 0; 118912048Speter} 119012048Speter 119112048SpeterCMDFUNCSTART(chctime) 119212048Speter{ 119398542Smckusick time_t secs; 119498542Smckusick int32_t nsecs; 119598542Smckusick 119698542Smckusick if (dotime(argv[1], &secs, &nsecs)) 119712048Speter return 1; 119898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 119998542Smckusick curinode->dp1.di_ctime = _time_to_time32(secs); 120098542Smckusick else 120198542Smckusick curinode->dp2.di_ctime = _time_to_time64(secs); 1202136322Sle DIP_SET(curinode, di_ctimensec, nsecs); 120312048Speter inodirty(); 120489827Sjoerg printactive(0); 120512048Speter return 0; 120612048Speter} 1207