1 /* $OpenBSD: newfs.c,v 1.88 2010/12/13 00:02:58 marco Exp $ */ 2 /* $NetBSD: newfs.c,v 1.20 1996/05/16 07:13:03 thorpej Exp $ */ 3 4 /* 5 * Copyright (c) 2002 Networks Associates Technology, Inc. 6 * All rights reserved. 7 * 8 * This software was developed for the FreeBSD Project by Marshall 9 * Kirk McKusick and Network Associates Laboratories, the Security 10 * Research Division of Network Associates, Inc. under DARPA/SPAWAR 11 * contract N66001-01-C-8035 ("CBOSS"), as part of the DARPA CHATS 12 * research program. 13 * 14 * Copyright (c) 1983, 1989, 1993, 1994 15 * The Regents of the University of California. All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. Neither the name of the University nor the names of its contributors 26 * may be used to endorse or promote products derived from this software 27 * without specific prior written permission. 28 * 29 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 30 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 31 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 32 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 33 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 34 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 35 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 36 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 37 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 38 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 39 * SUCH DAMAGE. 40 */ 41 42 #include <sys/param.h> 43 #include <sys/types.h> 44 #include <sys/stat.h> 45 #include <sys/ioctl.h> 46 #include <sys/dkio.h> 47 #include <sys/disklabel.h> 48 #include <sys/mount.h> 49 #include <sys/resource.h> 50 #include <sys/sysctl.h> 51 #include <sys/wait.h> 52 53 #include <ufs/ufs/dinode.h> 54 #include <ufs/ufs/dir.h> 55 #include <ufs/ffs/fs.h> 56 57 #include <ctype.h> 58 #include <err.h> 59 #include <errno.h> 60 #include <fcntl.h> 61 #include <paths.h> 62 #include <stdarg.h> 63 #include <stdio.h> 64 #include <stdlib.h> 65 #include <string.h> 66 #include <syslog.h> 67 #include <unistd.h> 68 #include <signal.h> 69 #include <util.h> 70 71 #include "mntopts.h" 72 #include "pathnames.h" 73 74 struct mntopt mopts[] = { 75 MOPT_STDOPTS, 76 MOPT_ASYNC, 77 MOPT_UPDATE, 78 MOPT_FORCE, 79 { NULL }, 80 }; 81 82 void fatal(const char *fmt, ...); 83 __dead void usage(void); 84 void mkfs(struct partition *, char *, int, int, mode_t, uid_t, gid_t); 85 void rewritelabel(char *, int, struct disklabel *); 86 u_short dkcksum(struct disklabel *); 87 88 /* 89 * The following two constants set the default block and fragment sizes. 90 * Both constants must be a power of 2 and meet the following constraints: 91 * MINBSIZE <= DESBLKSIZE <= MAXBSIZE 92 * sectorsize <= DESFRAGSIZE <= DESBLKSIZE 93 * DESBLKSIZE / DESFRAGSIZE <= 8 94 */ 95 #define DFL_FRAGSIZE 2048 96 #define DFL_BLKSIZE 16384 97 98 /* 99 * MAXBLKPG determines the maximum number of data blocks which are 100 * placed in a single cylinder group. The default is one indirect 101 * block worth of data blocks. 102 */ 103 #define MAXBLKPG_FFS1(bsize) ((bsize) / sizeof(int32_t)) 104 #define MAXBLKPG_FFS2(bsize) ((bsize) / sizeof(int64_t)) 105 106 /* 107 * Each file system has a number of inodes statically allocated. 108 * We allocate one inode slot per NFPI fragments, expecting this 109 * to be far more than we will ever need. 110 */ 111 #define NFPI 4 112 113 int mfs; /* run as the memory based filesystem */ 114 int Nflag; /* run without writing file system */ 115 int Oflag = 1; /* 0 = 4.3BSD ffs, 1 = 4.4BSD ffs, 2 = ffs2 */ 116 daddr64_t fssize; /* file system size */ 117 int sectorsize; /* bytes/sector */ 118 int fsize = 0; /* fragment size */ 119 int bsize = 0; /* block size */ 120 int maxfrgspercg = INT_MAX; /* maximum fragments per cylinder group */ 121 int minfree = MINFREE; /* free space threshold */ 122 int opt = DEFAULTOPT; /* optimization preference (space or time) */ 123 int reqopt = -1; /* opt preference has not been specified */ 124 int density; /* number of bytes per inode */ 125 int maxbpg; /* maximum blocks per file in a cyl group */ 126 int avgfilesize = AVFILESIZ;/* expected average file size */ 127 int avgfilesperdir = AFPDIR;/* expected number of files per directory */ 128 int mntflags = MNT_ASYNC; /* flags to be passed to mount */ 129 int quiet = 0; /* quiet flag */ 130 caddr_t membase; /* start address of memory based filesystem */ 131 char *disktype; 132 int unlabeled; 133 134 extern char *__progname; 135 struct disklabel *getdisklabel(char *, int); 136 137 #ifdef MFS 138 static int do_exec(const char *, const char *, char *const[]); 139 static int isdir(const char *); 140 static void copy(char *, char *, struct mfs_args *); 141 static int gettmpmnt(char *, size_t); 142 #endif 143 144 int 145 main(int argc, char *argv[]) 146 { 147 int ch; 148 struct partition *pp; 149 struct disklabel *lp; 150 struct disklabel mfsfakelabel; 151 struct partition oldpartition; 152 struct stat st; 153 struct statfs *mp; 154 struct rlimit rl; 155 int fsi = -1, oflagset = 0, fso, len, n, maxpartitions; 156 char *cp = NULL, *s1, *s2, *special, *opstring, *realdev; 157 #ifdef MFS 158 char mountfromname[BUFSIZ]; 159 char *pop = NULL, node[MAXPATHLEN]; 160 pid_t pid, res; 161 struct statfs sf; 162 struct stat mountpoint; 163 int status; 164 #endif 165 uid_t mfsuid = 0; 166 gid_t mfsgid = 0; 167 mode_t mfsmode = 0; 168 char *fstype = NULL; 169 char **saveargv = argv; 170 int ffsflag = 1; 171 const char *errstr; 172 173 if (strstr(__progname, "mfs")) 174 mfs = Nflag = quiet = 1; 175 176 maxpartitions = getmaxpartitions(); 177 if (maxpartitions > 26) 178 fatal("insane maxpartitions value %d", maxpartitions); 179 180 opstring = mfs ? 181 "P:T:b:c:e:f:i:m:o:s:" : 182 "NO:S:T:b:c:e:f:g:h:i:m:o:qs:t:"; 183 while ((ch = getopt(argc, argv, opstring)) != -1) { 184 switch (ch) { 185 case 'N': 186 Nflag = 1; 187 break; 188 case 'O': 189 Oflag = strtonum(optarg, 0, 2, &errstr); 190 if (errstr) 191 fatal("%s: invalid ffs version", optarg); 192 oflagset = 1; 193 break; 194 case 'S': 195 sectorsize = strtonum(optarg, 1, INT_MAX, &errstr); 196 if (errstr) 197 fatal("sector size is %s: %s", errstr, optarg); 198 break; 199 case 'T': 200 disktype = optarg; 201 break; 202 case 'b': 203 bsize = strtonum(optarg, MINBSIZE, MAXBSIZE, &errstr); 204 if (errstr) 205 fatal("block size is %s: %s", errstr, optarg); 206 break; 207 case 'c': 208 maxfrgspercg = strtonum(optarg, 1, INT_MAX, &errstr); 209 if (errstr) 210 fatal("fragments per cylinder group is %s: %s", 211 errstr, optarg); 212 break; 213 case 'e': 214 maxbpg = strtonum(optarg, 1, INT_MAX, &errstr); 215 if (errstr) 216 fatal("blocks per file in a cylinder group is" 217 " %s: %s", errstr, optarg); 218 break; 219 case 'f': 220 fsize = strtonum(optarg, MINBSIZE / MAXFRAG, MAXBSIZE, 221 &errstr); 222 if (errstr) 223 fatal("fragment size is %s: %s", 224 errstr, optarg); 225 break; 226 case 'g': 227 avgfilesize = strtonum(optarg, 1, INT_MAX, &errstr); 228 if (errstr) 229 fatal("average file size is %s: %s", 230 errstr, optarg); 231 break; 232 case 'h': 233 avgfilesperdir = strtonum(optarg, 1, INT_MAX, &errstr); 234 if (errstr) 235 fatal("average files per dir is %s: %s", 236 errstr, optarg); 237 break; 238 case 'i': 239 density = strtonum(optarg, 1, INT_MAX, &errstr); 240 if (errstr) 241 fatal("bytes per inode is %s: %s", 242 errstr, optarg); 243 break; 244 case 'm': 245 minfree = strtonum(optarg, 0, 99, &errstr); 246 if (errstr) 247 fatal("free space %% is %s: %s", 248 errstr, optarg); 249 break; 250 case 'o': 251 if (mfs) 252 getmntopts(optarg, mopts, &mntflags); 253 else { 254 if (strcmp(optarg, "space") == 0) 255 reqopt = opt = FS_OPTSPACE; 256 else if (strcmp(optarg, "time") == 0) 257 reqopt = opt = FS_OPTTIME; 258 else 259 fatal("%s: unknown optimization " 260 "preference: use `space' or `time'.", 261 optarg); 262 } 263 break; 264 case 'q': 265 quiet = 1; 266 break; 267 case 's': 268 fssize = strtonum(optarg, 1, LLONG_MAX, &errstr); 269 if (errstr) 270 fatal("file system size is %s: %s", 271 errstr, optarg); 272 break; 273 case 't': 274 fstype = optarg; 275 if (strcmp(fstype, "ffs")) 276 ffsflag = 0; 277 break; 278 #ifdef MFS 279 case 'P': 280 pop = optarg; 281 break; 282 #endif 283 case '?': 284 default: 285 usage(); 286 } 287 if (!ffsflag) 288 break; 289 } 290 argc -= optind; 291 argv += optind; 292 293 if (ffsflag && argc - mfs != 1) 294 usage(); 295 296 /* Increase our data size to the max */ 297 if (getrlimit(RLIMIT_DATA, &rl) == 0) { 298 rl.rlim_cur = rl.rlim_max; 299 (void)setrlimit(RLIMIT_DATA, &rl); 300 } 301 302 special = argv[0]; 303 304 if (!mfs) { 305 char execname[MAXPATHLEN], name[MAXPATHLEN]; 306 307 if (fstype == NULL) 308 fstype = readlabelfs(special, 0); 309 if (fstype != NULL && strcmp(fstype, "ffs")) { 310 snprintf(name, sizeof name, "newfs_%s", fstype); 311 saveargv[0] = name; 312 snprintf(execname, sizeof execname, "%s/newfs_%s", 313 _PATH_SBIN, fstype); 314 (void)execv(execname, saveargv); 315 snprintf(execname, sizeof execname, "%s/newfs_%s", 316 _PATH_USRSBIN, fstype); 317 (void)execv(execname, saveargv); 318 err(1, "%s not found", name); 319 } 320 } 321 322 if (mfs && !strcmp(special, "swap")) { 323 /* 324 * it's an MFS, mounted on "swap." fake up a label. 325 * XXX XXX XXX 326 */ 327 fso = -1; /* XXX; normally done below. */ 328 329 memset(&mfsfakelabel, 0, sizeof(mfsfakelabel)); 330 mfsfakelabel.d_secsize = 512; 331 mfsfakelabel.d_nsectors = 64; 332 mfsfakelabel.d_ntracks = 16; 333 mfsfakelabel.d_ncylinders = 16; 334 mfsfakelabel.d_secpercyl = 1024; 335 mfsfakelabel.d_secperunit = 16384; 336 mfsfakelabel.d_npartitions = 1; 337 mfsfakelabel.d_version = 1; 338 DL_SETPSIZE(&mfsfakelabel.d_partitions[0], 16384); 339 mfsfakelabel.d_partitions[0].p_fragblock = 340 DISKLABELV1_FFS_FRAGBLOCK(1024, 8); 341 mfsfakelabel.d_partitions[0].p_cpg = 16; 342 343 lp = &mfsfakelabel; 344 pp = &mfsfakelabel.d_partitions[0]; 345 346 goto havelabel; 347 } 348 if (Nflag) { 349 fso = -1; 350 } else { 351 fso = opendev(special, O_WRONLY, 0, &realdev); 352 if (fso < 0) 353 fatal("%s: %s", special, strerror(errno)); 354 special = realdev; 355 356 /* Bail if target special is mounted */ 357 n = getmntinfo(&mp, MNT_NOWAIT); 358 if (n == 0) 359 fatal("%s: getmntinfo: %s", special, strerror(errno)); 360 361 len = sizeof(_PATH_DEV) - 1; 362 s1 = special; 363 if (strncmp(_PATH_DEV, s1, len) == 0) 364 s1 += len; 365 366 while (--n >= 0) { 367 s2 = mp->f_mntfromname; 368 if (strncmp(_PATH_DEV, s2, len) == 0) { 369 s2 += len - 1; 370 *s2 = 'r'; 371 } 372 if (strcmp(s1, s2) == 0 || strcmp(s1, &s2[1]) == 0) 373 fatal("%s is mounted on %s", 374 special, mp->f_mntonname); 375 ++mp; 376 } 377 } 378 if (mfs && disktype != NULL) { 379 lp = (struct disklabel *)getdiskbyname(disktype); 380 if (lp == NULL) 381 fatal("%s: unknown disk type", disktype); 382 pp = &lp->d_partitions[1]; 383 } else { 384 fsi = opendev(special, O_RDONLY, 0, NULL); 385 if (fsi < 0) 386 fatal("%s: %s", special, strerror(errno)); 387 if (fstat(fsi, &st) < 0) 388 fatal("%s: %s", special, strerror(errno)); 389 if (!mfs) { 390 if (S_ISBLK(st.st_mode)) 391 fatal("%s: block device", special); 392 if (!S_ISCHR(st.st_mode)) 393 warnx("%s: not a character-special device", 394 special); 395 } 396 cp = strchr(argv[0], '\0') - 1; 397 if (cp == NULL || 398 ((*cp < 'a' || *cp > ('a' + maxpartitions - 1)) 399 && !isdigit(*cp))) 400 fatal("%s: can't figure out file system partition", 401 argv[0]); 402 lp = getdisklabel(special, fsi); 403 if (isdigit(*cp)) 404 pp = &lp->d_partitions[0]; 405 else 406 pp = &lp->d_partitions[*cp - 'a']; 407 if (DL_GETPSIZE(pp) == 0) 408 fatal("%s: `%c' partition is unavailable", 409 argv[0], *cp); 410 if (pp->p_fstype == FS_BOOT) 411 fatal("%s: `%c' partition overlaps boot program", 412 argv[0], *cp); 413 } 414 havelabel: 415 if (fssize == 0) 416 fssize = DL_GETPSIZE(pp); 417 if (fssize > DL_GETPSIZE(pp) && !mfs) 418 fatal("%s: maximum file system size on the `%c' partition is %lld", 419 argv[0], *cp, DL_GETPSIZE(pp)); 420 421 if (sectorsize == 0) { 422 sectorsize = lp->d_secsize; 423 if (sectorsize <= 0) 424 fatal("%s: no default sector size", argv[0]); 425 } 426 fssize *= sectorsize / DEV_BSIZE; 427 if (oflagset == 0 && fssize >= INT_MAX) 428 Oflag = 2; /* FFS2 */ 429 if (fsize == 0) { 430 fsize = DISKLABELV1_FFS_FSIZE(pp->p_fragblock); 431 if (fsize <= 0) 432 fsize = MAX(DFL_FRAGSIZE, lp->d_secsize); 433 } 434 if (bsize == 0) { 435 bsize = DISKLABELV1_FFS_BSIZE(pp->p_fragblock); 436 if (bsize <= 0) 437 bsize = MIN(DFL_BLKSIZE, 8 * fsize); 438 } 439 if (density == 0) 440 density = NFPI * fsize; 441 if (minfree < MINFREE && opt != FS_OPTSPACE && reqopt == -1) { 442 warnx("warning: changing optimization to space " 443 "because minfree is less than %d%%\n", MINFREE); 444 opt = FS_OPTSPACE; 445 } 446 if (maxbpg == 0) { 447 if (Oflag <= 1) 448 maxbpg = MAXBLKPG_FFS1(bsize); 449 else 450 maxbpg = MAXBLKPG_FFS2(bsize); 451 } 452 oldpartition = *pp; 453 #ifdef MFS 454 if (mfs) { 455 if (realpath(argv[1], node) == NULL) 456 err(1, "realpath %s", argv[1]); 457 if (stat(node, &mountpoint) < 0) 458 err(ECANCELED, "stat %s", node); 459 mfsuid = mountpoint.st_uid; 460 mfsgid = mountpoint.st_gid; 461 mfsmode = mountpoint.st_mode & ALLPERMS; 462 } 463 #endif 464 465 mkfs(pp, special, fsi, fso, mfsmode, mfsuid, mfsgid); 466 if (!Nflag && memcmp(pp, &oldpartition, sizeof(oldpartition))) 467 rewritelabel(special, fso, lp); 468 if (!Nflag) 469 close(fso); 470 close(fsi); 471 #ifdef MFS 472 if (mfs) { 473 struct mfs_args args; 474 memset(&args, 0, sizeof(args)); 475 args.base = membase; 476 args.size = fssize * DEV_BSIZE; 477 args.export_info.ex_root = -2; 478 if (mntflags & MNT_RDONLY) 479 args.export_info.ex_flags = MNT_EXRDONLY; 480 481 switch (pid = fork()) { 482 case -1: 483 err(10, "mfs"); 484 case 0: 485 snprintf(mountfromname, sizeof(mountfromname), 486 "mfs:%d", getpid()); 487 break; 488 default: 489 snprintf(mountfromname, sizeof(mountfromname), 490 "mfs:%d", pid); 491 for (;;) { 492 /* 493 * spin until the mount succeeds 494 * or the child exits 495 */ 496 usleep(1); 497 498 /* 499 * XXX Here is a race condition: another process 500 * can mount a filesystem which hides our 501 * ramdisk before we see the success. 502 */ 503 if (statfs(node, &sf) < 0) 504 err(ECANCELED, "statfs %s", node); 505 if (!strcmp(sf.f_mntfromname, mountfromname) && 506 !strncmp(sf.f_mntonname, node, 507 MNAMELEN) && 508 !strcmp(sf.f_fstypename, "mfs")) { 509 if (pop != NULL) 510 copy(pop, node, &args); 511 exit(0); 512 } 513 res = waitpid(pid, &status, WNOHANG); 514 if (res == -1) 515 err(EDEADLK, "waitpid"); 516 if (res != pid) 517 continue; 518 if (WIFEXITED(status)) { 519 if (WEXITSTATUS(status) == 0) 520 exit(0); 521 errx(1, "%s: mount: %s", node, 522 strerror(WEXITSTATUS(status))); 523 } else 524 errx(EDEADLK, "abnormal termination"); 525 } 526 /* NOTREACHED */ 527 } 528 529 (void) setsid(); 530 (void) close(0); 531 (void) close(1); 532 (void) close(2); 533 (void) chdir("/"); 534 535 args.fspec = mountfromname; 536 if (mntflags & MNT_RDONLY && pop != NULL) 537 mntflags &= ~MNT_RDONLY; 538 if (mount(MOUNT_MFS, node, mntflags, &args) < 0) 539 exit(errno); /* parent prints message */ 540 } 541 #endif 542 exit(0); 543 } 544 545 char lmsg[] = "%s: can't read disk label; disk type must be specified"; 546 547 struct disklabel * 548 getdisklabel(char *s, int fd) 549 { 550 static struct disklabel lab; 551 552 if (ioctl(fd, DIOCGDINFO, (char *)&lab) < 0) { 553 if (disktype != NULL) { 554 struct disklabel *lp; 555 556 unlabeled++; 557 lp = getdiskbyname(disktype); 558 if (lp == NULL) 559 fatal("%s: unknown disk type", disktype); 560 return (lp); 561 } 562 warn("ioctl (GDINFO)"); 563 fatal(lmsg, s); 564 } 565 return (&lab); 566 } 567 568 void 569 rewritelabel(char *s, int fd, struct disklabel *lp) 570 { 571 if (unlabeled) 572 return; 573 574 lp->d_checksum = 0; 575 lp->d_checksum = dkcksum(lp); 576 if (ioctl(fd, DIOCWDINFO, (char *)lp) < 0) { 577 warn("ioctl (WDINFO)"); 578 fatal("%s: can't rewrite disk label", s); 579 } 580 #ifdef __vax__ 581 if (lp->d_type == DTYPE_SMD && lp->d_flags & D_BADSECT) { 582 int i; 583 int cfd; 584 daddr64_t alt; 585 char specname[64]; 586 char blk[1024]; 587 char *cp; 588 589 /* 590 * Make name for 'c' partition. 591 */ 592 strncpy(specname, s, sizeof(specname) - 1); 593 specname[sizeof(specname) - 1] = '\0'; 594 cp = specname + strlen(specname) - 1; 595 if (!isdigit(*cp)) 596 *cp = 'c'; 597 cfd = open(specname, O_WRONLY); 598 if (cfd < 0) 599 fatal("%s: %s", specname, strerror(errno)); 600 memset(blk, 0, sizeof(blk)); 601 *(struct disklabel *)(blk + LABELOFFSET) = *lp; 602 alt = lp->d_ncylinders * lp->d_secpercyl - lp->d_nsectors; 603 for (i = 1; i < 11 && i < lp->d_nsectors; i += 2) { 604 off_t offset; 605 606 offset = alt + i; 607 offset *= lp->d_secsize; 608 if (lseek(cfd, offset, SEEK_SET) == -1) 609 fatal("lseek to badsector area: %s", 610 strerror(errno)); 611 if (write(cfd, blk, lp->d_secsize) != lp->d_secsize) 612 warn("alternate label %d write", i/2); 613 } 614 close(cfd); 615 } 616 #endif /*__vax__*/ 617 } 618 619 /*VARARGS*/ 620 void 621 fatal(const char *fmt, ...) 622 { 623 va_list ap; 624 625 va_start(ap, fmt); 626 if (fcntl(STDERR_FILENO, F_GETFL) < 0) { 627 openlog(__progname, LOG_CONS, LOG_DAEMON); 628 vsyslog(LOG_ERR, fmt, ap); 629 closelog(); 630 } else { 631 vwarnx(fmt, ap); 632 } 633 va_end(ap); 634 exit(1); 635 /*NOTREACHED*/ 636 } 637 638 __dead void 639 usage(void) 640 { 641 extern char *__progname; 642 643 if (mfs) { 644 fprintf(stderr, 645 "usage: %s [-b block-size] [-c fragments-per-cylinder-group] " 646 "[-e maxbpg]\n" 647 "\t[-f frag-size] [-i bytes] [-m free-space] [-o options] " 648 "[-P file]\n" 649 "\t[-s size] special node\n", 650 __progname); 651 } else { 652 fprintf(stderr, 653 "usage: %s [-Nq] [-b block-size] " 654 "[-c fragments-per-cylinder-group] [-e maxbpg]\n" 655 "\t[-f frag-size] [-g avgfilesize] [-h avgfpdir] [-i bytes]\n" 656 "\t[-m free-space] [-O filesystem-format] [-o optimization]\n" 657 "\t[-S sector-size] [-s size] [-T disktype] [-t fstype] " 658 "special\n", 659 __progname); 660 } 661 662 exit(1); 663 } 664 665 #ifdef MFS 666 667 static int 668 do_exec(const char *dir, const char *cmd, char *const argv[]) 669 { 670 pid_t pid; 671 int ret, status; 672 sig_t intsave, quitsave; 673 674 switch (pid = fork()) { 675 case -1: 676 err(1, "fork"); 677 case 0: 678 if (dir != NULL && chdir(dir) != 0) 679 err(1, "chdir"); 680 if (execv(cmd, argv) != 0) 681 err(1, "%s", cmd); 682 break; 683 default: 684 intsave = signal(SIGINT, SIG_IGN); 685 quitsave = signal(SIGQUIT, SIG_IGN); 686 for (;;) { 687 ret = waitpid(pid, &status, 0); 688 if (ret == -1) 689 err(11, "waitpid"); 690 if (WIFEXITED(status)) { 691 status = WEXITSTATUS(status); 692 if (status != 0) 693 warnx("%s: exited", cmd); 694 break; 695 } else if (WIFSIGNALED(status)) { 696 warnx("%s: %s", cmd, 697 strsignal(WTERMSIG(status))); 698 status = 1; 699 break; 700 } 701 } 702 signal(SIGINT, intsave); 703 signal(SIGQUIT, quitsave); 704 return (status); 705 } 706 /* NOTREACHED */ 707 return (-1); 708 } 709 710 static int 711 isdir(const char *path) 712 { 713 struct stat st; 714 715 if (stat(path, &st) != 0) 716 err(1, "cannot stat %s", path); 717 if (!S_ISDIR(st.st_mode) && !S_ISBLK(st.st_mode)) 718 errx(1, "%s: not a dir or a block device", path); 719 return (S_ISDIR(st.st_mode)); 720 } 721 722 static void 723 copy(char *src, char *dst, struct mfs_args *args) 724 { 725 int ret, dir, created = 0; 726 struct ufs_args mount_args; 727 char mountpoint[MNAMELEN]; 728 char *const argv[] = { "pax", "-rw", "-pe", ".", dst, NULL } ; 729 730 dir = isdir(src); 731 if (dir) 732 strlcpy(mountpoint, src, sizeof(mountpoint)); 733 else { 734 created = gettmpmnt(mountpoint, sizeof(mountpoint)); 735 memset(&mount_args, 0, sizeof(mount_args)); 736 mount_args.fspec = src; 737 ret = mount(MOUNT_FFS, mountpoint, MNT_RDONLY, &mount_args); 738 if (ret != 0) { 739 if (created && rmdir(mountpoint) != 0) 740 warn("rmdir %s", mountpoint); 741 if (unmount(dst, 0) != 0) 742 warn("unmount %s", dst); 743 err(1, "mount %s %s", src, mountpoint); 744 } 745 } 746 ret = do_exec(mountpoint, "/bin/pax", argv); 747 if (!dir && unmount(mountpoint, 0) != 0) 748 warn("unmount %s", mountpoint); 749 if (created && rmdir(mountpoint) != 0) 750 warn("rmdir %s", mountpoint); 751 if (ret != 0) { 752 if (unmount(dst, 0) != 0) 753 warn("unmount %s", dst); 754 errx(1, "copy %s to %s failed", mountpoint, dst); 755 } 756 757 if (mntflags & MNT_RDONLY) { 758 mntflags |= MNT_UPDATE; 759 if (mount(MOUNT_MFS, dst, mntflags, args) < 0) { 760 warn("%s: mount (update, rdonly)", dst); 761 if (unmount(dst, 0) != 0) 762 warn("unmount %s", dst); 763 exit(1); 764 } 765 } 766 } 767 768 static int 769 gettmpmnt(char *mountpoint, size_t len) 770 { 771 const char *tmp; 772 const char *mnt = _PATH_MNT; 773 struct statfs fs; 774 size_t n; 775 776 tmp = getenv("TMPDIR"); 777 if (tmp == NULL || *tmp == '\0') 778 tmp = _PATH_TMP; 779 780 if (statfs(tmp, &fs) != 0) 781 err(1, "statfs %s", tmp); 782 if (fs.f_flags & MNT_RDONLY) { 783 if (statfs(mnt, &fs) != 0) 784 err(1, "statfs %s", mnt); 785 if (strcmp(fs.f_mntonname, "/") != 0) 786 errx(1, "tmp mountpoint %s busy", mnt); 787 if (strlcpy(mountpoint, mnt, len) >= len) 788 errx(1, "tmp mountpoint %s too long", mnt); 789 return (0); 790 } 791 n = strlcpy(mountpoint, tmp, len); 792 if (n >= len) 793 errx(1, "tmp mount point too long"); 794 if (mountpoint[n - 1] != '/') 795 strlcat(mountpoint, "/", len); 796 n = strlcat(mountpoint, "mntXXXXXXXXXX", len); 797 if (n >= len) 798 errx(1, "tmp mount point too long"); 799 if (mkdtemp(mountpoint) == NULL) 800 err(1, "mkdtemp %s", mountpoint); 801 return (1); 802 } 803 804 #endif /* MFS */ 805