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: releng/10.2/sbin/fsdb/fsdb.c 248658 2013-03-23 20:00:02Z mckusick $"; 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> 42241013Smdf#include <stdint.h> 4312048Speter#include <string.h> 44217769Smckusick#include <time.h> 45122621Sjohan#include <timeconv.h> 4612048Speter 4712048Speter#include <ufs/ufs/dinode.h> 4812048Speter#include <ufs/ufs/dir.h> 4912048Speter#include <ufs/ffs/fs.h> 5012048Speter 5112048Speter#include "fsdb.h" 5212048Speter#include "fsck.h" 5312048Speter 5492881Simpstatic void usage(void) __dead2; 5592881Simpint cmdloop(void); 56159169Smaximstatic int compare_blk32(uint32_t *wantedblk, uint32_t curblk); 57159169Smaximstatic int compare_blk64(uint64_t *wantedblk, uint64_t curblk); 58159169Smaximstatic int founddatablk(uint64_t blk); 59159169Smaximstatic int find_blks32(uint32_t *buf, int size, uint32_t *blknum); 60159169Smaximstatic int find_blks64(uint64_t *buf, int size, uint64_t *blknum); 61159169Smaximstatic int find_indirblks32(uint32_t blk, int ind_level, uint32_t *blknum); 62159169Smaximstatic int find_indirblks64(uint64_t blk, int ind_level, uint64_t *blknum); 6312048Speter 6426557Scharnierstatic void 6592881Simpusage(void) 6612048Speter{ 6726557Scharnier fprintf(stderr, "usage: fsdb [-d] [-f] [-r] fsname\n"); 6826557Scharnier exit(1); 6912048Speter} 7012048Speter 7189826Sjoergint returntosingle; 7289826Sjoergchar nflag; 7312048Speter 7412048Speter/* 7512048Speter * We suck in lots of fsck code, and just pick & choose the stuff we want. 7612048Speter * 77102231Strhodes * fsreadfd is set up to read from the file system, fswritefd to write to 78102231Strhodes * the file system. 7912048Speter */ 8046080Simpint 8192881Simpmain(int argc, char *argv[]) 8212048Speter{ 8312048Speter int ch, rval; 8412048Speter char *fsys = NULL; 8512048Speter 8626557Scharnier while (-1 != (ch = getopt(argc, argv, "fdr"))) { 8712048Speter switch (ch) { 8812048Speter case 'f': 8926557Scharnier /* The -f option is left for historical 9026557Scharnier * reasons and has no meaning. 9126557Scharnier */ 9212048Speter break; 9312048Speter case 'd': 9412048Speter debug++; 9512048Speter break; 9624956Sjoerg case 'r': 9724956Sjoerg nflag++; /* "no" in fsck, readonly for us */ 9824956Sjoerg break; 9912048Speter default: 10012048Speter usage(); 10112048Speter } 10212048Speter } 10318585Sguido argc -= optind; 10418585Sguido argv += optind; 10526557Scharnier if (argc != 1) 10626557Scharnier usage(); 10726557Scharnier else 10826557Scharnier fsys = argv[0]; 10918585Sguido 11075884Siedowse sblock_init(); 11112048Speter if (!setup(fsys)) 112102231Strhodes errx(1, "cannot set up file system `%s'", fsys); 113102231Strhodes printf("%s file system `%s'\nLast Mounted on %s\n", 11424956Sjoerg nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt); 11512048Speter rval = cmdloop(); 11624956Sjoerg if (!nflag) { 11724956Sjoerg sblock.fs_clean = 0; /* mark it dirty */ 11824956Sjoerg sbdirty(); 11924956Sjoerg ckfini(0); 12024956Sjoerg printf("*** FILE SYSTEM MARKED DIRTY\n"); 12124956Sjoerg printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); 12224956Sjoerg printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); 12324956Sjoerg } 12412048Speter exit(rval); 12512048Speter} 12612048Speter 12792881Simp#define CMDFUNC(func) int func(int argc, char *argv[]) 12892881Simp#define CMDFUNCSTART(func) int func(int argc, char *argv[]) 12912048Speter 13012048SpeterCMDFUNC(helpfn); 13112048SpeterCMDFUNC(focus); /* focus on inode */ 13212048SpeterCMDFUNC(active); /* print active inode */ 13389827SjoergCMDFUNC(blocks); /* print blocks for active inode */ 13412048SpeterCMDFUNC(focusname); /* focus by name */ 13512048SpeterCMDFUNC(zapi); /* clear inode */ 13612048SpeterCMDFUNC(uplink); /* incr link */ 13712048SpeterCMDFUNC(downlink); /* decr link */ 13812048SpeterCMDFUNC(linkcount); /* set link count */ 13912048SpeterCMDFUNC(quit); /* quit */ 140159169SmaximCMDFUNC(findblk); /* find block */ 14112048SpeterCMDFUNC(ls); /* list directory */ 14212048SpeterCMDFUNC(rm); /* remove name */ 14312048SpeterCMDFUNC(ln); /* add name */ 14412048SpeterCMDFUNC(newtype); /* change type */ 14512048SpeterCMDFUNC(chmode); /* change mode */ 14618498SguidoCMDFUNC(chlen); /* change length */ 14712048SpeterCMDFUNC(chaflags); /* change flags */ 14812048SpeterCMDFUNC(chgen); /* change generation */ 14912048SpeterCMDFUNC(chowner); /* change owner */ 15012048SpeterCMDFUNC(chgroup); /* Change group */ 15112048SpeterCMDFUNC(back); /* pop back to last ino */ 152161558SceriCMDFUNC(chbtime); /* Change btime */ 15312048SpeterCMDFUNC(chmtime); /* Change mtime */ 15412048SpeterCMDFUNC(chctime); /* Change ctime */ 15512048SpeterCMDFUNC(chatime); /* Change atime */ 15612048SpeterCMDFUNC(chinum); /* Change inode # of dirent */ 15712048SpeterCMDFUNC(chname); /* Change dirname of dirent */ 15812048Speter 15912048Speterstruct cmdtable cmds[] = { 16024956Sjoerg { "help", "Print out help", 1, 1, FL_RO, helpfn }, 16124956Sjoerg { "?", "Print out help", 1, 1, FL_RO, helpfn }, 16224956Sjoerg { "inode", "Set active inode to INUM", 2, 2, FL_RO, focus }, 16324956Sjoerg { "clri", "Clear inode INUM", 2, 2, FL_WR, zapi }, 164157950Smaxim { "lookup", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname }, 165157950Smaxim { "cd", "Set active inode by looking up NAME", 2, 2, FL_RO | FL_ST, focusname }, 16624956Sjoerg { "back", "Go to previous active inode", 1, 1, FL_RO, back }, 16724956Sjoerg { "active", "Print active inode", 1, 1, FL_RO, active }, 16824956Sjoerg { "print", "Print active inode", 1, 1, FL_RO, active }, 16989827Sjoerg { "blocks", "Print block numbers of active inode", 1, 1, FL_RO, blocks }, 17024956Sjoerg { "uplink", "Increment link count", 1, 1, FL_WR, uplink }, 17124956Sjoerg { "downlink", "Decrement link count", 1, 1, FL_WR, downlink }, 17224956Sjoerg { "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount }, 173159169Smaxim { "findblk", "Find inode owning disk block(s)", 2, 33, FL_RO, findblk}, 17424956Sjoerg { "ls", "List current inode as directory", 1, 1, FL_RO, ls }, 175157950Smaxim { "rm", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm }, 176157950Smaxim { "del", "Remove NAME from current inode directory", 2, 2, FL_WR | FL_ST, rm }, 177157950Smaxim { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_WR | FL_ST, ln }, 17824956Sjoerg { "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_WR, chinum }, 179157950Smaxim { "chname", "Change dir entry number INDEX to NAME", 3, 3, FL_WR | FL_ST, chname }, 18024956Sjoerg { "chtype", "Change type of current inode to TYPE", 2, 2, FL_WR, newtype }, 18124956Sjoerg { "chmod", "Change mode of current inode to MODE", 2, 2, FL_WR, chmode }, 18224956Sjoerg { "chlen", "Change length of current inode to LENGTH", 2, 2, FL_WR, chlen }, 18324956Sjoerg { "chown", "Change owner of current inode to OWNER", 2, 2, FL_WR, chowner }, 18424956Sjoerg { "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup }, 18524956Sjoerg { "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_WR, chaflags }, 18624956Sjoerg { "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen }, 187161558Sceri { "btime", "Change btime of current inode to BTIME", 2, 2, FL_WR, chbtime }, 18824956Sjoerg { "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime }, 18924956Sjoerg { "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime }, 19024956Sjoerg { "atime", "Change atime of current inode to ATIME", 2, 2, FL_WR, chatime }, 19124956Sjoerg { "quit", "Exit", 1, 1, FL_RO, quit }, 19224956Sjoerg { "q", "Exit", 1, 1, FL_RO, quit }, 19324956Sjoerg { "exit", "Exit", 1, 1, FL_RO, quit }, 194136322Sle { NULL, 0, 0, 0, 0, NULL }, 19512048Speter}; 19612048Speter 19712048Speterint 19892881Simphelpfn(int argc, char *argv[]) 19912048Speter{ 20092806Sobrien struct cmdtable *cmdtp; 20112048Speter 20212048Speter printf("Commands are:\n%-10s %5s %5s %s\n", 203157950Smaxim "command", "min args", "max args", "what"); 20412048Speter 20512048Speter for (cmdtp = cmds; cmdtp->cmd; cmdtp++) 20612048Speter printf("%-10s %5u %5u %s\n", 207157950Smaxim cmdtp->cmd, cmdtp->minargc-1, cmdtp->maxargc-1, cmdtp->helptxt); 20812048Speter return 0; 20912048Speter} 21012048Speter 21112048Speterchar * 21292881Simpprompt(EditLine *el) 21312048Speter{ 21412048Speter static char pstring[64]; 215241013Smdf snprintf(pstring, sizeof(pstring), "fsdb (inum: %ju)> ", 216241013Smdf (uintmax_t)curinum); 21712048Speter return pstring; 21812048Speter} 21912048Speter 22012048Speter 22112048Speterint 22292881Simpcmdloop(void) 22312048Speter{ 22412048Speter char *line; 22512048Speter const char *elline; 22612048Speter int cmd_argc, rval = 0, known; 22712048Speter#define scratch known 22812048Speter char **cmd_argv; 22912048Speter struct cmdtable *cmdp; 23012048Speter History *hist; 23112048Speter EditLine *elptr; 23284261Sobrien HistEvent he; 23312048Speter 23412048Speter curinode = ginode(ROOTINO); 23512048Speter curinum = ROOTINO; 23689827Sjoerg printactive(0); 23712048Speter 23812048Speter hist = history_init(); 239151471Sstefanf history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */ 24012048Speter 24184261Sobrien elptr = el_init("fsdb", stdin, stdout, stderr); 24212048Speter el_set(elptr, EL_EDITOR, "emacs"); 24312048Speter el_set(elptr, EL_PROMPT, prompt); 24412048Speter el_set(elptr, EL_HIST, history, hist); 24512048Speter el_source(elptr, NULL); 24612048Speter 24712048Speter while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) { 24812048Speter if (debug) 24937001Scharnier printf("command `%s'\n", elline); 25012048Speter 25184261Sobrien history(hist, &he, H_ENTER, elline); 25212048Speter 25312048Speter line = strdup(elline); 25412048Speter cmd_argv = crack(line, &cmd_argc); 25512048Speter /* 25612048Speter * el_parse returns -1 to signal that it's not been handled 25712048Speter * internally. 25812048Speter */ 259148833Sstefanf if (el_parse(elptr, cmd_argc, (const char **)cmd_argv) != -1) 26012048Speter continue; 26112048Speter if (cmd_argc) { 26212048Speter known = 0; 26312048Speter for (cmdp = cmds; cmdp->cmd; cmdp++) { 26412048Speter if (!strcmp(cmdp->cmd, cmd_argv[0])) { 26524956Sjoerg if ((cmdp->flags & FL_WR) == FL_WR && nflag) 26624956Sjoerg warnx("`%s' requires write access", cmd_argv[0]), 26724956Sjoerg rval = 1; 26824956Sjoerg else if (cmd_argc >= cmdp->minargc && 26912048Speter cmd_argc <= cmdp->maxargc) 27012048Speter rval = (*cmdp->handler)(cmd_argc, cmd_argv); 271157950Smaxim else if (cmd_argc >= cmdp->minargc && 272157950Smaxim (cmdp->flags & FL_ST) == FL_ST) { 27389791Sgreen strcpy(line, elline); 27489791Sgreen cmd_argv = recrack(line, &cmd_argc, cmdp->maxargc); 27589791Sgreen rval = (*cmdp->handler)(cmd_argc, cmd_argv); 27689791Sgreen } else 27712048Speter rval = argcount(cmdp, cmd_argc, cmd_argv); 27812048Speter known = 1; 27912048Speter break; 28012048Speter } 28112048Speter } 28212048Speter if (!known) 28312048Speter warnx("unknown command `%s'", cmd_argv[0]), rval = 1; 28412048Speter } else 28512048Speter rval = 0; 28612048Speter free(line); 28712048Speter if (rval < 0) 28889810Sjoerg /* user typed "quit" */ 28989810Sjoerg return 0; 29012048Speter if (rval) 29112048Speter warnx("rval was %d", rval); 29212048Speter } 29312048Speter el_end(elptr); 29412048Speter history_end(hist); 29512048Speter return rval; 29612048Speter} 29712048Speter 29898542Smckusickunion dinode *curinode; 29912048Speterino_t curinum, ocurrent; 30012048Speter 30112048Speter#define GETINUM(ac,inum) inum = strtoul(argv[ac], &cp, 0); \ 30212048Speter if (inum < ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \ 303241013Smdf printf("inode %ju out of range; range is [%ju,%ju]\n", \ 304241013Smdf (uintmax_t)inum, (uintmax_t)ROOTINO, (uintmax_t)maxino); \ 30512048Speter return 1; \ 30612048Speter } 30712048Speter 30812048Speter/* 30912048Speter * Focus on given inode number 31012048Speter */ 31112048SpeterCMDFUNCSTART(focus) 31212048Speter{ 31312048Speter ino_t inum; 31412048Speter char *cp; 31512048Speter 31612048Speter GETINUM(1,inum); 31712048Speter curinode = ginode(inum); 31812048Speter ocurrent = curinum; 31912048Speter curinum = inum; 32089827Sjoerg printactive(0); 32112048Speter return 0; 32212048Speter} 32312048Speter 32412048SpeterCMDFUNCSTART(back) 32512048Speter{ 32612048Speter curinum = ocurrent; 32712048Speter curinode = ginode(curinum); 32889827Sjoerg printactive(0); 32912048Speter return 0; 33012048Speter} 33112048Speter 33212048SpeterCMDFUNCSTART(zapi) 33312048Speter{ 33412048Speter ino_t inum; 33598542Smckusick union dinode *dp; 33612048Speter char *cp; 33712048Speter 33812048Speter GETINUM(1,inum); 33912048Speter dp = ginode(inum); 34012048Speter clearinode(dp); 34112048Speter inodirty(); 34212048Speter if (curinode) /* re-set after potential change */ 34312048Speter curinode = ginode(curinum); 34412048Speter return 0; 34512048Speter} 34612048Speter 34712048SpeterCMDFUNCSTART(active) 34812048Speter{ 34989827Sjoerg printactive(0); 35012048Speter return 0; 35112048Speter} 35212048Speter 35389827SjoergCMDFUNCSTART(blocks) 35489827Sjoerg{ 35589827Sjoerg printactive(1); 35689827Sjoerg return 0; 35789827Sjoerg} 35812048Speter 35912048SpeterCMDFUNCSTART(quit) 36012048Speter{ 36112048Speter return -1; 36212048Speter} 36312048Speter 36412048SpeterCMDFUNCSTART(uplink) 36512048Speter{ 36612048Speter if (!checkactive()) 36712048Speter return 1; 368136322Sle DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1); 369241013Smdf printf("inode %ju link count now %d\n", 370241013Smdf (uintmax_t)curinum, DIP(curinode, di_nlink)); 37112048Speter inodirty(); 37212048Speter return 0; 37312048Speter} 37412048Speter 37512048SpeterCMDFUNCSTART(downlink) 37612048Speter{ 37712048Speter if (!checkactive()) 37812048Speter return 1; 379136322Sle DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1); 380241013Smdf printf("inode %ju link count now %d\n", 381241013Smdf (uintmax_t)curinum, DIP(curinode, di_nlink)); 38212048Speter inodirty(); 38312048Speter return 0; 38412048Speter} 38512048Speter 38612048Speterconst char *typename[] = { 38712048Speter "unknown", 38812048Speter "fifo", 38912048Speter "char special", 39012048Speter "unregistered #3", 39112048Speter "directory", 39212048Speter "unregistered #5", 39312048Speter "blk special", 39412048Speter "unregistered #7", 39512048Speter "regular", 39612048Speter "unregistered #9", 39712048Speter "symlink", 39812048Speter "unregistered #11", 39912048Speter "socket", 40012048Speter "unregistered #13", 40112048Speter "whiteout", 40212048Speter}; 403207141Sjeff 404207141Sjeffint diroff; 40512048Speterint slot; 40612048Speter 40712048Speterint 40892881Simpscannames(struct inodesc *idesc) 40912048Speter{ 41092806Sobrien struct direct *dirp = idesc->id_dirp; 41112048Speter 412207141Sjeff printf("slot %d off %d ino %d reclen %d: %s, `%.*s'\n", 413207141Sjeff slot++, diroff, dirp->d_ino, dirp->d_reclen, 414207141Sjeff typename[dirp->d_type], dirp->d_namlen, dirp->d_name); 415207141Sjeff diroff += dirp->d_reclen; 41612048Speter return (KEEPON); 41712048Speter} 41812048Speter 41912048SpeterCMDFUNCSTART(ls) 42012048Speter{ 42112048Speter struct inodesc idesc; 42212048Speter checkactivedir(); /* let it go on anyway */ 42312048Speter 42412048Speter slot = 0; 425207141Sjeff diroff = 0; 42612048Speter idesc.id_number = curinum; 42712048Speter idesc.id_func = scannames; 42812048Speter idesc.id_type = DATA; 42912048Speter idesc.id_fix = IGNORE; 43012048Speter ckinode(curinode, &idesc); 43112048Speter curinode = ginode(curinum); 43212048Speter 43312048Speter return 0; 43412048Speter} 43512048Speter 436159169Smaximstatic int findblk_numtofind; 437159169Smaximstatic int wantedblksize; 438159169Smaxim 439159169SmaximCMDFUNCSTART(findblk) 440159169Smaxim{ 441159169Smaxim ino_t inum, inosused; 442159169Smaxim uint32_t *wantedblk32; 443159169Smaxim uint64_t *wantedblk64; 444248658Smckusick struct bufarea *cgbp; 445248658Smckusick struct cg *cgp; 446159169Smaxim int c, i, is_ufs2; 447159169Smaxim 448159169Smaxim wantedblksize = (argc - 1); 449159169Smaxim is_ufs2 = sblock.fs_magic == FS_UFS2_MAGIC; 450159169Smaxim ocurrent = curinum; 451159169Smaxim 452159169Smaxim if (is_ufs2) { 453159169Smaxim wantedblk64 = calloc(wantedblksize, sizeof(uint64_t)); 454159169Smaxim if (wantedblk64 == NULL) 455159169Smaxim err(1, "malloc"); 456159169Smaxim for (i = 1; i < argc; i++) 457159169Smaxim wantedblk64[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0)); 458159169Smaxim } else { 459159169Smaxim wantedblk32 = calloc(wantedblksize, sizeof(uint32_t)); 460159169Smaxim if (wantedblk32 == NULL) 461159169Smaxim err(1, "malloc"); 462159169Smaxim for (i = 1; i < argc; i++) 463159169Smaxim wantedblk32[i - 1] = dbtofsb(&sblock, strtoull(argv[i], NULL, 0)); 464159169Smaxim } 465159169Smaxim findblk_numtofind = wantedblksize; 466159169Smaxim /* 467159169Smaxim * sblock.fs_ncg holds a number of cylinder groups. 468159169Smaxim * Iterate over all cylinder groups. 469159169Smaxim */ 470159169Smaxim for (c = 0; c < sblock.fs_ncg; c++) { 471159169Smaxim /* 472159169Smaxim * sblock.fs_ipg holds a number of inodes per cylinder group. 473159169Smaxim * Calculate a highest inode number for a given cylinder group. 474159169Smaxim */ 475159169Smaxim inum = c * sblock.fs_ipg; 476159169Smaxim /* Read cylinder group. */ 477248658Smckusick cgbp = cgget(c); 478248658Smckusick cgp = cgbp->b_un.b_cg; 479159169Smaxim /* 480159169Smaxim * Get a highest used inode number for a given cylinder group. 481159169Smaxim * For UFS1 all inodes initialized at the newfs stage. 482159169Smaxim */ 483159169Smaxim if (is_ufs2) 484159169Smaxim inosused = cgp->cg_initediblk; 485159169Smaxim else 486159169Smaxim inosused = sblock.fs_ipg; 487159169Smaxim 488159169Smaxim for (; inosused > 0; inum++, inosused--) { 489159169Smaxim /* Skip magic inodes: 0, WINO, ROOTINO. */ 490159169Smaxim if (inum < ROOTINO) 491159169Smaxim continue; 492159169Smaxim /* 493159169Smaxim * Check if the block we are looking for is just an inode block. 494159169Smaxim * 495159169Smaxim * ino_to_fsba() - get block containing inode from its number. 496159169Smaxim * INOPB() - get a number of inodes in one disk block. 497159169Smaxim */ 498159169Smaxim if (is_ufs2 ? 499159169Smaxim compare_blk64(wantedblk64, ino_to_fsba(&sblock, inum)) : 500159169Smaxim compare_blk32(wantedblk32, ino_to_fsba(&sblock, inum))) { 501241013Smdf printf("block %llu: inode block (%ju-%ju)\n", 502159169Smaxim (unsigned long long)fsbtodb(&sblock, 503159169Smaxim ino_to_fsba(&sblock, inum)), 504241013Smdf (uintmax_t)(inum / INOPB(&sblock)) * INOPB(&sblock), 505241013Smdf (uintmax_t)(inum / INOPB(&sblock) + 1) * INOPB(&sblock)); 506159169Smaxim findblk_numtofind--; 507159169Smaxim if (findblk_numtofind == 0) 508159169Smaxim goto end; 509159169Smaxim } 510159169Smaxim /* Get on-disk inode aka dinode. */ 511159169Smaxim curinum = inum; 512159169Smaxim curinode = ginode(inum); 513159169Smaxim /* Find IFLNK dinode with allocated data blocks. */ 514159169Smaxim switch (DIP(curinode, di_mode) & IFMT) { 515159169Smaxim case IFDIR: 516159169Smaxim case IFREG: 517159169Smaxim if (DIP(curinode, di_blocks) == 0) 518159169Smaxim continue; 519159169Smaxim break; 520159169Smaxim case IFLNK: 521159169Smaxim { 522159169Smaxim uint64_t size = DIP(curinode, di_size); 523159169Smaxim if (size > 0 && size < sblock.fs_maxsymlinklen && 524159169Smaxim DIP(curinode, di_blocks) == 0) 525159169Smaxim continue; 526159169Smaxim else 527159169Smaxim break; 528159169Smaxim } 529159169Smaxim default: 530159169Smaxim continue; 531159169Smaxim } 532159169Smaxim /* Look through direct data blocks. */ 533159169Smaxim if (is_ufs2 ? 534159169Smaxim find_blks64(curinode->dp2.di_db, NDADDR, wantedblk64) : 535159169Smaxim find_blks32(curinode->dp1.di_db, NDADDR, wantedblk32)) 536159169Smaxim goto end; 537159169Smaxim for (i = 0; i < NIADDR; i++) { 538159169Smaxim /* 539159169Smaxim * Does the block we are looking for belongs to the 540159169Smaxim * indirect blocks? 541159169Smaxim */ 542159169Smaxim if (is_ufs2 ? 543159169Smaxim compare_blk64(wantedblk64, curinode->dp2.di_ib[i]) : 544159169Smaxim compare_blk32(wantedblk32, curinode->dp1.di_ib[i])) 545159169Smaxim if (founddatablk(is_ufs2 ? curinode->dp2.di_ib[i] : 546159169Smaxim curinode->dp1.di_ib[i])) 547159169Smaxim goto end; 548159169Smaxim /* 549159169Smaxim * Search through indirect, double and triple indirect 550159169Smaxim * data blocks. 551159169Smaxim */ 552159169Smaxim if (is_ufs2 ? (curinode->dp2.di_ib[i] != 0) : 553159169Smaxim (curinode->dp1.di_ib[i] != 0)) 554159169Smaxim if (is_ufs2 ? 555159169Smaxim find_indirblks64(curinode->dp2.di_ib[i], i, 556159169Smaxim wantedblk64) : 557159169Smaxim find_indirblks32(curinode->dp1.di_ib[i], i, 558159169Smaxim wantedblk32)) 559159169Smaxim goto end; 560159169Smaxim } 561159169Smaxim } 562159169Smaxim } 563159169Smaximend: 564159169Smaxim curinum = ocurrent; 565159169Smaxim curinode = ginode(curinum); 566159169Smaxim return 0; 567159169Smaxim} 568159169Smaxim 569159169Smaximstatic int 570159169Smaximcompare_blk32(uint32_t *wantedblk, uint32_t curblk) 571159169Smaxim{ 572159169Smaxim int i; 573159169Smaxim 574159169Smaxim for (i = 0; i < wantedblksize; i++) { 575159169Smaxim if (wantedblk[i] != 0 && wantedblk[i] == curblk) { 576159169Smaxim wantedblk[i] = 0; 577159169Smaxim return 1; 578159169Smaxim } 579159169Smaxim } 580159169Smaxim return 0; 581159169Smaxim} 582159169Smaxim 583159169Smaximstatic int 584159169Smaximcompare_blk64(uint64_t *wantedblk, uint64_t curblk) 585159169Smaxim{ 586159169Smaxim int i; 587159169Smaxim 588159169Smaxim for (i = 0; i < wantedblksize; i++) { 589159169Smaxim if (wantedblk[i] != 0 && wantedblk[i] == curblk) { 590159169Smaxim wantedblk[i] = 0; 591159169Smaxim return 1; 592159169Smaxim } 593159169Smaxim } 594159169Smaxim return 0; 595159169Smaxim} 596159169Smaxim 597159169Smaximstatic int 598159169Smaximfounddatablk(uint64_t blk) 599159169Smaxim{ 600159169Smaxim 601241013Smdf printf("%llu: data block of inode %ju\n", 602241013Smdf (unsigned long long)fsbtodb(&sblock, blk), (uintmax_t)curinum); 603159169Smaxim findblk_numtofind--; 604159169Smaxim if (findblk_numtofind == 0) 605159169Smaxim return 1; 606159169Smaxim return 0; 607159169Smaxim} 608159169Smaxim 609159169Smaximstatic int 610159169Smaximfind_blks32(uint32_t *buf, int size, uint32_t *wantedblk) 611159169Smaxim{ 612159169Smaxim int blk; 613159169Smaxim for (blk = 0; blk < size; blk++) { 614159169Smaxim if (buf[blk] == 0) 615159169Smaxim continue; 616159169Smaxim if (compare_blk32(wantedblk, buf[blk])) { 617159169Smaxim if (founddatablk(buf[blk])) 618159169Smaxim return 1; 619159169Smaxim } 620159169Smaxim } 621159169Smaxim return 0; 622159169Smaxim} 623159169Smaxim 624159169Smaximstatic int 625159169Smaximfind_indirblks32(uint32_t blk, int ind_level, uint32_t *wantedblk) 626159169Smaxim{ 627159169Smaxim#define MAXNINDIR (MAXBSIZE / sizeof(uint32_t)) 628159169Smaxim uint32_t idblk[MAXNINDIR]; 629159169Smaxim int i; 630159169Smaxim 631163846Spjd blread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize); 632159169Smaxim if (ind_level <= 0) { 633159169Smaxim if (find_blks32(idblk, sblock.fs_bsize / sizeof(uint32_t), wantedblk)) 634159169Smaxim return 1; 635159169Smaxim } else { 636159169Smaxim ind_level--; 637159169Smaxim for (i = 0; i < sblock.fs_bsize / sizeof(uint32_t); i++) { 638159169Smaxim if (compare_blk32(wantedblk, idblk[i])) { 639159169Smaxim if (founddatablk(idblk[i])) 640159169Smaxim return 1; 641159169Smaxim } 642159169Smaxim if (idblk[i] != 0) 643159169Smaxim if (find_indirblks32(idblk[i], ind_level, wantedblk)) 644159169Smaxim return 1; 645159169Smaxim } 646159169Smaxim } 647159169Smaxim#undef MAXNINDIR 648159169Smaxim return 0; 649159169Smaxim} 650159169Smaxim 651159169Smaximstatic int 652159169Smaximfind_blks64(uint64_t *buf, int size, uint64_t *wantedblk) 653159169Smaxim{ 654159169Smaxim int blk; 655159169Smaxim for (blk = 0; blk < size; blk++) { 656159169Smaxim if (buf[blk] == 0) 657159169Smaxim continue; 658159169Smaxim if (compare_blk64(wantedblk, buf[blk])) { 659159169Smaxim if (founddatablk(buf[blk])) 660159169Smaxim return 1; 661159169Smaxim } 662159169Smaxim } 663159169Smaxim return 0; 664159169Smaxim} 665159169Smaxim 666159169Smaximstatic int 667159169Smaximfind_indirblks64(uint64_t blk, int ind_level, uint64_t *wantedblk) 668159169Smaxim{ 669159169Smaxim#define MAXNINDIR (MAXBSIZE / sizeof(uint64_t)) 670159169Smaxim uint64_t idblk[MAXNINDIR]; 671159169Smaxim int i; 672159169Smaxim 673163846Spjd blread(fsreadfd, (char *)idblk, fsbtodb(&sblock, blk), (int)sblock.fs_bsize); 674159169Smaxim if (ind_level <= 0) { 675159169Smaxim if (find_blks64(idblk, sblock.fs_bsize / sizeof(uint64_t), wantedblk)) 676159169Smaxim return 1; 677159169Smaxim } else { 678159169Smaxim ind_level--; 679159169Smaxim for (i = 0; i < sblock.fs_bsize / sizeof(uint64_t); i++) { 680159169Smaxim if (compare_blk64(wantedblk, idblk[i])) { 681159169Smaxim if (founddatablk(idblk[i])) 682159169Smaxim return 1; 683159169Smaxim } 684159169Smaxim if (idblk[i] != 0) 685159169Smaxim if (find_indirblks64(idblk[i], ind_level, wantedblk)) 686159169Smaxim return 1; 687159169Smaxim } 688159169Smaxim } 689159169Smaxim#undef MAXNINDIR 690159169Smaxim return 0; 691159169Smaxim} 692159169Smaxim 69392881Simpint findino(struct inodesc *idesc); /* from fsck */ 69492881Simpstatic int dolookup(char *name); 69512048Speter 69612048Speterstatic int 69792881Simpdolookup(char *name) 69812048Speter{ 69912048Speter struct inodesc idesc; 70012048Speter 70112048Speter if (!checkactivedir()) 70212048Speter return 0; 70312048Speter idesc.id_number = curinum; 70412048Speter idesc.id_func = findino; 70512048Speter idesc.id_name = name; 70612048Speter idesc.id_type = DATA; 70712048Speter idesc.id_fix = IGNORE; 70812048Speter if (ckinode(curinode, &idesc) & FOUND) { 70912048Speter curinum = idesc.id_parent; 71012048Speter curinode = ginode(curinum); 71189827Sjoerg printactive(0); 71212048Speter return 1; 71312048Speter } else { 71412048Speter warnx("name `%s' not found in current inode directory", name); 71512048Speter return 0; 71612048Speter } 71712048Speter} 71812048Speter 71912048SpeterCMDFUNCSTART(focusname) 72012048Speter{ 72112048Speter char *p, *val; 72212048Speter 72312048Speter if (!checkactive()) 72412048Speter return 1; 72512048Speter 72612048Speter ocurrent = curinum; 72712048Speter 72812048Speter if (argv[1][0] == '/') { 72912048Speter curinum = ROOTINO; 73012048Speter curinode = ginode(ROOTINO); 73112048Speter } else { 73212048Speter if (!checkactivedir()) 73312048Speter return 1; 73412048Speter } 73512048Speter for (p = argv[1]; p != NULL;) { 73612048Speter while ((val = strsep(&p, "/")) != NULL && *val == '\0'); 73712048Speter if (val) { 73812048Speter printf("component `%s': ", val); 73912048Speter fflush(stdout); 74012048Speter if (!dolookup(val)) { 74112048Speter curinode = ginode(curinum); 74212048Speter return(1); 74312048Speter } 74412048Speter } 74512048Speter } 74612048Speter return 0; 74712048Speter} 74812048Speter 74912048SpeterCMDFUNCSTART(ln) 75012048Speter{ 75112048Speter ino_t inum; 75212048Speter int rval; 75312048Speter char *cp; 75412048Speter 75512048Speter GETINUM(1,inum); 75612048Speter 75712048Speter if (!checkactivedir()) 75812048Speter return 1; 75912048Speter rval = makeentry(curinum, inum, argv[2]); 76012048Speter if (rval) 761241013Smdf printf("Ino %ju entered as `%s'\n", (uintmax_t)inum, argv[2]); 76212048Speter else 76312048Speter printf("could not enter name? weird.\n"); 76412048Speter curinode = ginode(curinum); 76512048Speter return rval; 76612048Speter} 76712048Speter 76812048SpeterCMDFUNCSTART(rm) 76912048Speter{ 77012048Speter int rval; 77112048Speter 77212048Speter if (!checkactivedir()) 77312048Speter return 1; 77412048Speter rval = changeino(curinum, argv[1], 0); 77512048Speter if (rval & ALTERED) { 77612048Speter printf("Name `%s' removed\n", argv[1]); 77712048Speter return 0; 77812048Speter } else { 77989791Sgreen printf("could not remove name ('%s')? weird.\n", argv[1]); 78012048Speter return 1; 78112048Speter } 78212048Speter} 78312048Speter 78412048Speterlong slotcount, desired; 78512048Speter 78612048Speterint 78792881Simpchinumfunc(struct inodesc *idesc) 78812048Speter{ 78992806Sobrien struct direct *dirp = idesc->id_dirp; 79012048Speter 79112048Speter if (slotcount++ == desired) { 79212048Speter dirp->d_ino = idesc->id_parent; 79312048Speter return STOP|ALTERED|FOUND; 79412048Speter } 79512048Speter return KEEPON; 79612048Speter} 79712048Speter 79812048SpeterCMDFUNCSTART(chinum) 79912048Speter{ 80012048Speter char *cp; 80112048Speter ino_t inum; 80212048Speter struct inodesc idesc; 80312048Speter 80412048Speter slotcount = 0; 80512048Speter if (!checkactivedir()) 80612048Speter return 1; 80712048Speter GETINUM(2,inum); 80812048Speter 80912048Speter desired = strtol(argv[1], &cp, 0); 81012048Speter if (cp == argv[1] || *cp != '\0' || desired < 0) { 81112048Speter printf("invalid slot number `%s'\n", argv[1]); 81212048Speter return 1; 81312048Speter } 81412048Speter 81512048Speter idesc.id_number = curinum; 81612048Speter idesc.id_func = chinumfunc; 81712048Speter idesc.id_fix = IGNORE; 81812048Speter idesc.id_type = DATA; 81912048Speter idesc.id_parent = inum; /* XXX convenient hiding place */ 82012048Speter 82112048Speter if (ckinode(curinode, &idesc) & FOUND) 82212048Speter return 0; 82312048Speter else { 82412048Speter warnx("no %sth slot in current directory", argv[1]); 82512048Speter return 1; 82612048Speter } 82712048Speter} 82812048Speter 82912048Speterint 83092881Simpchnamefunc(struct inodesc *idesc) 83112048Speter{ 83292806Sobrien struct direct *dirp = idesc->id_dirp; 83312048Speter struct direct testdir; 83412048Speter 83512048Speter if (slotcount++ == desired) { 83612048Speter /* will name fit? */ 83712048Speter testdir.d_namlen = strlen(idesc->id_name); 83812048Speter if (DIRSIZ(NEWDIRFMT, &testdir) <= dirp->d_reclen) { 83912048Speter dirp->d_namlen = testdir.d_namlen; 84012048Speter strcpy(dirp->d_name, idesc->id_name); 84112048Speter return STOP|ALTERED|FOUND; 84212048Speter } else 84312048Speter return STOP|FOUND; /* won't fit, so give up */ 84412048Speter } 84512048Speter return KEEPON; 84612048Speter} 84712048Speter 84812048SpeterCMDFUNCSTART(chname) 84912048Speter{ 85012048Speter int rval; 85112048Speter char *cp; 85212048Speter struct inodesc idesc; 85312048Speter 85412048Speter slotcount = 0; 85512048Speter if (!checkactivedir()) 85612048Speter return 1; 85712048Speter 85812048Speter desired = strtoul(argv[1], &cp, 0); 85912048Speter if (cp == argv[1] || *cp != '\0') { 86012048Speter printf("invalid slot number `%s'\n", argv[1]); 86112048Speter return 1; 86212048Speter } 86312048Speter 86412048Speter idesc.id_number = curinum; 86512048Speter idesc.id_func = chnamefunc; 86612048Speter idesc.id_fix = IGNORE; 86712048Speter idesc.id_type = DATA; 86812048Speter idesc.id_name = argv[2]; 86912048Speter 87012048Speter rval = ckinode(curinode, &idesc); 87112048Speter if ((rval & (FOUND|ALTERED)) == (FOUND|ALTERED)) 87212048Speter return 0; 87312048Speter else if (rval & FOUND) { 87412048Speter warnx("new name `%s' does not fit in slot %s\n", argv[2], argv[1]); 87512048Speter return 1; 87612048Speter } else { 87712048Speter warnx("no %sth slot in current directory", argv[1]); 87812048Speter return 1; 87912048Speter } 88012048Speter} 88112048Speter 88212048Speterstruct typemap { 88312048Speter const char *typename; 88412048Speter int typebits; 88512048Speter} typenamemap[] = { 88612048Speter {"file", IFREG}, 88712048Speter {"dir", IFDIR}, 88812048Speter {"socket", IFSOCK}, 88912048Speter {"fifo", IFIFO}, 89012048Speter}; 89112048Speter 89212048SpeterCMDFUNCSTART(newtype) 89312048Speter{ 89412048Speter int type; 89512048Speter struct typemap *tp; 89612048Speter 89712048Speter if (!checkactive()) 89812048Speter return 1; 89998542Smckusick type = DIP(curinode, di_mode) & IFMT; 90012048Speter for (tp = typenamemap; 90141023Struckman tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]; 90212048Speter tp++) { 90312048Speter if (!strcmp(argv[1], tp->typename)) { 90412048Speter printf("setting type to %s\n", tp->typename); 90512048Speter type = tp->typebits; 90612048Speter break; 90712048Speter } 90812048Speter } 90941023Struckman if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) { 91012048Speter warnx("type `%s' not known", argv[1]); 91112048Speter warnx("try one of `file', `dir', `socket', `fifo'"); 91212048Speter return 1; 91312048Speter } 914136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT); 915136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type); 91612048Speter inodirty(); 91789827Sjoerg printactive(0); 91812048Speter return 0; 91912048Speter} 92012048Speter 92118498SguidoCMDFUNCSTART(chlen) 92218498Sguido{ 92318498Sguido int rval = 1; 92418498Sguido long len; 92518498Sguido char *cp; 92618498Sguido 92718498Sguido if (!checkactive()) 92818498Sguido return 1; 92918498Sguido 93018498Sguido len = strtol(argv[1], &cp, 0); 93118498Sguido if (cp == argv[1] || *cp != '\0' || len < 0) { 93218498Sguido warnx("bad length `%s'", argv[1]); 93318498Sguido return 1; 93418498Sguido } 93518498Sguido 936136322Sle DIP_SET(curinode, di_size, len); 93718498Sguido inodirty(); 93889827Sjoerg printactive(0); 93918498Sguido return rval; 94018498Sguido} 94118498Sguido 94212048SpeterCMDFUNCSTART(chmode) 94312048Speter{ 94412048Speter int rval = 1; 94512048Speter long modebits; 94612048Speter char *cp; 94712048Speter 94812048Speter if (!checkactive()) 94912048Speter return 1; 95012048Speter 95112048Speter modebits = strtol(argv[1], &cp, 8); 95286258Siedowse if (cp == argv[1] || *cp != '\0' || (modebits & ~07777)) { 95312048Speter warnx("bad modebits `%s'", argv[1]); 95412048Speter return 1; 95512048Speter } 95612048Speter 957136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777); 958136322Sle DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits); 95912048Speter inodirty(); 96089827Sjoerg printactive(0); 96112048Speter return rval; 96212048Speter} 96312048Speter 96412048SpeterCMDFUNCSTART(chaflags) 96512048Speter{ 96612048Speter int rval = 1; 96712048Speter u_long flags; 96812048Speter char *cp; 96912048Speter 97012048Speter if (!checkactive()) 97112048Speter return 1; 97212048Speter 97312048Speter flags = strtoul(argv[1], &cp, 0); 97412048Speter if (cp == argv[1] || *cp != '\0' ) { 97512048Speter warnx("bad flags `%s'", argv[1]); 97612048Speter return 1; 97712048Speter } 97812048Speter 97912048Speter if (flags > UINT_MAX) { 98012048Speter warnx("flags set beyond 32-bit range of field (%lx)\n", flags); 98112048Speter return(1); 98212048Speter } 983136322Sle DIP_SET(curinode, di_flags, flags); 98412048Speter inodirty(); 98589827Sjoerg printactive(0); 98612048Speter return rval; 98712048Speter} 98812048Speter 98912048SpeterCMDFUNCSTART(chgen) 99012048Speter{ 99112048Speter int rval = 1; 99212048Speter long gen; 99312048Speter char *cp; 99412048Speter 99512048Speter if (!checkactive()) 99612048Speter return 1; 99712048Speter 99812048Speter gen = strtol(argv[1], &cp, 0); 99912048Speter if (cp == argv[1] || *cp != '\0' ) { 100012048Speter warnx("bad gen `%s'", argv[1]); 100112048Speter return 1; 100212048Speter } 100312048Speter 100412048Speter if (gen > INT_MAX || gen < INT_MIN) { 100512048Speter warnx("gen set beyond 32-bit range of field (%lx)\n", gen); 100612048Speter return(1); 100712048Speter } 1008136322Sle DIP_SET(curinode, di_gen, gen); 100912048Speter inodirty(); 101089827Sjoerg printactive(0); 101112048Speter return rval; 101212048Speter} 101312048Speter 101412048SpeterCMDFUNCSTART(linkcount) 101512048Speter{ 101612048Speter int rval = 1; 101712048Speter int lcnt; 101812048Speter char *cp; 101912048Speter 102012048Speter if (!checkactive()) 102112048Speter return 1; 102212048Speter 102312048Speter lcnt = strtol(argv[1], &cp, 0); 102412048Speter if (cp == argv[1] || *cp != '\0' ) { 102512048Speter warnx("bad link count `%s'", argv[1]); 102612048Speter return 1; 102712048Speter } 102812048Speter if (lcnt > USHRT_MAX || lcnt < 0) { 102912048Speter warnx("max link count is %d\n", USHRT_MAX); 103012048Speter return 1; 103112048Speter } 103212048Speter 1033136322Sle DIP_SET(curinode, di_nlink, lcnt); 103412048Speter inodirty(); 103589827Sjoerg printactive(0); 103612048Speter return rval; 103712048Speter} 103812048Speter 103912048SpeterCMDFUNCSTART(chowner) 104012048Speter{ 104112048Speter int rval = 1; 104212048Speter unsigned long uid; 104312048Speter char *cp; 104412048Speter struct passwd *pwd; 104512048Speter 104612048Speter if (!checkactive()) 104712048Speter return 1; 104812048Speter 104912048Speter uid = strtoul(argv[1], &cp, 0); 105012048Speter if (cp == argv[1] || *cp != '\0' ) { 105112048Speter /* try looking up name */ 105237001Scharnier if ((pwd = getpwnam(argv[1]))) { 105312048Speter uid = pwd->pw_uid; 105412048Speter } else { 105512048Speter warnx("bad uid `%s'", argv[1]); 105612048Speter return 1; 105712048Speter } 105812048Speter } 105912048Speter 1060136322Sle DIP_SET(curinode, di_uid, uid); 106112048Speter inodirty(); 106289827Sjoerg printactive(0); 106312048Speter return rval; 106412048Speter} 106512048Speter 106612048SpeterCMDFUNCSTART(chgroup) 106712048Speter{ 106812048Speter int rval = 1; 106912048Speter unsigned long gid; 107012048Speter char *cp; 107112048Speter struct group *grp; 107212048Speter 107312048Speter if (!checkactive()) 107412048Speter return 1; 107512048Speter 107612048Speter gid = strtoul(argv[1], &cp, 0); 107712048Speter if (cp == argv[1] || *cp != '\0' ) { 107837001Scharnier if ((grp = getgrnam(argv[1]))) { 107912048Speter gid = grp->gr_gid; 108012048Speter } else { 108112048Speter warnx("bad gid `%s'", argv[1]); 108212048Speter return 1; 108312048Speter } 108412048Speter } 108512048Speter 1086136322Sle DIP_SET(curinode, di_gid, gid); 108712048Speter inodirty(); 108889827Sjoerg printactive(0); 108912048Speter return rval; 109012048Speter} 109112048Speter 109212048Speterint 109398542Smckusickdotime(char *name, time_t *secp, int32_t *nsecp) 109412048Speter{ 109512048Speter char *p, *val; 109612048Speter struct tm t; 109712048Speter int32_t nsec; 109812048Speter p = strchr(name, '.'); 109912048Speter if (p) { 110012048Speter *p = '\0'; 110112048Speter nsec = strtoul(++p, &val, 0); 110212048Speter if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) { 110312048Speter warnx("invalid nanoseconds"); 110412048Speter goto badformat; 110512048Speter } 110612048Speter } else 110712048Speter nsec = 0; 110812048Speter if (strlen(name) != 14) { 110912048Speterbadformat: 111012048Speter warnx("date format: YYYYMMDDHHMMSS[.nsec]"); 111112048Speter return 1; 111212048Speter } 111398542Smckusick *nsecp = nsec; 111412048Speter 111512048Speter for (p = name; *p; p++) 111612048Speter if (*p < '0' || *p > '9') 111712048Speter goto badformat; 111812048Speter 111912048Speter p = name; 112012048Speter#define VAL() ((*p++) - '0') 112112048Speter t.tm_year = VAL(); 112212048Speter t.tm_year = VAL() + t.tm_year * 10; 112312048Speter t.tm_year = VAL() + t.tm_year * 10; 112412048Speter t.tm_year = VAL() + t.tm_year * 10 - 1900; 112512048Speter t.tm_mon = VAL(); 112612048Speter t.tm_mon = VAL() + t.tm_mon * 10 - 1; 112712048Speter t.tm_mday = VAL(); 112812048Speter t.tm_mday = VAL() + t.tm_mday * 10; 112912048Speter t.tm_hour = VAL(); 113012048Speter t.tm_hour = VAL() + t.tm_hour * 10; 113112048Speter t.tm_min = VAL(); 113212048Speter t.tm_min = VAL() + t.tm_min * 10; 113312048Speter t.tm_sec = VAL(); 113412048Speter t.tm_sec = VAL() + t.tm_sec * 10; 113512048Speter t.tm_isdst = -1; 113612048Speter 113798542Smckusick *secp = mktime(&t); 113898542Smckusick if (*secp == -1) { 113912048Speter warnx("date/time out of range"); 114012048Speter return 1; 114112048Speter } 114212048Speter return 0; 114312048Speter} 114412048Speter 1145161558SceriCMDFUNCSTART(chbtime) 1146161558Sceri{ 1147161558Sceri time_t secs; 1148161558Sceri int32_t nsecs; 1149161558Sceri 1150161558Sceri if (dotime(argv[1], &secs, &nsecs)) 1151161558Sceri return 1; 1152161558Sceri if (sblock.fs_magic == FS_UFS1_MAGIC) 1153161558Sceri return 1; 1154161558Sceri curinode->dp2.di_birthtime = _time_to_time64(secs); 1155161558Sceri curinode->dp2.di_birthnsec = nsecs; 1156161558Sceri inodirty(); 1157161558Sceri printactive(0); 1158161558Sceri return 0; 1159161558Sceri} 1160161558Sceri 116112048SpeterCMDFUNCSTART(chmtime) 116212048Speter{ 116398542Smckusick time_t secs; 116498542Smckusick int32_t nsecs; 116598542Smckusick 116698542Smckusick if (dotime(argv[1], &secs, &nsecs)) 116712048Speter return 1; 116898542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 116998542Smckusick curinode->dp1.di_mtime = _time_to_time32(secs); 117098542Smckusick else 117198542Smckusick curinode->dp2.di_mtime = _time_to_time64(secs); 1172136322Sle DIP_SET(curinode, di_mtimensec, nsecs); 117312048Speter inodirty(); 117489827Sjoerg printactive(0); 117512048Speter return 0; 117612048Speter} 117712048Speter 117812048SpeterCMDFUNCSTART(chatime) 117912048Speter{ 118098542Smckusick time_t secs; 118198542Smckusick int32_t nsecs; 118298542Smckusick 118398542Smckusick if (dotime(argv[1], &secs, &nsecs)) 118412048Speter return 1; 118598542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 118698542Smckusick curinode->dp1.di_atime = _time_to_time32(secs); 118798542Smckusick else 118898542Smckusick curinode->dp2.di_atime = _time_to_time64(secs); 1189136322Sle DIP_SET(curinode, di_atimensec, nsecs); 119012048Speter inodirty(); 119189827Sjoerg printactive(0); 119212048Speter return 0; 119312048Speter} 119412048Speter 119512048SpeterCMDFUNCSTART(chctime) 119612048Speter{ 119798542Smckusick time_t secs; 119898542Smckusick int32_t nsecs; 119998542Smckusick 120098542Smckusick if (dotime(argv[1], &secs, &nsecs)) 120112048Speter return 1; 120298542Smckusick if (sblock.fs_magic == FS_UFS1_MAGIC) 120398542Smckusick curinode->dp1.di_ctime = _time_to_time32(secs); 120498542Smckusick else 120598542Smckusick curinode->dp2.di_ctime = _time_to_time64(secs); 1206136322Sle DIP_SET(curinode, di_ctimensec, nsecs); 120712048Speter inodirty(); 120889827Sjoerg printactive(0); 120912048Speter return 0; 121012048Speter} 1211