fsdb.c revision 50476
1241675Suqs/* $NetBSD: fsdb.c,v 1.2 1995/10/08 23:18:10 thorpej Exp $ */ 2241675Suqs 3241675Suqs/* 4241675Suqs * Copyright (c) 1995 John T. Kohl 5241675Suqs * All rights reserved. 6241675Suqs * 7241675Suqs * Redistribution and use in source and binary forms, with or without 8241675Suqs * modification, are permitted provided that the following conditions 9241675Suqs * are met: 10241675Suqs * 1. Redistributions of source code must retain the above copyright 11241675Suqs * notice, this list of conditions and the following disclaimer. 12241675Suqs * 2. Redistributions in binary form must reproduce the above copyright 13241675Suqs * notice, this list of conditions and the following disclaimer in the 14241675Suqs * documentation and/or other materials provided with the distribution. 15241675Suqs * 3. The name of the author may not be used to endorse or promote products 16241675Suqs * derived from this software without specific prior written permission. 17241675Suqs * 18241675Suqs * THIS SOFTWARE IS PROVIDED BY THE AUTHOR `AS IS'' AND ANY EXPRESS OR 19241675Suqs * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20241675Suqs * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21241675Suqs * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, 22241675Suqs * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23241675Suqs * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24241675Suqs * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25241675Suqs * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 26241675Suqs * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 27241675Suqs * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 28241675Suqs * POSSIBILITY OF SUCH DAMAGE. 29241675Suqs */ 30241675Suqs 31241675Suqs#ifndef lint 32241675Suqsstatic const char rcsid[] = 33241675Suqs "$FreeBSD: head/sbin/fsdb/fsdb.c 50476 1999-08-28 00:22:10Z peter $"; 34241675Suqs#endif /* not lint */ 35241675Suqs 36241675Suqs#include <sys/types.h> 37241675Suqs#include <sys/param.h> 38241675Suqs#include <sys/time.h> 39241675Suqs#include <ctype.h> 40241675Suqs#include <err.h> 41241675Suqs#include <grp.h> 42241675Suqs#include <histedit.h> 43241675Suqs#include <pwd.h> 44241675Suqs#include <string.h> 45241675Suqs 46241675Suqs#include <ufs/ufs/dinode.h> 47241675Suqs#include <ufs/ufs/dir.h> 48241675Suqs#include <ufs/ffs/fs.h> 49241675Suqs 50241675Suqs#include "fsdb.h" 51241675Suqs#include "fsck.h" 52241675Suqs 53241675Suqsstatic void usage __P((void)); 54241675Suqsint cmdloop __P((void)); 55241675Suqs 56241675Suqsstatic void 57241675Suqsusage() 58241675Suqs{ 59241675Suqs fprintf(stderr, "usage: fsdb [-d] [-f] [-r] fsname\n"); 60241675Suqs exit(1); 61241675Suqs} 62241675Suqs 63241675Suqsint returntosingle = 0; 64241675Suqschar nflag = 0; 65241675Suqs 66241675Suqs/* 67241675Suqs * We suck in lots of fsck code, and just pick & choose the stuff we want. 68241675Suqs * 69241675Suqs * fsreadfd is set up to read from the file system, fswritefd to write to 70241675Suqs * the file system. 71241675Suqs */ 72241675Suqsint 73241675Suqsmain(argc, argv) 74241675Suqs int argc; 75241675Suqs char *argv[]; 76241675Suqs{ 77241675Suqs int ch, rval; 78241675Suqs char *fsys = NULL; 79241675Suqs 80241675Suqs while (-1 != (ch = getopt(argc, argv, "fdr"))) { 81241675Suqs switch (ch) { 82241675Suqs case 'f': 83241675Suqs /* The -f option is left for historical 84241675Suqs * reasons and has no meaning. 85241675Suqs */ 86241675Suqs break; 87241675Suqs case 'd': 88241675Suqs debug++; 89241675Suqs break; 90241675Suqs case 'r': 91241675Suqs nflag++; /* "no" in fsck, readonly for us */ 92241675Suqs break; 93241675Suqs default: 94241675Suqs usage(); 95241675Suqs } 96241675Suqs } 97241675Suqs argc -= optind; 98241675Suqs argv += optind; 99241675Suqs if (argc != 1) 100241675Suqs usage(); 101241675Suqs else 102241675Suqs fsys = argv[0]; 103241675Suqs 104241675Suqs if (!setup(fsys)) 105241675Suqs errx(1, "cannot set up file system `%s'", fsys); 106241675Suqs printf("%s file system `%s'\nLast Mounted on %s\n", 107241675Suqs nflag? "Examining": "Editing", fsys, sblock.fs_fsmnt); 108241675Suqs rval = cmdloop(); 109241675Suqs if (!nflag) { 110241675Suqs sblock.fs_clean = 0; /* mark it dirty */ 111241675Suqs sbdirty(); 112241675Suqs ckfini(0); 113241675Suqs printf("*** FILE SYSTEM MARKED DIRTY\n"); 114241675Suqs printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); 115241675Suqs printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); 116241675Suqs } 117241675Suqs exit(rval); 118241675Suqs} 119241675Suqs 120241675Suqs#define CMDFUNC(func) int func __P((int argc, char *argv[])) 121241675Suqs#define CMDFUNCSTART(func) int func(argc, argv) \ 122241675Suqs int argc; \ 123241675Suqs char *argv[]; 124241675Suqs 125241675SuqsCMDFUNC(helpfn); 126241675SuqsCMDFUNC(focus); /* focus on inode */ 127241675SuqsCMDFUNC(active); /* print active inode */ 128241675SuqsCMDFUNC(focusname); /* focus by name */ 129241675SuqsCMDFUNC(zapi); /* clear inode */ 130241675SuqsCMDFUNC(uplink); /* incr link */ 131241675SuqsCMDFUNC(downlink); /* decr link */ 132241675SuqsCMDFUNC(linkcount); /* set link count */ 133241675SuqsCMDFUNC(quit); /* quit */ 134241675SuqsCMDFUNC(ls); /* list directory */ 135241675SuqsCMDFUNC(rm); /* remove name */ 136241675SuqsCMDFUNC(ln); /* add name */ 137241675SuqsCMDFUNC(newtype); /* change type */ 138241675SuqsCMDFUNC(chmode); /* change mode */ 139241675SuqsCMDFUNC(chlen); /* change length */ 140241675SuqsCMDFUNC(chaflags); /* change flags */ 141241675SuqsCMDFUNC(chgen); /* change generation */ 142241675SuqsCMDFUNC(chowner); /* change owner */ 143241675SuqsCMDFUNC(chgroup); /* Change group */ 144241675SuqsCMDFUNC(back); /* pop back to last ino */ 145241675SuqsCMDFUNC(chmtime); /* Change mtime */ 146241675SuqsCMDFUNC(chctime); /* Change ctime */ 147241675SuqsCMDFUNC(chatime); /* Change atime */ 148241675SuqsCMDFUNC(chinum); /* Change inode # of dirent */ 149241675SuqsCMDFUNC(chname); /* Change dirname of dirent */ 150241675Suqs 151241675Suqsstruct cmdtable cmds[] = { 152241675Suqs { "help", "Print out help", 1, 1, FL_RO, helpfn }, 153241675Suqs { "?", "Print out help", 1, 1, FL_RO, helpfn }, 154241675Suqs { "inode", "Set active inode to INUM", 2, 2, FL_RO, focus }, 155241675Suqs { "clri", "Clear inode INUM", 2, 2, FL_WR, zapi }, 156241675Suqs { "lookup", "Set active inode by looking up NAME", 2, 2, FL_RO, focusname }, 157241675Suqs { "cd", "Set active inode by looking up NAME", 2, 2, FL_RO, focusname }, 158241675Suqs { "back", "Go to previous active inode", 1, 1, FL_RO, back }, 159241675Suqs { "active", "Print active inode", 1, 1, FL_RO, active }, 160241675Suqs { "print", "Print active inode", 1, 1, FL_RO, active }, 161241675Suqs { "uplink", "Increment link count", 1, 1, FL_WR, uplink }, 162241675Suqs { "downlink", "Decrement link count", 1, 1, FL_WR, downlink }, 163241675Suqs { "linkcount", "Set link count to COUNT", 2, 2, FL_WR, linkcount }, 164241675Suqs { "ls", "List current inode as directory", 1, 1, FL_RO, ls }, 165241675Suqs { "rm", "Remove NAME from current inode directory", 2, 2, FL_WR, rm }, 166241675Suqs { "del", "Remove NAME from current inode directory", 2, 2, FL_WR, rm }, 167241675Suqs { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, FL_WR, ln }, 168241675Suqs { "chinum", "Change dir entry number INDEX to INUM", 3, 3, FL_WR, chinum }, 169241675Suqs { "chname", "Change dir entry number INDEX to NAME", 3, 3, FL_WR, chname }, 170241675Suqs { "chtype", "Change type of current inode to TYPE", 2, 2, FL_WR, newtype }, 171241675Suqs { "chmod", "Change mode of current inode to MODE", 2, 2, FL_WR, chmode }, 172241675Suqs { "chlen", "Change length of current inode to LENGTH", 2, 2, FL_WR, chlen }, 173241675Suqs { "chown", "Change owner of current inode to OWNER", 2, 2, FL_WR, chowner }, 174241675Suqs { "chgrp", "Change group of current inode to GROUP", 2, 2, FL_WR, chgroup }, 175241675Suqs { "chflags", "Change flags of current inode to FLAGS", 2, 2, FL_WR, chaflags }, 176241675Suqs { "chgen", "Change generation number of current inode to GEN", 2, 2, FL_WR, chgen }, 177241675Suqs { "mtime", "Change mtime of current inode to MTIME", 2, 2, FL_WR, chmtime }, 178241675Suqs { "ctime", "Change ctime of current inode to CTIME", 2, 2, FL_WR, chctime }, 179241675Suqs { "atime", "Change atime of current inode to ATIME", 2, 2, FL_WR, chatime }, 180241675Suqs { "quit", "Exit", 1, 1, FL_RO, quit }, 181241675Suqs { "q", "Exit", 1, 1, FL_RO, quit }, 182241675Suqs { "exit", "Exit", 1, 1, FL_RO, quit }, 183241675Suqs { NULL, 0, 0, 0 }, 184241675Suqs}; 185241675Suqs 186241675Suqsint 187241675Suqshelpfn(argc, argv) 188241675Suqs int argc; 189241675Suqs char *argv[]; 190241675Suqs{ 191241675Suqs register struct cmdtable *cmdtp; 192241675Suqs 193241675Suqs printf("Commands are:\n%-10s %5s %5s %s\n", 194241675Suqs "command", "min argc", "max argc", "what"); 195241675Suqs 196241675Suqs for (cmdtp = cmds; cmdtp->cmd; cmdtp++) 197241675Suqs printf("%-10s %5u %5u %s\n", 198241675Suqs cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt); 199241675Suqs return 0; 200241675Suqs} 201241675Suqs 202241675Suqschar * 203241675Suqsprompt(el) 204241675Suqs EditLine *el; 205241675Suqs{ 206241675Suqs static char pstring[64]; 207241675Suqs snprintf(pstring, sizeof(pstring), "fsdb (inum: %d)> ", curinum); 208241675Suqs return pstring; 209241675Suqs} 210241675Suqs 211241675Suqs 212241675Suqsint 213241675Suqscmdloop() 214241675Suqs{ 215241675Suqs char *line; 216241675Suqs const char *elline; 217241675Suqs int cmd_argc, rval = 0, known; 218241675Suqs#define scratch known 219241675Suqs char **cmd_argv; 220241675Suqs struct cmdtable *cmdp; 221241675Suqs History *hist; 222241675Suqs EditLine *elptr; 223241675Suqs 224241675Suqs curinode = ginode(ROOTINO); 225241675Suqs curinum = ROOTINO; 226241675Suqs printactive(); 227241675Suqs 228241675Suqs hist = history_init(); 229241675Suqs history(hist, H_EVENT, 100); /* 100 elt history buffer */ 230241675Suqs 231241675Suqs elptr = el_init("fsdb", stdin, stdout); 232241675Suqs el_set(elptr, EL_EDITOR, "emacs"); 233241675Suqs el_set(elptr, EL_PROMPT, prompt); 234241675Suqs el_set(elptr, EL_HIST, history, hist); 235241675Suqs el_source(elptr, NULL); 236241675Suqs 237241675Suqs while ((elline = el_gets(elptr, &scratch)) != NULL && scratch != 0) { 238241675Suqs if (debug) 239241675Suqs printf("command `%s'\n", elline); 240241675Suqs 241241675Suqs history(hist, H_ENTER, elline); 242241675Suqs 243241675Suqs line = strdup(elline); 244241675Suqs cmd_argv = crack(line, &cmd_argc); 245241675Suqs /* 246241675Suqs * el_parse returns -1 to signal that it's not been handled 247241675Suqs * internally. 248241675Suqs */ 249241675Suqs if (el_parse(elptr, cmd_argc, cmd_argv) != -1) 250241675Suqs continue; 251241675Suqs if (cmd_argc) { 252241675Suqs known = 0; 253241675Suqs for (cmdp = cmds; cmdp->cmd; cmdp++) { 254241675Suqs if (!strcmp(cmdp->cmd, cmd_argv[0])) { 255241675Suqs if ((cmdp->flags & FL_WR) == FL_WR && nflag) 256241675Suqs warnx("`%s' requires write access", cmd_argv[0]), 257241675Suqs rval = 1; 258241675Suqs else if (cmd_argc >= cmdp->minargc && 259241675Suqs cmd_argc <= cmdp->maxargc) 260241675Suqs rval = (*cmdp->handler)(cmd_argc, cmd_argv); 261241675Suqs else 262241675Suqs rval = argcount(cmdp, cmd_argc, cmd_argv); 263241675Suqs known = 1; 264241675Suqs break; 265241675Suqs } 266241675Suqs } 267241675Suqs if (!known) 268241675Suqs warnx("unknown command `%s'", cmd_argv[0]), rval = 1; 269241675Suqs } else 270241675Suqs rval = 0; 271241675Suqs free(line); 272241675Suqs if (rval < 0) 273241675Suqs return rval; 274241675Suqs if (rval) 275241675Suqs warnx("rval was %d", rval); 276241675Suqs } 277241675Suqs el_end(elptr); 278241675Suqs history_end(hist); 279241675Suqs return rval; 280241675Suqs} 281241675Suqs 282241675Suqsstruct dinode *curinode; 283241675Suqsino_t curinum, ocurrent; 284241675Suqs 285241675Suqs#define GETINUM(ac,inum) inum = strtoul(argv[ac], &cp, 0); \ 286241675Suqs if (inum < ROOTINO || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \ 287241675Suqs printf("inode %d out of range; range is [%d,%d]\n", \ 288241675Suqs inum, ROOTINO, maxino); \ 289241675Suqs return 1; \ 290241675Suqs } 291241675Suqs 292241675Suqs/* 293241675Suqs * Focus on given inode number 294241675Suqs */ 295241675SuqsCMDFUNCSTART(focus) 296241675Suqs{ 297241675Suqs ino_t inum; 298241675Suqs char *cp; 299241675Suqs 300241675Suqs GETINUM(1,inum); 301241675Suqs curinode = ginode(inum); 302241675Suqs ocurrent = curinum; 303241675Suqs curinum = inum; 304241675Suqs printactive(); 305241675Suqs return 0; 306241675Suqs} 307241675Suqs 308241675SuqsCMDFUNCSTART(back) 309241675Suqs{ 310241675Suqs curinum = ocurrent; 311241675Suqs curinode = ginode(curinum); 312241675Suqs printactive(); 313241675Suqs return 0; 314241675Suqs} 315241675Suqs 316241675SuqsCMDFUNCSTART(zapi) 317241675Suqs{ 318241675Suqs ino_t inum; 319241675Suqs struct dinode *dp; 320241675Suqs char *cp; 321241675Suqs 322241675Suqs GETINUM(1,inum); 323241675Suqs dp = ginode(inum); 324241675Suqs clearinode(dp); 325241675Suqs inodirty(); 326241675Suqs if (curinode) /* re-set after potential change */ 327241675Suqs curinode = ginode(curinum); 328241675Suqs return 0; 329241675Suqs} 330241675Suqs 331241675SuqsCMDFUNCSTART(active) 332241675Suqs{ 333241675Suqs printactive(); 334241675Suqs return 0; 335241675Suqs} 336241675Suqs 337241675Suqs 338241675SuqsCMDFUNCSTART(quit) 339241675Suqs{ 340241675Suqs return -1; 341241675Suqs} 342241675Suqs 343241675SuqsCMDFUNCSTART(uplink) 344241675Suqs{ 345241675Suqs if (!checkactive()) 346241675Suqs return 1; 347241675Suqs printf("inode %d link count now %d\n", curinum, ++curinode->di_nlink); 348241675Suqs inodirty(); 349241675Suqs return 0; 350241675Suqs} 351241675Suqs 352241675SuqsCMDFUNCSTART(downlink) 353241675Suqs{ 354241675Suqs if (!checkactive()) 355241675Suqs return 1; 356241675Suqs printf("inode %d link count now %d\n", curinum, --curinode->di_nlink); 357241675Suqs inodirty(); 358241675Suqs return 0; 359241675Suqs} 360241675Suqs 361241675Suqsconst char *typename[] = { 362241675Suqs "unknown", 363241675Suqs "fifo", 364241675Suqs "char special", 365241675Suqs "unregistered #3", 366241675Suqs "directory", 367241675Suqs "unregistered #5", 368241675Suqs "blk special", 369241675Suqs "unregistered #7", 370241675Suqs "regular", 371241675Suqs "unregistered #9", 372241675Suqs "symlink", 373241675Suqs "unregistered #11", 374241675Suqs "socket", 375241675Suqs "unregistered #13", 376241675Suqs "whiteout", 377241675Suqs}; 378241675Suqs 379241675Suqsint slot; 380241675Suqs 381241675Suqsint 382241675Suqsscannames(idesc) 383241675Suqs struct inodesc *idesc; 384241675Suqs{ 385241675Suqs register struct direct *dirp = idesc->id_dirp; 386241675Suqs 387241675Suqs printf("slot %d ino %d reclen %d: %s, `%.*s'\n", 388241675Suqs slot++, dirp->d_ino, dirp->d_reclen, typename[dirp->d_type], 389241675Suqs dirp->d_namlen, dirp->d_name); 390241675Suqs return (KEEPON); 391241675Suqs} 392241675Suqs 393241675SuqsCMDFUNCSTART(ls) 394241675Suqs{ 395241675Suqs struct inodesc idesc; 396241675Suqs checkactivedir(); /* let it go on anyway */ 397241675Suqs 398241675Suqs slot = 0; 399241675Suqs idesc.id_number = curinum; 400241675Suqs idesc.id_func = scannames; 401241675Suqs idesc.id_type = DATA; 402241675Suqs idesc.id_fix = IGNORE; 403241675Suqs ckinode(curinode, &idesc); 404241675Suqs curinode = ginode(curinum); 405241675Suqs 406241675Suqs return 0; 407241675Suqs} 408241675Suqs 409241675Suqsint findino __P((struct inodesc *idesc)); /* from fsck */ 410241675Suqsstatic int dolookup __P((char *name)); 411241675Suqs 412241675Suqsstatic int 413241675Suqsdolookup(name) 414241675Suqs char *name; 415241675Suqs{ 416241675Suqs struct inodesc idesc; 417241675Suqs 418241675Suqs if (!checkactivedir()) 419241675Suqs return 0; 420241675Suqs idesc.id_number = curinum; 421241675Suqs idesc.id_func = findino; 422241675Suqs idesc.id_name = name; 423241675Suqs idesc.id_type = DATA; 424241675Suqs idesc.id_fix = IGNORE; 425241675Suqs if (ckinode(curinode, &idesc) & FOUND) { 426241675Suqs curinum = idesc.id_parent; 427241675Suqs curinode = ginode(curinum); 428241675Suqs printactive(); 429241675Suqs return 1; 430241675Suqs } else { 431241675Suqs warnx("name `%s' not found in current inode directory", name); 432241675Suqs return 0; 433241675Suqs } 434241675Suqs} 435241675Suqs 436241675SuqsCMDFUNCSTART(focusname) 437241675Suqs{ 438241675Suqs char *p, *val; 439241675Suqs 440241675Suqs if (!checkactive()) 441241675Suqs return 1; 442241675Suqs 443241675Suqs ocurrent = curinum; 444241675Suqs 445241675Suqs if (argv[1][0] == '/') { 446241675Suqs curinum = ROOTINO; 447241675Suqs curinode = ginode(ROOTINO); 448241675Suqs } else { 449241675Suqs if (!checkactivedir()) 450241675Suqs return 1; 451241675Suqs } 452241675Suqs for (p = argv[1]; p != NULL;) { 453241675Suqs while ((val = strsep(&p, "/")) != NULL && *val == '\0'); 454241675Suqs if (val) { 455241675Suqs printf("component `%s': ", val); 456241675Suqs fflush(stdout); 457241675Suqs if (!dolookup(val)) { 458241675Suqs curinode = ginode(curinum); 459241675Suqs return(1); 460241675Suqs } 461241675Suqs } 462241675Suqs } 463241675Suqs return 0; 464241675Suqs} 465241675Suqs 466241675SuqsCMDFUNCSTART(ln) 467241675Suqs{ 468241675Suqs ino_t inum; 469241675Suqs int rval; 470241675Suqs char *cp; 471241675Suqs 472241675Suqs GETINUM(1,inum); 473241675Suqs 474241675Suqs if (!checkactivedir()) 475241675Suqs return 1; 476241675Suqs rval = makeentry(curinum, inum, argv[2]); 477241675Suqs if (rval) 478241675Suqs printf("Ino %d entered as `%s'\n", inum, argv[2]); 479241675Suqs else 480241675Suqs printf("could not enter name? weird.\n"); 481241675Suqs curinode = ginode(curinum); 482241675Suqs return rval; 483241675Suqs} 484241675Suqs 485241675SuqsCMDFUNCSTART(rm) 486241675Suqs{ 487241675Suqs int rval; 488241675Suqs 489241675Suqs if (!checkactivedir()) 490241675Suqs return 1; 491241675Suqs rval = changeino(curinum, argv[1], 0); 492241675Suqs if (rval & ALTERED) { 493241675Suqs printf("Name `%s' removed\n", argv[1]); 494241675Suqs return 0; 495241675Suqs } else { 496241675Suqs printf("could not remove name? weird.\n"); 497241675Suqs return 1; 498241675Suqs } 499241675Suqs} 500241675Suqs 501241675Suqslong slotcount, desired; 502241675Suqs 503241675Suqsint 504241675Suqschinumfunc(idesc) 505241675Suqs struct inodesc *idesc; 506241675Suqs{ 507241675Suqs register struct direct *dirp = idesc->id_dirp; 508241675Suqs 509241675Suqs if (slotcount++ == desired) { 510241675Suqs dirp->d_ino = idesc->id_parent; 511241675Suqs return STOP|ALTERED|FOUND; 512241675Suqs } 513241675Suqs return KEEPON; 514241675Suqs} 515241675Suqs 516241675SuqsCMDFUNCSTART(chinum) 517241675Suqs{ 518241675Suqs char *cp; 519241675Suqs ino_t inum; 520241675Suqs struct inodesc idesc; 521241675Suqs 522241675Suqs slotcount = 0; 523241675Suqs if (!checkactivedir()) 524241675Suqs return 1; 525241675Suqs GETINUM(2,inum); 526241675Suqs 527241675Suqs desired = strtol(argv[1], &cp, 0); 528241675Suqs if (cp == argv[1] || *cp != '\0' || desired < 0) { 529241675Suqs printf("invalid slot number `%s'\n", argv[1]); 530241675Suqs return 1; 531241675Suqs } 532241675Suqs 533241675Suqs idesc.id_number = curinum; 534241675Suqs idesc.id_func = chinumfunc; 535241675Suqs idesc.id_fix = IGNORE; 536241675Suqs idesc.id_type = DATA; 537241675Suqs idesc.id_parent = inum; /* XXX convenient hiding place */ 538241675Suqs 539241675Suqs if (ckinode(curinode, &idesc) & FOUND) 540241675Suqs return 0; 541241675Suqs else { 542241675Suqs warnx("no %sth slot in current directory", argv[1]); 543241675Suqs return 1; 544241675Suqs } 545241675Suqs} 546241675Suqs 547241675Suqsint 548241675Suqschnamefunc(idesc) 549241675Suqs struct inodesc *idesc; 550241675Suqs{ 551241675Suqs register struct direct *dirp = idesc->id_dirp; 552241675Suqs struct direct testdir; 553241675Suqs 554241675Suqs if (slotcount++ == desired) { 555241675Suqs /* will name fit? */ 556241675Suqs testdir.d_namlen = strlen(idesc->id_name); 557241675Suqs if (DIRSIZ(NEWDIRFMT, &testdir) <= dirp->d_reclen) { 558241675Suqs dirp->d_namlen = testdir.d_namlen; 559241675Suqs strcpy(dirp->d_name, idesc->id_name); 560241675Suqs return STOP|ALTERED|FOUND; 561241675Suqs } else 562241675Suqs return STOP|FOUND; /* won't fit, so give up */ 563241675Suqs } 564241675Suqs return KEEPON; 565241675Suqs} 566241675Suqs 567241675SuqsCMDFUNCSTART(chname) 568241675Suqs{ 569241675Suqs int rval; 570241675Suqs char *cp; 571241675Suqs struct inodesc idesc; 572241675Suqs 573241675Suqs slotcount = 0; 574241675Suqs if (!checkactivedir()) 575241675Suqs return 1; 576241675Suqs 577241675Suqs desired = strtoul(argv[1], &cp, 0); 578241675Suqs if (cp == argv[1] || *cp != '\0') { 579241675Suqs printf("invalid slot number `%s'\n", argv[1]); 580241675Suqs return 1; 581241675Suqs } 582241675Suqs 583241675Suqs idesc.id_number = curinum; 584241675Suqs idesc.id_func = chnamefunc; 585241675Suqs idesc.id_fix = IGNORE; 586241675Suqs idesc.id_type = DATA; 587241675Suqs idesc.id_name = argv[2]; 588241675Suqs 589241675Suqs rval = ckinode(curinode, &idesc); 590241675Suqs if ((rval & (FOUND|ALTERED)) == (FOUND|ALTERED)) 591241675Suqs return 0; 592241675Suqs else if (rval & FOUND) { 593241675Suqs warnx("new name `%s' does not fit in slot %s\n", argv[2], argv[1]); 594241675Suqs return 1; 595241675Suqs } else { 596241675Suqs warnx("no %sth slot in current directory", argv[1]); 597241675Suqs return 1; 598241675Suqs } 599241675Suqs} 600241675Suqs 601241675Suqsstruct typemap { 602241675Suqs const char *typename; 603241675Suqs int typebits; 604241675Suqs} typenamemap[] = { 605241675Suqs {"file", IFREG}, 606241675Suqs {"dir", IFDIR}, 607241675Suqs {"socket", IFSOCK}, 608241675Suqs {"fifo", IFIFO}, 609241675Suqs}; 610241675Suqs 611241675SuqsCMDFUNCSTART(newtype) 612241675Suqs{ 613241675Suqs int type; 614241675Suqs struct typemap *tp; 615241675Suqs 616241675Suqs if (!checkactive()) 617241675Suqs return 1; 618241675Suqs type = curinode->di_mode & IFMT; 619241675Suqs for (tp = typenamemap; 620241675Suqs tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]; 621241675Suqs tp++) { 622241675Suqs if (!strcmp(argv[1], tp->typename)) { 623241675Suqs printf("setting type to %s\n", tp->typename); 624241675Suqs type = tp->typebits; 625241675Suqs break; 626241675Suqs } 627241675Suqs } 628241675Suqs if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) { 629241675Suqs warnx("type `%s' not known", argv[1]); 630241675Suqs warnx("try one of `file', `dir', `socket', `fifo'"); 631241675Suqs return 1; 632241675Suqs } 633241675Suqs curinode->di_mode &= ~IFMT; 634241675Suqs curinode->di_mode |= type; 635241675Suqs inodirty(); 636241675Suqs printactive(); 637241675Suqs return 0; 638241675Suqs} 639241675Suqs 640241675SuqsCMDFUNCSTART(chlen) 641241675Suqs{ 642241675Suqs int rval = 1; 643241675Suqs long len; 644241675Suqs char *cp; 645241675Suqs 646241675Suqs if (!checkactive()) 647241675Suqs return 1; 648241675Suqs 649241675Suqs len = strtol(argv[1], &cp, 0); 650241675Suqs if (cp == argv[1] || *cp != '\0' || len < 0) { 651241675Suqs warnx("bad length `%s'", argv[1]); 652241675Suqs return 1; 653241675Suqs } 654241675Suqs 655241675Suqs curinode->di_size = len; 656241675Suqs inodirty(); 657241675Suqs printactive(); 658241675Suqs return rval; 659241675Suqs} 660241675Suqs 661241675SuqsCMDFUNCSTART(chmode) 662241675Suqs{ 663241675Suqs int rval = 1; 664241675Suqs long modebits; 665241675Suqs char *cp; 666241675Suqs 667241675Suqs if (!checkactive()) 668241675Suqs return 1; 669241675Suqs 670241675Suqs modebits = strtol(argv[1], &cp, 8); 671241675Suqs if (cp == argv[1] || *cp != '\0' ) { 672241675Suqs warnx("bad modebits `%s'", argv[1]); 673241675Suqs return 1; 674241675Suqs } 675241675Suqs 676241675Suqs curinode->di_mode &= ~07777; 677241675Suqs curinode->di_mode |= modebits; 678241675Suqs inodirty(); 679241675Suqs printactive(); 680241675Suqs return rval; 681241675Suqs} 682241675Suqs 683241675SuqsCMDFUNCSTART(chaflags) 684241675Suqs{ 685241675Suqs int rval = 1; 686241675Suqs u_long flags; 687241675Suqs char *cp; 688241675Suqs 689241675Suqs if (!checkactive()) 690241675Suqs return 1; 691241675Suqs 692241675Suqs flags = strtoul(argv[1], &cp, 0); 693241675Suqs if (cp == argv[1] || *cp != '\0' ) { 694241675Suqs warnx("bad flags `%s'", argv[1]); 695241675Suqs return 1; 696241675Suqs } 697241675Suqs 698241675Suqs if (flags > UINT_MAX) { 699241675Suqs warnx("flags set beyond 32-bit range of field (%lx)\n", flags); 700241675Suqs return(1); 701241675Suqs } 702241675Suqs curinode->di_flags = flags; 703241675Suqs inodirty(); 704241675Suqs printactive(); 705241675Suqs return rval; 706241675Suqs} 707241675Suqs 708241675SuqsCMDFUNCSTART(chgen) 709241675Suqs{ 710241675Suqs int rval = 1; 711241675Suqs long gen; 712241675Suqs char *cp; 713241675Suqs 714241675Suqs if (!checkactive()) 715241675Suqs return 1; 716241675Suqs 717241675Suqs gen = strtol(argv[1], &cp, 0); 718241675Suqs if (cp == argv[1] || *cp != '\0' ) { 719241675Suqs warnx("bad gen `%s'", argv[1]); 720241675Suqs return 1; 721241675Suqs } 722241675Suqs 723241675Suqs if (gen > INT_MAX || gen < INT_MIN) { 724241675Suqs warnx("gen set beyond 32-bit range of field (%lx)\n", gen); 725241675Suqs return(1); 726241675Suqs } 727241675Suqs curinode->di_gen = gen; 728241675Suqs inodirty(); 729241675Suqs printactive(); 730241675Suqs return rval; 731241675Suqs} 732241675Suqs 733241675SuqsCMDFUNCSTART(linkcount) 734241675Suqs{ 735241675Suqs int rval = 1; 736241675Suqs int lcnt; 737241675Suqs char *cp; 738241675Suqs 739241675Suqs if (!checkactive()) 740241675Suqs return 1; 741241675Suqs 742241675Suqs lcnt = strtol(argv[1], &cp, 0); 743241675Suqs if (cp == argv[1] || *cp != '\0' ) { 744241675Suqs warnx("bad link count `%s'", argv[1]); 745241675Suqs return 1; 746241675Suqs } 747241675Suqs if (lcnt > USHRT_MAX || lcnt < 0) { 748241675Suqs warnx("max link count is %d\n", USHRT_MAX); 749241675Suqs return 1; 750241675Suqs } 751241675Suqs 752241675Suqs curinode->di_nlink = lcnt; 753241675Suqs inodirty(); 754241675Suqs printactive(); 755241675Suqs return rval; 756241675Suqs} 757241675Suqs 758241675SuqsCMDFUNCSTART(chowner) 759241675Suqs{ 760241675Suqs int rval = 1; 761241675Suqs unsigned long uid; 762241675Suqs char *cp; 763241675Suqs struct passwd *pwd; 764241675Suqs 765241675Suqs if (!checkactive()) 766241675Suqs return 1; 767241675Suqs 768241675Suqs uid = strtoul(argv[1], &cp, 0); 769241675Suqs if (cp == argv[1] || *cp != '\0' ) { 770241675Suqs /* try looking up name */ 771241675Suqs if ((pwd = getpwnam(argv[1]))) { 772241675Suqs uid = pwd->pw_uid; 773241675Suqs } else { 774241675Suqs warnx("bad uid `%s'", argv[1]); 775241675Suqs return 1; 776241675Suqs } 777241675Suqs } 778241675Suqs 779241675Suqs curinode->di_uid = uid; 780241675Suqs inodirty(); 781241675Suqs printactive(); 782241675Suqs return rval; 783241675Suqs} 784241675Suqs 785241675SuqsCMDFUNCSTART(chgroup) 786241675Suqs{ 787241675Suqs int rval = 1; 788241675Suqs unsigned long gid; 789241675Suqs char *cp; 790241675Suqs struct group *grp; 791241675Suqs 792241675Suqs if (!checkactive()) 793241675Suqs return 1; 794241675Suqs 795241675Suqs gid = strtoul(argv[1], &cp, 0); 796241675Suqs if (cp == argv[1] || *cp != '\0' ) { 797241675Suqs if ((grp = getgrnam(argv[1]))) { 798241675Suqs gid = grp->gr_gid; 799241675Suqs } else { 800241675Suqs warnx("bad gid `%s'", argv[1]); 801241675Suqs return 1; 802241675Suqs } 803241675Suqs } 804241675Suqs 805241675Suqs curinode->di_gid = gid; 806241675Suqs inodirty(); 807241675Suqs printactive(); 808241675Suqs return rval; 809241675Suqs} 810241675Suqs 811241675Suqsint 812241675Suqsdotime(name, rts) 813241675Suqs char *name; 814241675Suqs struct timespec *rts; 815241675Suqs{ 816241675Suqs char *p, *val; 817241675Suqs struct tm t; 818241675Suqs int32_t sec; 819241675Suqs int32_t nsec; 820241675Suqs p = strchr(name, '.'); 821241675Suqs if (p) { 822241675Suqs *p = '\0'; 823241675Suqs nsec = strtoul(++p, &val, 0); 824241675Suqs if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) { 825241675Suqs warnx("invalid nanoseconds"); 826241675Suqs goto badformat; 827241675Suqs } 828241675Suqs } else 829241675Suqs nsec = 0; 830241675Suqs if (strlen(name) != 14) { 831241675Suqsbadformat: 832241675Suqs warnx("date format: YYYYMMDDHHMMSS[.nsec]"); 833241675Suqs return 1; 834241675Suqs } 835241675Suqs 836241675Suqs for (p = name; *p; p++) 837241675Suqs if (*p < '0' || *p > '9') 838241675Suqs goto badformat; 839241675Suqs 840241675Suqs p = name; 841241675Suqs#define VAL() ((*p++) - '0') 842241675Suqs t.tm_year = VAL(); 843241675Suqs t.tm_year = VAL() + t.tm_year * 10; 844241675Suqs t.tm_year = VAL() + t.tm_year * 10; 845241675Suqs t.tm_year = VAL() + t.tm_year * 10 - 1900; 846241675Suqs t.tm_mon = VAL(); 847241675Suqs t.tm_mon = VAL() + t.tm_mon * 10 - 1; 848241675Suqs t.tm_mday = VAL(); 849241675Suqs t.tm_mday = VAL() + t.tm_mday * 10; 850241675Suqs t.tm_hour = VAL(); 851241675Suqs t.tm_hour = VAL() + t.tm_hour * 10; 852241675Suqs t.tm_min = VAL(); 853241675Suqs t.tm_min = VAL() + t.tm_min * 10; 854241675Suqs t.tm_sec = VAL(); 855241675Suqs t.tm_sec = VAL() + t.tm_sec * 10; 856241675Suqs t.tm_isdst = -1; 857241675Suqs 858241675Suqs sec = mktime(&t); 859241675Suqs if (sec == -1) { 860241675Suqs warnx("date/time out of range"); 861241675Suqs return 1; 862241675Suqs } 863241675Suqs rts->tv_sec = sec; 864241675Suqs rts->tv_nsec = nsec; 865241675Suqs return 0; 866241675Suqs} 867241675Suqs 868241675SuqsCMDFUNCSTART(chmtime) 869241675Suqs{ 870241675Suqs if (dotime(argv[1], &curinode->di_ctime)) 871241675Suqs return 1; 872241675Suqs inodirty(); 873241675Suqs printactive(); 874241675Suqs return 0; 875241675Suqs} 876241675Suqs 877241675SuqsCMDFUNCSTART(chatime) 878241675Suqs{ 879241675Suqs if (dotime(argv[1], &curinode->di_ctime)) 880241675Suqs return 1; 881241675Suqs inodirty(); 882241675Suqs printactive(); 883241675Suqs return 0; 884241675Suqs} 885241675Suqs 886241675SuqsCMDFUNCSTART(chctime) 887241675Suqs{ 888241675Suqs if (dotime(argv[1], &curinode->di_ctime)) 889241675Suqs return 1; 890241675Suqs inodirty(); 891241675Suqs printactive(); 892241675Suqs return 0; 893241675Suqs} 894241675Suqs