| File: | src/sbin/fsdb/fsdb.c |
| Warning: | line 284, column 4 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
| 1 | /* $OpenBSD: fsdb.c,v 1.34 2021/01/27 05:03:25 deraadt Exp $ */ | |||
| 2 | /* $NetBSD: fsdb.c,v 1.7 1997/01/11 06:50:53 lukem Exp $ */ | |||
| 3 | ||||
| 4 | /*- | |||
| 5 | * Copyright (c) 1996 The NetBSD Foundation, Inc. | |||
| 6 | * All rights reserved. | |||
| 7 | * | |||
| 8 | * This code is derived from software contributed to The NetBSD Foundation | |||
| 9 | * by John T. Kohl. | |||
| 10 | * | |||
| 11 | * Redistribution and use in source and binary forms, with or without | |||
| 12 | * modification, are permitted provided that the following conditions | |||
| 13 | * are met: | |||
| 14 | * 1. Redistributions of source code must retain the above copyright | |||
| 15 | * notice, this list of conditions and the following disclaimer. | |||
| 16 | * 2. Redistributions in binary form must reproduce the above copyright | |||
| 17 | * notice, this list of conditions and the following disclaimer in the | |||
| 18 | * documentation and/or other materials provided with the distribution. | |||
| 19 | * | |||
| 20 | * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS | |||
| 21 | * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | |||
| 22 | * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR | |||
| 23 | * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE | |||
| 24 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |||
| 25 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |||
| 26 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |||
| 27 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |||
| 28 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |||
| 29 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |||
| 30 | * POSSIBILITY OF SUCH DAMAGE. | |||
| 31 | */ | |||
| 32 | ||||
| 33 | #include <sys/stat.h> | |||
| 34 | #include <sys/time.h> | |||
| 35 | #include <sys/mount.h> | |||
| 36 | #include <ctype.h> | |||
| 37 | #include <err.h> | |||
| 38 | #include <fcntl.h> | |||
| 39 | #include <grp.h> | |||
| 40 | #include <histedit.h> | |||
| 41 | #include <limits.h> | |||
| 42 | #include <pwd.h> | |||
| 43 | #include <stdio.h> | |||
| 44 | #include <stdlib.h> | |||
| 45 | #include <string.h> | |||
| 46 | #include <unistd.h> | |||
| 47 | ||||
| 48 | #include <ufs/ufs/dinode.h> | |||
| 49 | #include <ufs/ufs/dir.h> | |||
| 50 | #include <ufs/ffs/fs.h> | |||
| 51 | ||||
| 52 | #include "fsdb.h" | |||
| 53 | #include "fsck.h" | |||
| 54 | #include "extern.h" | |||
| 55 | ||||
| 56 | extern char *__progname; /* from crt0.o */ | |||
| 57 | ||||
| 58 | int main(int, char *[]); | |||
| 59 | static void usage(void); | |||
| 60 | static int cmdloop(void); | |||
| 61 | static int helpfn(int, char *[]); | |||
| 62 | static char *prompt(EditLine *); | |||
| 63 | static int scannames(struct inodesc *); | |||
| 64 | static int dolookup(char *); | |||
| 65 | static int chinumfunc(struct inodesc *); | |||
| 66 | static int chnamefunc(struct inodesc *); | |||
| 67 | static int dotime(char *, time_t *, int32_t *); | |||
| 68 | ||||
| 69 | int returntosingle = 0; | |||
| 70 | union dinode *curinode; | |||
| 71 | ino_t curinum; | |||
| 72 | ||||
| 73 | struct inostatlist *inostathead; | |||
| 74 | ||||
| 75 | struct bufarea bufhead; /* head of list of other blks in filesys */ | |||
| 76 | struct bufarea sblk; /* file system superblock */ | |||
| 77 | struct bufarea asblk; /* alternate file system superblock */ | |||
| 78 | struct bufarea *pdirbp; /* current directory contents */ | |||
| 79 | struct bufarea *pbp; /* current inode block */ | |||
| 80 | ||||
| 81 | struct dups *duplist; /* head of dup list */ | |||
| 82 | struct dups *muldup; /* end of unique duplicate dup block numbers */ | |||
| 83 | ||||
| 84 | struct zlncnt *zlnhead; /* head of zero link count list */ | |||
| 85 | ||||
| 86 | struct inoinfo **inphead, **inpsort; | |||
| 87 | ||||
| 88 | extern long numdirs, listmax, inplast; | |||
| 89 | ||||
| 90 | long secsize; /* actual disk sector size */ | |||
| 91 | char nflag; /* assume a no response */ | |||
| 92 | char yflag; /* assume a yes response */ | |||
| 93 | daddr_t bflag; /* location of alternate super block */ | |||
| 94 | int debug; /* output debugging info */ | |||
| 95 | int cvtlevel; /* convert to newer file system format */ | |||
| 96 | char usedsoftdep; /* just fix soft dependency inconsistencies */ | |||
| 97 | int preen; /* just fix normal inconsistencies */ | |||
| 98 | char resolved; /* cleared if unresolved changes => not clean */ | |||
| 99 | char havesb; /* superblock has been read */ | |||
| 100 | char skipclean; /* skip clean file systems if preening */ | |||
| 101 | int fsmodified; /* 1 => write done to file system */ | |||
| 102 | int fsreadfd; /* file descriptor for reading file system */ | |||
| 103 | int fswritefd; /* file descriptor for writing file system */ | |||
| 104 | int rerun; /* rerun fsck. Only used in non-preen mode */ | |||
| 105 | ||||
| 106 | daddr_t maxfsblock; /* number of blocks in the file system */ | |||
| 107 | char *blockmap; /* ptr to primary blk allocation map */ | |||
| 108 | ino_t maxino; /* number of inodes in file system */ | |||
| 109 | ino_t lastino; /* last inode in use */ | |||
| 110 | ||||
| 111 | ino_t lfdir; /* lost & found directory inode number */ | |||
| 112 | ||||
| 113 | daddr_t n_blks; /* number of blocks in use */ | |||
| 114 | int64_t n_files; /* number of files in use */ | |||
| 115 | ||||
| 116 | struct ufs1_dinode ufs1_zino; | |||
| 117 | struct ufs2_dinode ufs2_zino; | |||
| 118 | ||||
| 119 | ||||
| 120 | static void | |||
| 121 | usage(void) | |||
| 122 | { | |||
| 123 | fprintf(stderr(&__sF[2]), "usage: %s [-d] -f fsname\n", __progname); | |||
| 124 | exit(1); | |||
| 125 | } | |||
| 126 | ||||
| 127 | /* | |||
| 128 | * We suck in lots of fsck code, and just pick & choose the stuff we want. | |||
| 129 | * | |||
| 130 | * fsreadfd is set up to read from the file system, fswritefd to write to | |||
| 131 | * the file system. | |||
| 132 | */ | |||
| 133 | int | |||
| 134 | main(int argc, char *argv[]) | |||
| 135 | { | |||
| 136 | int ch, rval; | |||
| 137 | char *fsys = NULL((void *)0); | |||
| 138 | ||||
| 139 | while (-1 != (ch = getopt(argc, argv, "f:d"))) { | |||
| ||||
| 140 | switch (ch) { | |||
| 141 | case 'f': | |||
| 142 | fsys = optarg; | |||
| 143 | break; | |||
| 144 | case 'd': | |||
| 145 | debug++; | |||
| 146 | break; | |||
| 147 | default: | |||
| 148 | usage(); | |||
| 149 | } | |||
| 150 | } | |||
| 151 | if (fsys == NULL((void *)0)) | |||
| 152 | usage(); | |||
| 153 | if (!setup(fsys, 1)) | |||
| 154 | errx(1, "cannot set up file system `%s'", fsys); | |||
| 155 | printf("Editing file system `%s'\nLast Mounted on %s\n", fsys, | |||
| 156 | sblock(*sblk.b_un.b_fs).fs_fsmnt); | |||
| 157 | rval = cmdloop(); | |||
| 158 | sblock(*sblk.b_un.b_fs).fs_clean = 0; /* mark it dirty */ | |||
| 159 | sbdirty()sblk.b_dirty = 1; | |||
| 160 | ckfini(0); | |||
| 161 | printf("*** FILE SYSTEM MARKED DIRTY\n"); | |||
| 162 | printf("*** BE SURE TO RUN FSCK TO CLEAN UP ANY DAMAGE\n"); | |||
| 163 | printf("*** IF IT WAS MOUNTED, RE-MOUNT WITH -u -o reload\n"); | |||
| 164 | exit(rval); | |||
| 165 | } | |||
| 166 | ||||
| 167 | #define CMDFUNC(func)static int func(int argc, char *argv[]) static int func(int argc, char *argv[]) | |||
| 168 | #define CMDFUNCSTART(func)static int func(int argc, char *argv[]) static int func(int argc, char *argv[]) | |||
| 169 | ||||
| 170 | CMDFUNC(helpfn)static int helpfn(int argc, char *argv[]); | |||
| 171 | CMDFUNC(focus)static int focus(int argc, char *argv[]); /* focus on inode */ | |||
| 172 | CMDFUNC(active)static int active(int argc, char *argv[]); /* print active inode */ | |||
| 173 | CMDFUNC(focusname)static int focusname(int argc, char *argv[]); /* focus by name */ | |||
| 174 | CMDFUNC(zapi)static int zapi(int argc, char *argv[]); /* clear inode */ | |||
| 175 | CMDFUNC(uplink)static int uplink(int argc, char *argv[]); /* incr link */ | |||
| 176 | CMDFUNC(downlink)static int downlink(int argc, char *argv[]); /* decr link */ | |||
| 177 | CMDFUNC(linkcount)static int linkcount(int argc, char *argv[]); /* set link count */ | |||
| 178 | CMDFUNC(quit)static int quit(int argc, char *argv[]); /* quit */ | |||
| 179 | CMDFUNC(ls)static int ls(int argc, char *argv[]); /* list directory */ | |||
| 180 | CMDFUNC(rm)static int rm(int argc, char *argv[]); /* remove name */ | |||
| 181 | CMDFUNC(ln)static int ln(int argc, char *argv[]); /* add name */ | |||
| 182 | CMDFUNC(newtype)static int newtype(int argc, char *argv[]); /* change type */ | |||
| 183 | CMDFUNC(chmode)static int chmode(int argc, char *argv[]); /* change mode */ | |||
| 184 | CMDFUNC(chlen)static int chlen(int argc, char *argv[]); /* change length */ | |||
| 185 | CMDFUNC(chaflags)static int chaflags(int argc, char *argv[]); /* change flags */ | |||
| 186 | CMDFUNC(chgen)static int chgen(int argc, char *argv[]); /* change generation */ | |||
| 187 | CMDFUNC(chowner)static int chowner(int argc, char *argv[]); /* change owner */ | |||
| 188 | CMDFUNC(chgroup)static int chgroup(int argc, char *argv[]); /* Change group */ | |||
| 189 | CMDFUNC(back)static int back(int argc, char *argv[]); /* pop back to last ino */ | |||
| 190 | CMDFUNC(chmtime)static int chmtime(int argc, char *argv[]); /* Change mtime */ | |||
| 191 | CMDFUNC(chctime)static int chctime(int argc, char *argv[]); /* Change ctime */ | |||
| 192 | CMDFUNC(chatime)static int chatime(int argc, char *argv[]); /* Change atime */ | |||
| 193 | CMDFUNC(chinum)static int chinum(int argc, char *argv[]); /* Change inode # of dirent */ | |||
| 194 | CMDFUNC(chname)static int chname(int argc, char *argv[]); /* Change dirname of dirent */ | |||
| 195 | ||||
| 196 | static struct cmdtable cmds[] = { | |||
| 197 | { "help", "Print out help", 1, 1, helpfn }, | |||
| 198 | { "?", "Print out help", 1, 1, helpfn }, | |||
| 199 | { "inode", "Set active inode to INUM", 2, 2, focus }, | |||
| 200 | { "clri", "Clear inode INUM", 2, 2, zapi }, | |||
| 201 | { "lookup", "Set active inode by looking up NAME", 2, 2, focusname }, | |||
| 202 | { "cd", "Set active inode by looking up NAME", 2, 2, focusname }, | |||
| 203 | { "back", "Go to previous active inode", 1, 1, back }, | |||
| 204 | { "active", "Print active inode", 1, 1, active }, | |||
| 205 | { "print", "Print active inode", 1, 1, active }, | |||
| 206 | { "uplink", "Increment link count", 1, 1, uplink }, | |||
| 207 | { "downlink", "Decrement link count", 1, 1, downlink }, | |||
| 208 | { "linkcount", "Set link count to COUNT", 2, 2, linkcount }, | |||
| 209 | { "ls", "List current inode as directory", 1, 1, ls }, | |||
| 210 | { "rm", "Remove NAME from current inode directory", 2, 2, rm }, | |||
| 211 | { "del", "Remove NAME from current inode directory", 2, 2, rm }, | |||
| 212 | { "ln", "Hardlink INO into current inode directory as NAME", 3, 3, ln }, | |||
| 213 | { "chinum", "Change dir entry number INDEX to INUM", 3, 3, chinum }, | |||
| 214 | { "chname", "Change dir entry number INDEX to NAME", 3, 3, chname }, | |||
| 215 | { "chtype", "Change type of current inode to TYPE", 2, 2, newtype }, | |||
| 216 | { "chmod", "Change mode of current inode to MODE", 2, 2, chmode }, | |||
| 217 | { "chown", "Change owner of current inode to OWNER", 2, 2, chowner }, | |||
| 218 | { "chlen", "Change length of current inode to LENGTH", 2, 2, chlen }, | |||
| 219 | { "chgrp", "Change group of current inode to GROUP", 2, 2, chgroup }, | |||
| 220 | { "chflags", "Change flags of current inode to FLAGS", 2, 2, chaflags }, | |||
| 221 | { "chgen", "Change generation number of current inode to GEN", 2, 2, chgen }, | |||
| 222 | { "mtime", "Change mtime of current inode to MTIME", 2, 2, chmtime }, | |||
| 223 | { "ctime", "Change ctime of current inode to CTIME", 2, 2, chctime }, | |||
| 224 | { "atime", "Change atime of current inode to ATIME", 2, 2, chatime }, | |||
| 225 | { "quit", "Exit", 1, 1, quit }, | |||
| 226 | { "q", "Exit", 1, 1, quit }, | |||
| 227 | { "exit", "Exit", 1, 1, quit }, | |||
| 228 | { NULL((void *)0), 0, 0, 0 }, | |||
| 229 | }; | |||
| 230 | ||||
| 231 | static int | |||
| 232 | helpfn(int argc, char *argv[]) | |||
| 233 | { | |||
| 234 | struct cmdtable *cmdtp; | |||
| 235 | ||||
| 236 | printf("Commands are:\n%-10s %5s %5s %s\n", | |||
| 237 | "command", "min argc", "max argc", "what"); | |||
| 238 | ||||
| 239 | for (cmdtp = cmds; cmdtp->cmd; cmdtp++) | |||
| 240 | printf("%-10s %5u %5u %s\n", | |||
| 241 | cmdtp->cmd, cmdtp->minargc, cmdtp->maxargc, cmdtp->helptxt); | |||
| 242 | return 0; | |||
| 243 | } | |||
| 244 | ||||
| 245 | static char * | |||
| 246 | prompt(EditLine *el) | |||
| 247 | { | |||
| 248 | static char pstring[64]; | |||
| 249 | ||||
| 250 | snprintf(pstring, sizeof(pstring), "fsdb (inum: %llu)> ", | |||
| 251 | (unsigned long long)curinum); | |||
| 252 | return pstring; | |||
| 253 | } | |||
| 254 | ||||
| 255 | ||||
| 256 | static int | |||
| 257 | cmdloop(void) | |||
| 258 | { | |||
| 259 | char *line = NULL((void *)0); | |||
| 260 | const char *elline; | |||
| 261 | int cmd_argc, rval = 0, known; | |||
| 262 | #define scratchknown known | |||
| 263 | char **cmd_argv; | |||
| 264 | struct cmdtable *cmdp; | |||
| 265 | History *hist; | |||
| 266 | EditLine *elptr; | |||
| 267 | HistEvent hev; | |||
| 268 | ||||
| 269 | curinode = ginode(ROOTINO((ufsino_t)2)); | |||
| 270 | curinum = ROOTINO((ufsino_t)2); | |||
| 271 | printactive(); | |||
| 272 | ||||
| 273 | hist = history_init(); | |||
| 274 | history(hist, &hev, H_SETSIZE1, 100); /* 100 elt history buffer */ | |||
| 275 | ||||
| 276 | elptr = el_init(__progname, stdin(&__sF[0]), stdout(&__sF[1]), stderr(&__sF[2])); | |||
| 277 | el_set(elptr, EL_EDITOR2, "emacs"); | |||
| 278 | el_set(elptr, EL_PROMPT0, prompt); | |||
| 279 | el_set(elptr, EL_HIST10, history, hist); | |||
| 280 | el_source(elptr, NULL((void *)0)); | |||
| 281 | ||||
| 282 | while ((elline = el_gets(elptr, &scratchknown)) != NULL((void *)0) && scratchknown != 0) { | |||
| 283 | if (debug) | |||
| 284 | printf("command `%s'\n", line); | |||
| ||||
| 285 | ||||
| 286 | history(hist, &hev, H_ENTER10, elline); | |||
| 287 | ||||
| 288 | line = strdup(elline); | |||
| 289 | if (line == NULL((void *)0)) | |||
| 290 | errx(1, "out of memory"); | |||
| 291 | cmd_argv = crack(line, &cmd_argc); | |||
| 292 | if (cmd_argc) { | |||
| 293 | /* | |||
| 294 | * el_parse returns -1 to signal that it's not been handled | |||
| 295 | * internally. | |||
| 296 | */ | |||
| 297 | if (el_parse(elptr, cmd_argc, (const char **)cmd_argv) != -1) | |||
| 298 | continue; | |||
| 299 | known = 0; | |||
| 300 | for (cmdp = cmds; cmdp->cmd; cmdp++) { | |||
| 301 | if (!strcmp(cmdp->cmd, cmd_argv[0])) { | |||
| 302 | if (cmd_argc >= cmdp->minargc && | |||
| 303 | cmd_argc <= cmdp->maxargc) | |||
| 304 | rval = (*cmdp->handler)(cmd_argc, | |||
| 305 | cmd_argv); | |||
| 306 | else | |||
| 307 | rval = argcount(cmdp, | |||
| 308 | cmd_argc, cmd_argv); | |||
| 309 | known = 1; | |||
| 310 | break; | |||
| 311 | } | |||
| 312 | } | |||
| 313 | if (!known) { | |||
| 314 | warnx("unknown command `%s'", cmd_argv[0]); | |||
| 315 | rval = 1; | |||
| 316 | } | |||
| 317 | } else | |||
| 318 | rval = 0; | |||
| 319 | free(line); | |||
| 320 | if (rval
| |||
| 321 | return rval; | |||
| 322 | if (rval
| |||
| 323 | warnx("rval was %d", rval); | |||
| 324 | } | |||
| 325 | el_end(elptr); | |||
| 326 | history_end(hist); | |||
| 327 | return rval; | |||
| 328 | } | |||
| 329 | ||||
| 330 | static ino_t ocurrent; | |||
| 331 | ||||
| 332 | #define GETINUM(ac,inum)inum = strtoull(argv[ac], &cp, 0); if (inum < ((ufsino_t )2) || inum > maxino || cp == argv[ac] || *cp != '\0' ) { printf ("inode %llu out of range; range is [%llu,%llu]\n", (unsigned long long)inum, (unsigned long long)((ufsino_t)2), (unsigned long long)maxino); return 1; } inum = strtoull(argv[ac], &cp, 0); \ | |||
| 333 | if (inum < ROOTINO((ufsino_t)2) || inum > maxino || cp == argv[ac] || *cp != '\0' ) { \ | |||
| 334 | printf("inode %llu out of range; range is [%llu,%llu]\n", \ | |||
| 335 | (unsigned long long)inum, (unsigned long long)ROOTINO((ufsino_t)2), \ | |||
| 336 | (unsigned long long)maxino); \ | |||
| 337 | return 1; \ | |||
| 338 | } | |||
| 339 | ||||
| 340 | /* | |||
| 341 | * Focus on given inode number | |||
| 342 | */ | |||
| 343 | CMDFUNCSTART(focus)static int focus(int argc, char *argv[]) | |||
| 344 | { | |||
| 345 | ino_t inum; | |||
| 346 | char *cp; | |||
| 347 | ||||
| 348 | GETINUM(1,inum)inum = strtoull(argv[1], &cp, 0); if (inum < ((ufsino_t )2) || inum > maxino || cp == argv[1] || *cp != '\0' ) { printf ("inode %llu out of range; range is [%llu,%llu]\n", (unsigned long long)inum, (unsigned long long)((ufsino_t)2), (unsigned long long)maxino); return 1; }; | |||
| 349 | curinode = ginode(inum); | |||
| 350 | ocurrent = curinum; | |||
| 351 | curinum = inum; | |||
| 352 | printactive(); | |||
| 353 | return 0; | |||
| 354 | } | |||
| 355 | ||||
| 356 | CMDFUNCSTART(back)static int back(int argc, char *argv[]) | |||
| 357 | { | |||
| 358 | curinum = ocurrent; | |||
| 359 | curinode = ginode(curinum); | |||
| 360 | printactive(); | |||
| 361 | return 0; | |||
| 362 | } | |||
| 363 | ||||
| 364 | CMDFUNCSTART(zapi)static int zapi(int argc, char *argv[]) | |||
| 365 | { | |||
| 366 | ino_t inum; | |||
| 367 | union dinode *dp; | |||
| 368 | char *cp; | |||
| 369 | ||||
| 370 | GETINUM(1,inum)inum = strtoull(argv[1], &cp, 0); if (inum < ((ufsino_t )2) || inum > maxino || cp == argv[1] || *cp != '\0' ) { printf ("inode %llu out of range; range is [%llu,%llu]\n", (unsigned long long)inum, (unsigned long long)((ufsino_t)2), (unsigned long long)maxino); return 1; }; | |||
| 371 | dp = ginode(inum); | |||
| 372 | clearinode(dp)if ((*sblk.b_un.b_fs).fs_magic == 0x011954) { (dp)->dp1 = ufs1_zino ; } else { (dp)->dp2 = ufs2_zino; }; | |||
| 373 | inodirty(); | |||
| 374 | if (curinode) /* re-set after potential change */ | |||
| 375 | curinode = ginode(curinum); | |||
| 376 | return 0; | |||
| 377 | } | |||
| 378 | ||||
| 379 | CMDFUNCSTART(active)static int active(int argc, char *argv[]) | |||
| 380 | { | |||
| 381 | printactive(); | |||
| 382 | return 0; | |||
| 383 | } | |||
| 384 | ||||
| 385 | ||||
| 386 | CMDFUNCSTART(quit)static int quit(int argc, char *argv[]) | |||
| 387 | { | |||
| 388 | return -1; | |||
| 389 | } | |||
| 390 | ||||
| 391 | CMDFUNCSTART(uplink)static int uplink(int argc, char *argv[]) | |||
| 392 | { | |||
| 393 | if (!checkactive()) | |||
| 394 | return 1; | |||
| 395 | DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) + 1)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_nlink = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? ( curinode)->dp1.di_nlink : (curinode)->dp2.di_nlink) + 1 ); else (curinode)->dp2.di_nlink = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1.di_nlink : (curinode)-> dp2.di_nlink) + 1); } while (0); | |||
| 396 | printf("inode %llu link count now %d\n", | |||
| 397 | (unsigned long long)curinum, DIP(curinode, di_nlink)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1 .di_nlink : (curinode)->dp2.di_nlink)); | |||
| 398 | inodirty(); | |||
| 399 | return 0; | |||
| 400 | } | |||
| 401 | ||||
| 402 | CMDFUNCSTART(downlink)static int downlink(int argc, char *argv[]) | |||
| 403 | { | |||
| 404 | if (!checkactive()) | |||
| 405 | return 1; | |||
| 406 | DIP_SET(curinode, di_nlink, DIP(curinode, di_nlink) - 1)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_nlink = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? ( curinode)->dp1.di_nlink : (curinode)->dp2.di_nlink) - 1 ); else (curinode)->dp2.di_nlink = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1.di_nlink : (curinode)-> dp2.di_nlink) - 1); } while (0); | |||
| 407 | printf("inode %llu link count now %d\n", | |||
| 408 | (unsigned long long)curinum, DIP(curinode, di_nlink)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1 .di_nlink : (curinode)->dp2.di_nlink)); | |||
| 409 | inodirty(); | |||
| 410 | return 0; | |||
| 411 | } | |||
| 412 | ||||
| 413 | static const char *typename[] = { | |||
| 414 | "unknown", | |||
| 415 | "fifo", | |||
| 416 | "char special", | |||
| 417 | "unregistered #3", | |||
| 418 | "directory", | |||
| 419 | "unregistered #5", | |||
| 420 | "blk special", | |||
| 421 | "unregistered #7", | |||
| 422 | "regular", | |||
| 423 | "unregistered #9", | |||
| 424 | "symlink", | |||
| 425 | "unregistered #11", | |||
| 426 | "socket", | |||
| 427 | "unregistered #13", | |||
| 428 | "whiteout", | |||
| 429 | }; | |||
| 430 | ||||
| 431 | static int slot; | |||
| 432 | ||||
| 433 | static int | |||
| 434 | scannames(struct inodesc *idesc) | |||
| 435 | { | |||
| 436 | struct direct *dirp = idesc->id_dirp; | |||
| 437 | ||||
| 438 | printf("slot %d ino %llu reclen %d: %s, `%.*s'\n", | |||
| 439 | slot++, (unsigned long long)dirp->d_ino, dirp->d_reclen, | |||
| 440 | typename[dirp->d_type], dirp->d_namlen, dirp->d_name); | |||
| 441 | return (KEEPON0x04); | |||
| 442 | } | |||
| 443 | ||||
| 444 | CMDFUNCSTART(ls)static int ls(int argc, char *argv[]) | |||
| 445 | { | |||
| 446 | struct inodesc idesc; | |||
| 447 | checkactivedir(); /* let it go on anyway */ | |||
| 448 | ||||
| 449 | slot = 0; | |||
| 450 | idesc.id_number = curinum; | |||
| 451 | idesc.id_func = scannames; | |||
| 452 | idesc.id_type = DATA1; | |||
| 453 | idesc.id_fix = IGNORE; | |||
| 454 | ckinode(curinode, &idesc); | |||
| 455 | curinode = ginode(curinum); | |||
| 456 | ||||
| 457 | return 0; | |||
| 458 | } | |||
| 459 | ||||
| 460 | static int | |||
| 461 | dolookup(char *name) | |||
| 462 | { | |||
| 463 | struct inodesc idesc; | |||
| 464 | ||||
| 465 | if (!checkactivedir()) | |||
| 466 | return 0; | |||
| 467 | idesc.id_number = curinum; | |||
| 468 | idesc.id_func = findino; | |||
| 469 | idesc.id_name = name; | |||
| 470 | idesc.id_type = DATA1; | |||
| 471 | idesc.id_fix = IGNORE; | |||
| 472 | if (ckinode(curinode, &idesc) & FOUND0x10) { | |||
| 473 | curinum = idesc.id_parent; | |||
| 474 | curinode = ginode(curinum); | |||
| 475 | printactive(); | |||
| 476 | return 1; | |||
| 477 | } else { | |||
| 478 | warnx("name `%s' not found in current inode directory", name); | |||
| 479 | return 0; | |||
| 480 | } | |||
| 481 | } | |||
| 482 | ||||
| 483 | CMDFUNCSTART(focusname)static int focusname(int argc, char *argv[]) | |||
| 484 | { | |||
| 485 | char *p, *val; | |||
| 486 | ||||
| 487 | if (!checkactive()) | |||
| 488 | return 1; | |||
| 489 | ||||
| 490 | ocurrent = curinum; | |||
| 491 | ||||
| 492 | if (argv[1][0] == '/') { | |||
| 493 | curinum = ROOTINO((ufsino_t)2); | |||
| 494 | curinode = ginode(ROOTINO((ufsino_t)2)); | |||
| 495 | } else { | |||
| 496 | if (!checkactivedir()) | |||
| 497 | return 1; | |||
| 498 | } | |||
| 499 | for (p = argv[1]; p != NULL((void *)0);) { | |||
| 500 | while ((val = strsep(&p, "/")) != NULL((void *)0) && *val == '\0') | |||
| 501 | continue; | |||
| 502 | if (val) { | |||
| 503 | printf("component `%s': ", val); | |||
| 504 | fflush(stdout(&__sF[1])); | |||
| 505 | if (!dolookup(val)) { | |||
| 506 | curinode = ginode(curinum); | |||
| 507 | return(1); | |||
| 508 | } | |||
| 509 | } | |||
| 510 | } | |||
| 511 | return 0; | |||
| 512 | } | |||
| 513 | ||||
| 514 | CMDFUNCSTART(ln)static int ln(int argc, char *argv[]) | |||
| 515 | { | |||
| 516 | ino_t inum; | |||
| 517 | int rval; | |||
| 518 | char *cp; | |||
| 519 | ||||
| 520 | GETINUM(1,inum)inum = strtoull(argv[1], &cp, 0); if (inum < ((ufsino_t )2) || inum > maxino || cp == argv[1] || *cp != '\0' ) { printf ("inode %llu out of range; range is [%llu,%llu]\n", (unsigned long long)inum, (unsigned long long)((ufsino_t)2), (unsigned long long)maxino); return 1; }; | |||
| 521 | ||||
| 522 | if (!checkactivedir()) | |||
| 523 | return 1; | |||
| 524 | rval = makeentry(curinum, inum, argv[2]); | |||
| 525 | if (rval) | |||
| 526 | printf("Ino %llu entered as `%s'\n", | |||
| 527 | (unsigned long long)inum, argv[2]); | |||
| 528 | else | |||
| 529 | printf("could not enter name? weird.\n"); | |||
| 530 | curinode = ginode(curinum); | |||
| 531 | return rval; | |||
| 532 | } | |||
| 533 | ||||
| 534 | CMDFUNCSTART(rm)static int rm(int argc, char *argv[]) | |||
| 535 | { | |||
| 536 | int rval; | |||
| 537 | ||||
| 538 | if (!checkactivedir()) | |||
| 539 | return 1; | |||
| 540 | rval = changeino(curinum, argv[1], 0); | |||
| 541 | if (rval & ALTERED0x08) { | |||
| 542 | printf("Name `%s' removed\n", argv[1]); | |||
| 543 | return 0; | |||
| 544 | } else { | |||
| 545 | printf("could not remove name? weird.\n"); | |||
| 546 | return 1; | |||
| 547 | } | |||
| 548 | } | |||
| 549 | ||||
| 550 | static long slotcount, desired; | |||
| 551 | ||||
| 552 | static int | |||
| 553 | chinumfunc(struct inodesc *idesc) | |||
| 554 | { | |||
| 555 | struct direct *dirp = idesc->id_dirp; | |||
| 556 | ||||
| 557 | if (slotcount++ == desired) { | |||
| 558 | dirp->d_ino = idesc->id_parent; | |||
| 559 | return STOP0x01|ALTERED0x08|FOUND0x10; | |||
| 560 | } | |||
| 561 | return KEEPON0x04; | |||
| 562 | } | |||
| 563 | ||||
| 564 | CMDFUNCSTART(chinum)static int chinum(int argc, char *argv[]) | |||
| 565 | { | |||
| 566 | char *cp; | |||
| 567 | ino_t inum; | |||
| 568 | struct inodesc idesc; | |||
| 569 | ||||
| 570 | slotcount = 0; | |||
| 571 | if (!checkactivedir()) | |||
| 572 | return 1; | |||
| 573 | GETINUM(2,inum)inum = strtoull(argv[2], &cp, 0); if (inum < ((ufsino_t )2) || inum > maxino || cp == argv[2] || *cp != '\0' ) { printf ("inode %llu out of range; range is [%llu,%llu]\n", (unsigned long long)inum, (unsigned long long)((ufsino_t)2), (unsigned long long)maxino); return 1; }; | |||
| 574 | ||||
| 575 | desired = strtol(argv[1], &cp, 0); | |||
| 576 | if (cp == argv[1] || *cp != '\0' || desired < 0) { | |||
| 577 | printf("invalid slot number `%s'\n", argv[1]); | |||
| 578 | return 1; | |||
| 579 | } | |||
| 580 | ||||
| 581 | idesc.id_number = curinum; | |||
| 582 | idesc.id_func = chinumfunc; | |||
| 583 | idesc.id_fix = IGNORE; | |||
| 584 | idesc.id_type = DATA1; | |||
| 585 | idesc.id_parent = inum; /* XXX convenient hiding place */ | |||
| 586 | ||||
| 587 | if (ckinode(curinode, &idesc) & FOUND0x10) | |||
| 588 | return 0; | |||
| 589 | else { | |||
| 590 | warnx("no %sth slot in current directory", argv[1]); | |||
| 591 | return 1; | |||
| 592 | } | |||
| 593 | } | |||
| 594 | ||||
| 595 | static int | |||
| 596 | chnamefunc(struct inodesc *idesc) | |||
| 597 | { | |||
| 598 | struct direct *dirp = idesc->id_dirp; | |||
| 599 | struct direct testdir; | |||
| 600 | ||||
| 601 | if (slotcount++ == desired) { | |||
| 602 | /* will name fit? */ | |||
| 603 | testdir.d_namlen = strlen(idesc->id_name); | |||
| 604 | if (DIRSIZ(NEWDIRFMT, &testdir)((0) ? ((sizeof(struct direct) - (255 +1)) + (((&testdir) ->d_type+1 + 3) &~ 3)) : ((sizeof(struct direct) - (255 +1)) + (((&testdir)->d_namlen+1 + 3) &~ 3))) <= dirp->d_reclen) { | |||
| 605 | dirp->d_namlen = testdir.d_namlen; | |||
| 606 | strlcpy(dirp->d_name, idesc->id_name, sizeof dirp->d_name); | |||
| 607 | return STOP0x01|ALTERED0x08|FOUND0x10; | |||
| 608 | } else | |||
| 609 | return STOP0x01|FOUND0x10; /* won't fit, so give up */ | |||
| 610 | } | |||
| 611 | return KEEPON0x04; | |||
| 612 | } | |||
| 613 | ||||
| 614 | CMDFUNCSTART(chname)static int chname(int argc, char *argv[]) | |||
| 615 | { | |||
| 616 | int rval; | |||
| 617 | char *cp; | |||
| 618 | struct inodesc idesc; | |||
| 619 | ||||
| 620 | slotcount = 0; | |||
| 621 | if (!checkactivedir()) | |||
| 622 | return 1; | |||
| 623 | ||||
| 624 | desired = strtoul(argv[1], &cp, 0); | |||
| 625 | if (cp == argv[1] || *cp != '\0') { | |||
| 626 | printf("invalid slot number `%s'\n", argv[1]); | |||
| 627 | return 1; | |||
| 628 | } | |||
| 629 | ||||
| 630 | idesc.id_number = curinum; | |||
| 631 | idesc.id_func = chnamefunc; | |||
| 632 | idesc.id_fix = IGNORE; | |||
| 633 | idesc.id_type = DATA1; | |||
| 634 | idesc.id_name = argv[2]; | |||
| 635 | ||||
| 636 | rval = ckinode(curinode, &idesc); | |||
| 637 | if ((rval & (FOUND0x10|ALTERED0x08)) == (FOUND0x10|ALTERED0x08)) | |||
| 638 | return 0; | |||
| 639 | else if (rval & FOUND0x10) { | |||
| 640 | warnx("new name `%s' does not fit in slot %s", argv[2], argv[1]); | |||
| 641 | return 1; | |||
| 642 | } else { | |||
| 643 | warnx("no %sth slot in current directory", argv[1]); | |||
| 644 | return 1; | |||
| 645 | } | |||
| 646 | } | |||
| 647 | ||||
| 648 | static struct typemap { | |||
| 649 | const char *typename; | |||
| 650 | int typebits; | |||
| 651 | } typenamemap[] = { | |||
| 652 | {"file", IFREG0100000}, | |||
| 653 | {"dir", IFDIR0040000}, | |||
| 654 | {"socket", IFSOCK0140000}, | |||
| 655 | {"fifo", IFIFO0010000}, | |||
| 656 | }; | |||
| 657 | ||||
| 658 | CMDFUNCSTART(newtype)static int newtype(int argc, char *argv[]) | |||
| 659 | { | |||
| 660 | int type; | |||
| 661 | struct typemap *tp; | |||
| 662 | ||||
| 663 | if (!checkactive()) | |||
| 664 | return 1; | |||
| 665 | type = DIP(curinode, di_mode)(((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1 .di_mode : (curinode)->dp2.di_mode) & IFMT0170000; | |||
| 666 | for (tp = typenamemap; | |||
| 667 | tp < &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]; | |||
| 668 | tp++) { | |||
| 669 | if (!strcmp(argv[1], tp->typename)) { | |||
| 670 | printf("setting type to %s\n", tp->typename); | |||
| 671 | type = tp->typebits; | |||
| 672 | break; | |||
| 673 | } | |||
| 674 | } | |||
| 675 | if (tp == &typenamemap[sizeof(typenamemap)/sizeof(*typenamemap)]) { | |||
| 676 | warnx("type `%s' not known", argv[1]); | |||
| 677 | warnx("try one of `file', `dir', `socket', `fifo'"); | |||
| 678 | return 1; | |||
| 679 | } | |||
| 680 | DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~IFMT)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode )->dp1.di_mode : (curinode)->dp2.di_mode) & ~0170000 ); else (curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2 .di_mode) & ~0170000); } while (0); | |||
| 681 | DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | type)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode )->dp1.di_mode : (curinode)->dp2.di_mode) | type); else (curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2. di_mode) | type); } while (0); | |||
| 682 | inodirty(); | |||
| 683 | printactive(); | |||
| 684 | return 0; | |||
| 685 | } | |||
| 686 | ||||
| 687 | CMDFUNCSTART(chmode)static int chmode(int argc, char *argv[]) | |||
| 688 | { | |||
| 689 | int rval = 1; | |||
| 690 | long modebits; | |||
| 691 | char *cp; | |||
| 692 | ||||
| 693 | if (!checkactive()) | |||
| 694 | return 1; | |||
| 695 | ||||
| 696 | modebits = strtol(argv[1], &cp, 8); | |||
| 697 | if (cp == argv[1] || *cp != '\0' ) { | |||
| 698 | warnx("bad modebits `%s'", argv[1]); | |||
| 699 | return 1; | |||
| 700 | } | |||
| 701 | ||||
| 702 | DIP_SET(curinode, di_mode, DIP(curinode, di_mode) & ~07777)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode )->dp1.di_mode : (curinode)->dp2.di_mode) & ~07777) ; else (curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2 .di_mode) & ~07777); } while (0); | |||
| 703 | DIP_SET(curinode, di_mode, DIP(curinode, di_mode) | modebits)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode )->dp1.di_mode : (curinode)->dp2.di_mode) | modebits); else (curinode)->dp2.di_mode = ((((*sblk.b_un.b_fs).fs_magic == 0x011954) ? (curinode)->dp1.di_mode : (curinode)->dp2. di_mode) | modebits); } while (0); | |||
| 704 | inodirty(); | |||
| 705 | printactive(); | |||
| 706 | return rval; | |||
| 707 | } | |||
| 708 | ||||
| 709 | CMDFUNCSTART(chlen)static int chlen(int argc, char *argv[]) | |||
| 710 | { | |||
| 711 | int rval = 1; | |||
| 712 | long len; | |||
| 713 | char *cp; | |||
| 714 | ||||
| 715 | if (!checkactive()) | |||
| 716 | return 1; | |||
| 717 | ||||
| 718 | len = strtol(argv[1], &cp, 0); | |||
| 719 | if (cp == argv[1] || *cp != '\0' || len < 0) { | |||
| 720 | warnx("bad length '%s'", argv[1]); | |||
| 721 | return 1; | |||
| 722 | } | |||
| 723 | ||||
| 724 | DIP_SET(curinode, di_size, len)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_size = (len); else (curinode)->dp2.di_size = (len); } while (0); | |||
| 725 | inodirty(); | |||
| 726 | printactive(); | |||
| 727 | return rval; | |||
| 728 | } | |||
| 729 | ||||
| 730 | CMDFUNCSTART(chaflags)static int chaflags(int argc, char *argv[]) | |||
| 731 | { | |||
| 732 | int rval = 1; | |||
| 733 | u_long flags; | |||
| 734 | char *cp; | |||
| 735 | ||||
| 736 | if (!checkactive()) | |||
| 737 | return 1; | |||
| 738 | ||||
| 739 | flags = strtoul(argv[1], &cp, 0); | |||
| 740 | if (cp == argv[1] || *cp != '\0' ) { | |||
| 741 | warnx("bad flags `%s'", argv[1]); | |||
| 742 | return 1; | |||
| 743 | } | |||
| 744 | ||||
| 745 | if (flags > UINT_MAX(2147483647 *2U +1U)) { | |||
| 746 | warnx("flags set beyond 32-bit range of field (%lx)", flags); | |||
| 747 | return(1); | |||
| 748 | } | |||
| 749 | DIP_SET(curinode, di_flags, flags)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_flags = (flags); else (curinode)->dp2.di_flags = (flags ); } while (0); | |||
| 750 | inodirty(); | |||
| 751 | printactive(); | |||
| 752 | return rval; | |||
| 753 | } | |||
| 754 | ||||
| 755 | CMDFUNCSTART(chgen)static int chgen(int argc, char *argv[]) | |||
| 756 | { | |||
| 757 | int rval = 1; | |||
| 758 | long long gen; | |||
| 759 | char *cp; | |||
| 760 | ||||
| 761 | if (!checkactive()) | |||
| 762 | return 1; | |||
| 763 | ||||
| 764 | gen = strtoll(argv[1], &cp, 0); | |||
| 765 | if (cp == argv[1] || *cp != '\0' ) { | |||
| 766 | warnx("bad gen `%s'", argv[1]); | |||
| 767 | return 1; | |||
| 768 | } | |||
| 769 | ||||
| 770 | if (gen > UINT_MAX(2147483647 *2U +1U) || gen < 0) { | |||
| 771 | warnx("gen set beyond 32-bit range of field (%llx)", gen); | |||
| 772 | return(1); | |||
| 773 | } | |||
| 774 | DIP_SET(curinode, di_gen, gen)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_gen = (gen); else (curinode)->dp2.di_gen = (gen); } while (0); | |||
| 775 | inodirty(); | |||
| 776 | printactive(); | |||
| 777 | return rval; | |||
| 778 | } | |||
| 779 | ||||
| 780 | CMDFUNCSTART(linkcount)static int linkcount(int argc, char *argv[]) | |||
| 781 | { | |||
| 782 | int rval = 1; | |||
| 783 | int lcnt; | |||
| 784 | char *cp; | |||
| 785 | ||||
| 786 | if (!checkactive()) | |||
| 787 | return 1; | |||
| 788 | ||||
| 789 | lcnt = strtol(argv[1], &cp, 0); | |||
| 790 | if (cp == argv[1] || *cp != '\0' ) { | |||
| 791 | warnx("bad link count `%s'", argv[1]); | |||
| 792 | return 1; | |||
| 793 | } | |||
| 794 | if (lcnt > USHRT_MAX(32767 *2 +1) || lcnt < 0) { | |||
| 795 | warnx("max link count is %d", USHRT_MAX(32767 *2 +1)); | |||
| 796 | return 1; | |||
| 797 | } | |||
| 798 | ||||
| 799 | DIP_SET(curinode, di_nlink, lcnt)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_nlink = (lcnt); else (curinode)->dp2.di_nlink = (lcnt ); } while (0); | |||
| 800 | inodirty(); | |||
| 801 | printactive(); | |||
| 802 | return rval; | |||
| 803 | } | |||
| 804 | ||||
| 805 | CMDFUNCSTART(chowner)static int chowner(int argc, char *argv[]) | |||
| 806 | { | |||
| 807 | int rval = 1; | |||
| 808 | uid_t uid; | |||
| 809 | char *cp; | |||
| 810 | ||||
| 811 | if (!checkactive()) | |||
| 812 | return 1; | |||
| 813 | ||||
| 814 | uid = strtoul(argv[1], &cp, 0); | |||
| 815 | if (cp == argv[1] || *cp != '\0' ) { | |||
| 816 | /* try looking up name */ | |||
| 817 | if (uid_from_user(argv[1], &uid) == -1) { | |||
| 818 | warnx("bad uid `%s'", argv[1]); | |||
| 819 | return 1; | |||
| 820 | } | |||
| 821 | } | |||
| 822 | ||||
| 823 | DIP_SET(curinode, di_uid, uid)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_uid = (uid); else (curinode)->dp2.di_uid = (uid); } while (0); | |||
| 824 | inodirty(); | |||
| 825 | printactive(); | |||
| 826 | return rval; | |||
| 827 | } | |||
| 828 | ||||
| 829 | CMDFUNCSTART(chgroup)static int chgroup(int argc, char *argv[]) | |||
| 830 | { | |||
| 831 | int rval = 1; | |||
| 832 | gid_t gid; | |||
| 833 | char *cp; | |||
| 834 | struct group *grp; | |||
| 835 | ||||
| 836 | if (!checkactive()) | |||
| 837 | return 1; | |||
| 838 | ||||
| 839 | gid = strtoul(argv[1], &cp, 0); | |||
| 840 | if (cp == argv[1] || *cp != '\0' ) { | |||
| 841 | if ((grp = getgrnam(argv[1]))) { | |||
| 842 | gid = grp->gr_gid; | |||
| 843 | } else { | |||
| 844 | warnx("bad gid `%s'", argv[1]); | |||
| 845 | return 1; | |||
| 846 | } | |||
| 847 | } | |||
| 848 | ||||
| 849 | DIP_SET(curinode, di_gid, gid)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_gid = (gid); else (curinode)->dp2.di_gid = (gid); } while (0); | |||
| 850 | inodirty(); | |||
| 851 | printactive(); | |||
| 852 | return rval; | |||
| 853 | } | |||
| 854 | ||||
| 855 | static int | |||
| 856 | dotime(char *name, time_t *rsec, int32_t *rnsec) | |||
| 857 | { | |||
| 858 | char *p, *val; | |||
| 859 | struct tm t; | |||
| 860 | time_t sec; | |||
| 861 | int32_t nsec; | |||
| 862 | ||||
| 863 | p = strchr(name, '.'); | |||
| 864 | if (p) { | |||
| 865 | *p = '\0'; | |||
| 866 | nsec = strtoul(++p, &val, 0); | |||
| 867 | if (val == p || *val != '\0' || nsec >= 1000000000 || nsec < 0) { | |||
| 868 | warnx("invalid nanoseconds"); | |||
| 869 | goto badformat; | |||
| 870 | } | |||
| 871 | } else | |||
| 872 | nsec = 0; | |||
| 873 | ||||
| 874 | if (strlen(name) != 14) { | |||
| 875 | badformat: | |||
| 876 | warnx("date format: YYYYMMDDHHMMSS[.nsec]"); | |||
| 877 | return 1; | |||
| 878 | } | |||
| 879 | ||||
| 880 | for (p = name; *p; p++) | |||
| 881 | if (*p < '0' || *p > '9') | |||
| 882 | goto badformat; | |||
| 883 | ||||
| 884 | p = name; | |||
| 885 | #define VAL()((*p++) - '0') ((*p++) - '0') | |||
| 886 | bzero(&t, sizeof t); | |||
| 887 | t.tm_year = VAL()((*p++) - '0'); | |||
| 888 | t.tm_year = VAL()((*p++) - '0') + t.tm_year * 10; | |||
| 889 | t.tm_year = VAL()((*p++) - '0') + t.tm_year * 10; | |||
| 890 | t.tm_year = VAL()((*p++) - '0') + t.tm_year * 10 - 1900; | |||
| 891 | t.tm_mon = VAL()((*p++) - '0'); | |||
| 892 | t.tm_mon = VAL()((*p++) - '0') + t.tm_mon * 10 - 1; | |||
| 893 | t.tm_mday = VAL()((*p++) - '0'); | |||
| 894 | t.tm_mday = VAL()((*p++) - '0') + t.tm_mday * 10; | |||
| 895 | t.tm_hour = VAL()((*p++) - '0'); | |||
| 896 | t.tm_hour = VAL()((*p++) - '0') + t.tm_hour * 10; | |||
| 897 | t.tm_min = VAL()((*p++) - '0'); | |||
| 898 | t.tm_min = VAL()((*p++) - '0') + t.tm_min * 10; | |||
| 899 | t.tm_sec = VAL()((*p++) - '0'); | |||
| 900 | t.tm_sec = VAL()((*p++) - '0') + t.tm_sec * 10; | |||
| 901 | t.tm_isdst = -1; | |||
| 902 | ||||
| 903 | sec = mktime(&t); | |||
| 904 | if (sec == -1) { | |||
| 905 | warnx("date/time out of range"); | |||
| 906 | return 1; | |||
| 907 | } | |||
| 908 | *rsec = sec; | |||
| 909 | *rnsec = nsec; | |||
| 910 | return 0; | |||
| 911 | } | |||
| 912 | ||||
| 913 | CMDFUNCSTART(chmtime)static int chmtime(int argc, char *argv[]) | |||
| 914 | { | |||
| 915 | time_t rsec; | |||
| 916 | int32_t nsec; | |||
| 917 | ||||
| 918 | if (dotime(argv[1], &rsec, &nsec)) | |||
| 919 | return 1; | |||
| 920 | DIP_SET(curinode, di_mtime, rsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_mtime = (rsec); else (curinode)->dp2.di_mtime = (rsec ); } while (0); | |||
| 921 | DIP_SET(curinode, di_mtimensec, nsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_mtimensec = (nsec); else (curinode)->dp2.di_mtimensec = (nsec); } while (0); | |||
| 922 | inodirty(); | |||
| 923 | printactive(); | |||
| 924 | return 0; | |||
| 925 | } | |||
| 926 | ||||
| 927 | CMDFUNCSTART(chatime)static int chatime(int argc, char *argv[]) | |||
| 928 | { | |||
| 929 | time_t rsec; | |||
| 930 | int32_t nsec; | |||
| 931 | ||||
| 932 | if (dotime(argv[1], &rsec, &nsec)) | |||
| 933 | return 1; | |||
| 934 | DIP_SET(curinode, di_atime, rsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_atime = (rsec); else (curinode)->dp2.di_atime = (rsec ); } while (0); | |||
| 935 | DIP_SET(curinode, di_atimensec, nsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_atimensec = (nsec); else (curinode)->dp2.di_atimensec = (nsec); } while (0); | |||
| 936 | inodirty(); | |||
| 937 | printactive(); | |||
| 938 | return 0; | |||
| 939 | } | |||
| 940 | ||||
| 941 | CMDFUNCSTART(chctime)static int chctime(int argc, char *argv[]) | |||
| 942 | { | |||
| 943 | time_t rsec; | |||
| 944 | int32_t nsec; | |||
| 945 | ||||
| 946 | if (dotime(argv[1], &rsec, &nsec)) | |||
| 947 | return 1; | |||
| 948 | DIP_SET(curinode, di_ctime, rsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_ctime = (rsec); else (curinode)->dp2.di_ctime = (rsec ); } while (0); | |||
| 949 | DIP_SET(curinode, di_ctimensec, nsec)do { if ((*sblk.b_un.b_fs).fs_magic == 0x011954) (curinode)-> dp1.di_ctimensec = (nsec); else (curinode)->dp2.di_ctimensec = (nsec); } while (0); | |||
| 950 | inodirty(); | |||
| 951 | printactive(); | |||
| 952 | return 0; | |||
| 953 | } |