1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 27 /* All Rights Reserved */ 28 29 30 #include <stdio.h> 31 #include <stdio_ext.h> 32 #include <limits.h> 33 #include <unistd.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <sys/signal.h> 37 #include <sys/mnttab.h> 38 #include <errno.h> 39 #include <sys/types.h> 40 #include <sys/stat.h> 41 #include <sys/param.h> 42 #include <sys/wait.h> 43 #include <sys/vfstab.h> 44 #include <sys/fcntl.h> 45 #include <sys/resource.h> 46 #include <sys/mntent.h> 47 #include <sys/ctfs.h> 48 #include <locale.h> 49 #include <stdarg.h> 50 #include <sys/mount.h> 51 #include <sys/objfs.h> 52 #include "fslib.h" 53 #include <sharefs/share.h> 54 55 #define FS_PATH "/usr/lib/fs" 56 #define ALT_PATH "/etc/fs" 57 #define FULLPATH_MAX 32 58 #define FSTYPE_MAX 8 59 #define ARGV_MAX 16 60 61 int aflg, oflg, Vflg, dashflg, dflg, fflg; 62 63 extern void rpterr(), usage(), mnterror(); 64 65 extern char *optarg; /* used by getopt */ 66 extern int optind, opterr; 67 68 static char *myname; 69 char fs_path[] = FS_PATH; 70 char alt_path[] = ALT_PATH; 71 char mnttab[MAXPATHLEN + 1]; 72 char *oarg, *farg; 73 int maxrun, nrun; 74 int no_mnttab; 75 int lofscnt; /* presence of lofs prohibits parallel */ 76 /* umounting */ 77 int exitcode; 78 char resolve[MAXPATHLEN]; 79 static char ibuf[BUFSIZ]; 80 81 /* 82 * Currently, mounting cachefs's simultaneous uncovers various problems. 83 * For the short term, we serialize cachefs activity while we fix 84 * these cachefs bugs. 85 */ 86 #define CACHEFS_BUG 87 #ifdef CACHEFS_BUG 88 #include <sys/fs/cachefs_fs.h> /* for BACKMNT_NAME */ 89 int cachefs_running; /* parallel cachefs not supported yet */ 90 #endif 91 92 /* 93 * The basic mount struct that describes an mnttab entry. 94 * It is used both in an array and as a linked list elem. 95 */ 96 97 typedef struct mountent { 98 struct mnttab ment; /* the mnttab data */ 99 int mlevel; /* mount level of the mount pt */ 100 pid_t pid; /* the pid of this mount process */ 101 #define RDPIPE 0 102 #define WRPIPE 1 103 int sopipe[2]; /* pipe attached to child's stdout */ 104 int sepipe[2]; /* pipe attached to child's stderr */ 105 struct mountent *link; /* used when in linked list */ 106 } mountent_t; 107 108 static mountent_t *mntll; /* head of global linked list of */ 109 /* mountents */ 110 int listlength; /* # of elems in this list */ 111 112 /* 113 * If the automatic flag (-a) is given and mount points are not specified 114 * on the command line, then do not attempt to umount these. These 115 * generally need to be kept mounted until system shutdown. 116 */ 117 static const char *keeplist[] = { 118 "/", 119 "/dev", 120 "/dev/fd", 121 "/devices", 122 "/etc/mnttab", 123 "/etc/svc/volatile", 124 "/lib", 125 "/proc", 126 "/sbin", 127 CTFS_ROOT, 128 OBJFS_ROOT, 129 "/tmp", 130 "/usr", 131 "/var", 132 "/var/adm", 133 "/var/run", 134 SHARETAB, 135 NULL 136 }; 137 138 static void nomem(); 139 static void doexec(struct mnttab *); 140 static int setup_iopipe(mountent_t *); 141 static void setup_output(mountent_t *); 142 static void doio(mountent_t *); 143 static void do_umounts(mountent_t **); 144 static int dowait(); 145 static int parumount(); 146 static int mcompar(const void *, const void *); 147 static void cleanup(int); 148 149 static mountent_t **make_mntarray(char **, int); 150 static mountent_t *getmntall(); 151 static mountent_t *new_mountent(struct mnttab *); 152 static mountent_t *getmntlast(mountent_t *, char *, char *); 153 154 int 155 main(int argc, char **argv) 156 { 157 int cc; 158 struct mnttab mget; 159 char *mname, *is_special; 160 int fscnt; 161 mountent_t *mp; 162 163 (void) setlocale(LC_ALL, ""); 164 165 #if !defined(TEXT_DOMAIN) 166 #define TEXT_DOMAIN "SYS_TEST" 167 #endif 168 (void) textdomain(TEXT_DOMAIN); 169 170 myname = strrchr(argv[0], '/'); 171 if (myname) 172 myname++; 173 else 174 myname = argv[0]; 175 176 /* 177 * Process the args. 178 * "-d" for compatibility 179 */ 180 while ((cc = getopt(argc, argv, "ado:Vf?")) != -1) 181 switch (cc) { 182 case 'a': 183 aflg++; 184 break; 185 #ifdef DEBUG 186 case 'd': 187 dflg++; 188 break; 189 #endif 190 191 case '?': 192 usage(); 193 break; 194 case 'o': 195 if (oflg) 196 usage(); 197 else { 198 oflg++; 199 oarg = optarg; 200 } 201 break; 202 case 'f': 203 fflg++; 204 break; 205 case 'V': 206 if (Vflg) 207 usage(); 208 else 209 Vflg++; 210 break; 211 default: 212 usage(); 213 break; 214 } 215 216 fscnt = argc - optind; 217 if (!aflg && fscnt != 1) 218 usage(); 219 220 /* copy '--' to specific */ 221 if (strcmp(argv[optind-1], "--") == 0) 222 dashflg++; 223 224 /* 225 * mnttab may be a symlink to a file in another file system. 226 * This happens during install when / is mounted read-only 227 * and /etc/mnttab is symlinked to a file in /tmp. 228 * If this is the case, we need to follow the symlink to the 229 * read-write file itself so that the subsequent mnttab.temp 230 * open and rename will work. 231 */ 232 if (realpath(MNTTAB, mnttab) == NULL) { 233 strcpy(mnttab, MNTTAB); 234 } 235 236 /* 237 * bugid 1205242 238 * call the realpath() here, so that if the user is 239 * trying to umount an autofs directory, the directory 240 * is forced to mount. 241 */ 242 243 mname = argv[optind]; 244 is_special = realpath(mname, resolve); 245 246 /* 247 * Read the whole mnttab into memory. 248 */ 249 mntll = getmntall(); 250 251 if (aflg && fscnt != 1) 252 exit(parumount(argv + optind, fscnt)); 253 254 aflg = 0; 255 256 mntnull(&mget); 257 if (listlength == 0) { 258 fprintf(stderr, gettext( 259 "%s: warning: no entries found in %s\n"), 260 myname, mnttab); 261 mget.mnt_mountp = mname; /* assume mount point */ 262 no_mnttab++; 263 doexec(&mget); 264 exit(0); 265 } 266 267 mp = NULL; 268 269 /* 270 * if realpath fails, it can't be a mount point, so we'll 271 * go straight to the code that treats the arg as a special. 272 * if realpath succeeds, it could be a special or a mount point; 273 * we'll start by assuming it's a mount point, and if it's not, 274 * try to treat it as a special. 275 */ 276 if (is_special != NULL) { 277 /* 278 * if this succeeds, 279 * we'll have the appropriate record; if it fails 280 * we'll assume the arg is a special of some sort 281 */ 282 mp = getmntlast(mntll, NULL, resolve); 283 } 284 /* 285 * Since stackable mount is allowed (RFE 2001535), 286 * we will un-mount the last entry in the MNTTAB that matches. 287 */ 288 if (mp == NULL) { 289 /* 290 * Perhaps there is a bogus mnttab entry that 291 * can't be resolved: 292 */ 293 if ((mp = getmntlast(mntll, NULL, mname)) == NULL) 294 /* 295 * assume it's a device (special) now 296 */ 297 mp = getmntlast(mntll, mname, NULL); 298 if (mp) { 299 /* 300 * Found it. 301 * This is a device. Now we want to know if 302 * it stackmounted on by something else. 303 * The original fix for bug 1103850 has a 304 * problem with lockfs (bug 1119731). This 305 * is a revised method. 306 */ 307 mountent_t *lmp; 308 lmp = getmntlast(mntll, NULL, mp->ment.mnt_mountp); 309 310 if (lmp && strcmp(lmp->ment.mnt_special, 311 mp->ment.mnt_special)) { 312 errno = EBUSY; 313 rpterr(mname); 314 exit(1); 315 } 316 } else { 317 fprintf(stderr, gettext( 318 "%s: warning: %s not in mnttab\n"), 319 myname, mname); 320 if (Vflg) 321 exit(1); 322 /* 323 * same error as mount -V 324 * would give for unknown 325 * mount point 326 */ 327 mget.mnt_special = mget.mnt_mountp = mname; 328 } 329 } 330 331 if (mp) 332 doexec(&mp->ment); 333 else 334 doexec(&mget); 335 336 return (0); 337 } 338 339 void 340 doexec(struct mnttab *ment) 341 { 342 int ret; 343 344 #ifdef DEBUG 345 if (dflg) 346 fprintf(stderr, "%d: umounting %s\n", 347 getpid(), ment->mnt_mountp); 348 #endif 349 350 /* try to exec the dependent portion */ 351 if ((ment->mnt_fstype != NULL) || Vflg) { 352 char full_path[FULLPATH_MAX]; 353 char alter_path[FULLPATH_MAX]; 354 char *newargv[ARGV_MAX]; 355 int ii; 356 357 if (strlen(ment->mnt_fstype) > (size_t)FSTYPE_MAX) { 358 fprintf(stderr, gettext( 359 "%s: FSType %s exceeds %d characters\n"), 360 myname, ment->mnt_fstype, FSTYPE_MAX); 361 exit(1); 362 } 363 364 /* build the full pathname of the fstype dependent command. */ 365 sprintf(full_path, "%s/%s/%s", fs_path, ment->mnt_fstype, 366 myname); 367 sprintf(alter_path, "%s/%s/%s", alt_path, ment->mnt_fstype, 368 myname); 369 370 /* 371 * create the new arg list, and end the list with a 372 * null pointer 373 */ 374 ii = 2; 375 if (oflg) { 376 newargv[ii++] = "-o"; 377 newargv[ii++] = oarg; 378 } 379 if (dashflg) { 380 newargv[ii++] = "--"; 381 } 382 if (fflg) { 383 newargv[ii++] = "-f"; 384 } 385 newargv[ii++] = (ment->mnt_mountp) 386 ? ment->mnt_mountp : ment->mnt_special; 387 newargv[ii] = NULL; 388 389 /* set the new argv[0] to the filename */ 390 newargv[1] = myname; 391 392 if (Vflg) { 393 printf("%s", myname); 394 for (ii = 2; newargv[ii]; ii++) 395 printf(" %s", newargv[ii]); 396 printf("\n"); 397 fflush(stdout); 398 exit(0); 399 } 400 401 /* Try to exec the fstype dependent umount. */ 402 execv(full_path, &newargv[1]); 403 if (errno == ENOEXEC) { 404 newargv[0] = "sh"; 405 newargv[1] = full_path; 406 execv("/sbin/sh", &newargv[0]); 407 } 408 newargv[1] = myname; 409 execv(alter_path, &newargv[1]); 410 if (errno == ENOEXEC) { 411 newargv[0] = "sh"; 412 newargv[1] = alter_path; 413 execv("/sbin/sh", &newargv[0]); 414 } 415 /* exec failed */ 416 if (errno != ENOENT) { 417 fprintf(stderr, gettext("umount: cannot execute %s\n"), 418 full_path); 419 exit(1); 420 } 421 } 422 /* 423 * No fstype independent executable then. We'll go generic 424 * from here. 425 */ 426 427 /* don't use -o with generic */ 428 if (oflg) { 429 fprintf(stderr, gettext( 430 "%s: %s specific umount does not exist;" 431 " -o suboption ignored\n"), 432 myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>"); 433 } 434 435 signal(SIGHUP, SIG_IGN); 436 signal(SIGQUIT, SIG_IGN); 437 signal(SIGINT, SIG_IGN); 438 /* 439 * Try to umount the mountpoint. 440 * If that fails, try the corresponding special. 441 * (This ordering is necessary for nfs umounts.) 442 * (for remote resources: if the first umount returns EBUSY 443 * don't call umount again - umount() with a resource name 444 * will return a misleading error to the user 445 */ 446 if (fflg) { 447 if (((ret = umount2(ment->mnt_mountp, MS_FORCE)) < 0) && 448 (errno != EBUSY && errno != ENOTSUP && 449 errno != EPERM)) 450 ret = umount2(ment->mnt_special, MS_FORCE); 451 } else { 452 if (((ret = umount2(ment->mnt_mountp, 0)) < 0) && 453 (errno != EBUSY) && (errno != EPERM)) 454 ret = umount2(ment->mnt_special, 0); 455 } 456 457 if (ret < 0) { 458 rpterr(ment->mnt_mountp); 459 if (errno != EINVAL && errno != EFAULT) 460 exit(1); 461 462 exitcode = 1; 463 } 464 465 exit(exitcode); 466 } 467 468 void 469 rpterr(char *sp) 470 { 471 switch (errno) { 472 case EPERM: 473 fprintf(stderr, gettext("%s: permission denied\n"), myname); 474 break; 475 case ENXIO: 476 fprintf(stderr, gettext("%s: %s no device\n"), myname, sp); 477 break; 478 case ENOENT: 479 fprintf(stderr, 480 gettext("%s: %s no such file or directory\n"), 481 myname, sp); 482 break; 483 case EINVAL: 484 fprintf(stderr, gettext("%s: %s not mounted\n"), myname, sp); 485 break; 486 case EBUSY: 487 fprintf(stderr, gettext("%s: %s busy\n"), myname, sp); 488 break; 489 case ENOTBLK: 490 fprintf(stderr, 491 gettext("%s: %s block device required\n"), myname, sp); 492 break; 493 case ECOMM: 494 fprintf(stderr, 495 gettext("%s: warning: broken link detected\n"), myname); 496 break; 497 default: 498 perror(myname); 499 fprintf(stderr, gettext("%s: cannot unmount %s\n"), myname, sp); 500 } 501 } 502 503 void 504 usage(void) 505 { 506 fprintf(stderr, gettext( 507 "Usage:\n%s [-f] [-V] [-o specific_options] {special | mount-point}\n"), 508 myname); 509 fprintf(stderr, gettext( 510 "%s -a [-f] [-V] [-o specific_options] [mount_point ...]\n"), myname); 511 exit(1); 512 } 513 514 void 515 mnterror(int flag) 516 { 517 switch (flag) { 518 case MNT_TOOLONG: 519 fprintf(stderr, 520 gettext("%s: line in mnttab exceeds %d characters\n"), 521 myname, MNT_LINE_MAX-2); 522 break; 523 case MNT_TOOFEW: 524 fprintf(stderr, 525 gettext("%s: line in mnttab has too few entries\n"), 526 myname); 527 break; 528 default: 529 break; 530 } 531 } 532 533 /* 534 * Search the mlist linked list for the 535 * first match of specp or mntp. The list is expected to be in reverse 536 * order of /etc/mnttab. 537 * If both are specified, then both have to match. 538 * Returns the (mountent_t *) of the match, otherwise returns NULL. 539 */ 540 mountent_t * 541 getmntlast(mountent_t *mlist, char *specp, char *mntp) 542 { 543 int mfound, sfound; 544 545 for (/* */; mlist; mlist = mlist->link) { 546 mfound = sfound = 0; 547 if (mntp && (strcmp(mlist->ment.mnt_mountp, mntp) == 0)) { 548 if (specp == NULL) 549 return (mlist); 550 mfound++; 551 } 552 if (specp && (strcmp(mlist->ment.mnt_special, specp) == 0)) { 553 if (mntp == NULL) 554 return (mlist); 555 sfound++; 556 } 557 if (mfound && sfound) 558 return (mlist); 559 } 560 return (NULL); 561 } 562 563 564 565 /* 566 * Perform the parallel version of umount. Returns 0 if no errors occurred, 567 * non zero otherwise. 568 */ 569 int 570 parumount(char **mntlist, int count) 571 { 572 int maxfd = OPEN_MAX; 573 struct rlimit rl; 574 mountent_t **mntarray, **ml, *mp; 575 576 /* 577 * If no mount points are specified and none were found in mnttab, 578 * then end it all here. 579 */ 580 if (count == 0 && mntll == NULL) 581 return (0); 582 583 /* 584 * This is the process scaling section. After running a series 585 * of tests based on the number of simultaneous processes and 586 * processors available, optimum performance was achieved near or 587 * at (PROCN * 2). 588 */ 589 if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1) 590 maxrun = 4; 591 else 592 maxrun = maxrun * 2 + 1; 593 594 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 595 rl.rlim_cur = rl.rlim_max; 596 if (setrlimit(RLIMIT_NOFILE, &rl) == 0) 597 maxfd = (int)rl.rlim_cur; 598 (void) enable_extended_FILE_stdio(-1, -1); 599 } 600 601 /* 602 * The parent needs to maintain 3 of its own fd's, plus 2 for 603 * each child (the stdout and stderr pipes). 604 */ 605 maxfd = (maxfd / 2) - 6; /* 6 takes care of temporary */ 606 /* periods of open fds */ 607 if (maxfd < maxrun) 608 maxrun = maxfd; 609 if (maxrun < 4) 610 maxrun = 4; /* sanity check */ 611 612 mntarray = make_mntarray(mntlist, count); 613 614 if (listlength == 0) { 615 if (count == 0) /* not an error, just none found */ 616 return (0); 617 fprintf(stderr, gettext("%s: no valid entries found in %s\n"), 618 myname, mnttab); 619 return (1); 620 } 621 622 /* 623 * Sort the entries based on their mount level only if lofs's are 624 * not present. 625 */ 626 if (lofscnt == 0) { 627 qsort((void *)mntarray, listlength, sizeof (mountent_t *), 628 mcompar); 629 /* 630 * If we do not detect a lofs by now, we never will. 631 */ 632 lofscnt = -1; 633 } 634 /* 635 * Now link them up so that a given pid is easier to find when 636 * we go to clean up after they are done. 637 */ 638 mntll = mntarray[0]; 639 for (ml = mntarray; mp = *ml; /* */) 640 mp->link = *++ml; 641 642 /* 643 * Try to handle interrupts in a reasonable way. 644 */ 645 sigset(SIGHUP, cleanup); 646 sigset(SIGQUIT, cleanup); 647 sigset(SIGINT, cleanup); 648 649 do_umounts(mntarray); /* do the umounts */ 650 return (exitcode); 651 } 652 653 /* 654 * Returns a mountent_t array based on mntlist. If mntlist is NULL, then 655 * it returns all mnttab entries with a few exceptions. Sets the global 656 * variable listlength to the number of entries in the array. 657 */ 658 mountent_t ** 659 make_mntarray(char **mntlist, int count) 660 { 661 mountent_t *mp, **mpp; 662 int ndx; 663 char *cp; 664 665 if (count > 0) 666 listlength = count; 667 668 mpp = (mountent_t **)malloc(sizeof (*mp) * (listlength + 1)); 669 if (mpp == NULL) 670 nomem(); 671 672 if (count == 0) { 673 if (mntll == NULL) { /* no entries? */ 674 listlength = 0; 675 return (NULL); 676 } 677 /* 678 * No mount list specified: take all mnttab mount points 679 * except for a few cases. 680 */ 681 for (ndx = 0, mp = mntll; mp; mp = mp->link) { 682 if (fsstrinlist(mp->ment.mnt_mountp, keeplist)) 683 continue; 684 mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp); 685 if (mp->ment.mnt_fstype && 686 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0)) 687 lofscnt++; 688 689 mpp[ndx++] = mp; 690 } 691 mpp[ndx] = NULL; 692 listlength = ndx; 693 return (mpp); 694 } 695 696 /* 697 * A list of mount points was specified on the command line. 698 * Build an array out of these. 699 */ 700 for (ndx = 0; count--; ) { 701 cp = *mntlist++; 702 if (realpath(cp, resolve) == NULL) { 703 fprintf(stderr, 704 gettext("%s: warning: can't resolve %s\n"), 705 myname, cp); 706 exitcode = 1; 707 mp = getmntlast(mntll, NULL, cp); /* try anyways */ 708 } else 709 mp = getmntlast(mntll, NULL, resolve); 710 if (mp == NULL) { 711 struct mnttab mnew; 712 /* 713 * Then we've reached the end without finding 714 * what we are looking for, but we still have to 715 * try to umount it: append it to mntarray. 716 */ 717 fprintf(stderr, gettext( 718 "%s: warning: %s not found in %s\n"), 719 myname, resolve, mnttab); 720 exitcode = 1; 721 mntnull(&mnew); 722 mnew.mnt_special = mnew.mnt_mountp = strdup(resolve); 723 if (mnew.mnt_special == NULL) 724 nomem(); 725 mp = new_mountent(&mnew); 726 } 727 if (mp->ment.mnt_fstype && 728 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0)) 729 lofscnt++; 730 731 mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp); 732 mpp[ndx++] = mp; 733 } 734 mpp[ndx] = NULL; 735 listlength = ndx; 736 return (mpp); 737 } 738 739 /* 740 * Returns the tail of a linked list of all mnttab entries. I.e, it's faster 741 * to return the mnttab in reverse order. 742 * Sets listlength to the number of entries in the list. 743 * Returns NULL if none are found. 744 */ 745 mountent_t * 746 getmntall(void) 747 { 748 FILE *fp; 749 mountent_t *mtail; 750 int cnt = 0, ret; 751 struct mnttab mget; 752 753 if ((fp = fopen(mnttab, "r")) == NULL) { 754 fprintf(stderr, gettext("%s: warning cannot open %s\n"), 755 myname, mnttab); 756 return (0); 757 } 758 mtail = NULL; 759 760 while ((ret = getmntent(fp, &mget)) != -1) { 761 mountent_t *mp; 762 763 if (ret > 0) { 764 mnterror(ret); 765 continue; 766 } 767 768 mp = new_mountent(&mget); 769 mp->link = mtail; 770 mtail = mp; 771 cnt++; 772 } 773 fclose(fp); 774 if (mtail == NULL) { 775 listlength = 0; 776 return (NULL); 777 } 778 listlength = cnt; 779 return (mtail); 780 } 781 782 void 783 do_umounts(mountent_t **mntarray) 784 { 785 mountent_t *mp, *mpprev, **ml = mntarray; 786 int cnt = listlength; 787 788 /* 789 * Main loop for the forked children: 790 */ 791 for (mpprev = *ml; mp = *ml; mpprev = mp, ml++, cnt--) { 792 pid_t pid; 793 794 /* 795 * Check to see if we cross a mount level: e.g., 796 * /a/b/c -> /a/b. If so, we need to wait for all current 797 * umounts to finish before umounting the rest. 798 * 799 * Also, we unmount serially as long as there are lofs's 800 * to mount to avoid improper umount ordering. 801 */ 802 if (mp->mlevel < mpprev->mlevel || lofscnt > 0) 803 while (nrun > 0 && (dowait() != -1)) 804 ; 805 806 if (lofscnt == 0) { 807 /* 808 * We can now go to parallel umounting. 809 */ 810 qsort((void *)ml, cnt, sizeof (mountent_t *), mcompar); 811 mp = *ml; /* possible first entry */ 812 lofscnt--; /* so we don't do this again */ 813 } 814 815 while (setup_iopipe(mp) == -1 && (dowait() != -1)) 816 ; 817 818 while (nrun >= maxrun && (dowait() != -1)) /* throttle */ 819 ; 820 821 #ifdef CACHEFS_BUG 822 /* 823 * If this is the back file system, then let cachefs/umount 824 * unmount it. 825 */ 826 if (strstr(mp->ment.mnt_mountp, BACKMNT_NAME)) 827 continue; 828 829 830 if (mp->ment.mnt_fstype && 831 (strcmp(mp->ment.mnt_fstype, "cachefs") == 0)) { 832 while (cachefs_running && (dowait() != -1)) 833 ; 834 cachefs_running = 1; 835 } 836 #endif 837 838 if ((pid = fork()) == -1) { 839 perror("fork"); 840 cleanup(-1); 841 /* not reached */ 842 } 843 #ifdef DEBUG 844 if (dflg && pid > 0) { 845 fprintf(stderr, "parent %d: umounting %d %s\n", 846 getpid(), pid, mp->ment.mnt_mountp); 847 } 848 #endif 849 if (pid == 0) { /* child */ 850 signal(SIGHUP, SIG_IGN); 851 signal(SIGQUIT, SIG_IGN); 852 signal(SIGINT, SIG_IGN); 853 setup_output(mp); 854 doexec(&mp->ment); 855 perror("exec"); 856 exit(1); 857 } 858 859 /* parent */ 860 (void) close(mp->sopipe[WRPIPE]); 861 (void) close(mp->sepipe[WRPIPE]); 862 mp->pid = pid; 863 nrun++; 864 } 865 cleanup(0); 866 } 867 868 /* 869 * cleanup the existing children and exit with an error 870 * if asig != 0. 871 */ 872 void 873 cleanup(int asig) 874 { 875 /* 876 * Let the stragglers finish. 877 */ 878 while (nrun > 0 && (dowait() != -1)) 879 ; 880 if (asig != 0) 881 exit(1); 882 } 883 884 885 /* 886 * Waits for 1 child to die. 887 * 888 * Returns -1 if no children are left to wait for. 889 * Returns 0 if a child died without an error. 890 * Returns 1 if a child died with an error. 891 * Sets the global exitcode if an error occurred. 892 */ 893 int 894 dowait(void) 895 { 896 int wstat, child, ret; 897 mountent_t *mp, *prevp; 898 899 if ((child = wait(&wstat)) == -1) 900 return (-1); 901 902 if (WIFEXITED(wstat)) /* this should always be true */ 903 ret = WEXITSTATUS(wstat); 904 else 905 ret = 1; /* assume some kind of error */ 906 nrun--; 907 if (ret) 908 exitcode = 1; 909 910 /* 911 * Find our child so we can process its std output, if any. 912 * This search gets smaller and smaller as children are cleaned 913 * up. 914 */ 915 for (prevp = NULL, mp = mntll; mp; mp = mp->link) { 916 if (mp->pid != child) { 917 prevp = mp; 918 continue; 919 } 920 /* 921 * Found: let's remove it from this list. 922 */ 923 if (prevp) { 924 prevp->link = mp->link; 925 mp->link = NULL; 926 } 927 break; 928 } 929 930 if (mp == NULL) { 931 /* 932 * This should never happen. 933 */ 934 #ifdef DEBUG 935 fprintf(stderr, gettext( 936 "%s: unknown child %d\n"), myname, child); 937 #endif 938 exitcode = 1; 939 return (1); 940 } 941 doio(mp); /* Any output? */ 942 943 if (mp->ment.mnt_fstype && 944 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0)) 945 lofscnt--; 946 947 #ifdef CACHEFS_BUG 948 if (mp->ment.mnt_fstype && 949 (strcmp(mp->ment.mnt_fstype, "cachefs") == 0)) 950 cachefs_running = 0; 951 #endif 952 953 return (ret); 954 } 955 956 static const mountent_t zmount = { 0 }; 957 958 mountent_t * 959 new_mountent(struct mnttab *ment) 960 { 961 mountent_t *new; 962 963 new = (mountent_t *)malloc(sizeof (*new)); 964 if (new == NULL) 965 nomem(); 966 967 *new = zmount; 968 if (ment->mnt_special && 969 (new->ment.mnt_special = strdup(ment->mnt_special)) == NULL) 970 nomem(); 971 if (ment->mnt_mountp && 972 (new->ment.mnt_mountp = strdup(ment->mnt_mountp)) == NULL) 973 nomem(); 974 if (ment->mnt_fstype && 975 (new->ment.mnt_fstype = strdup(ment->mnt_fstype)) == NULL) 976 nomem(); 977 return (new); 978 } 979 980 981 /* 982 * Sort in descending order of "mount level". For example, /a/b/c is 983 * placed before /a/b . 984 */ 985 int 986 mcompar(const void *a, const void *b) 987 { 988 mountent_t *a1, *b1; 989 990 a1 = *(mountent_t **)a; 991 b1 = *(mountent_t **)b; 992 return (b1->mlevel - a1->mlevel); 993 } 994 995 /* 996 * The purpose of this routine is to form stdout and stderr 997 * pipes for the children's output. The parent then reads and writes it 998 * out it serially in order to ensure that the output is 999 * not garbled. 1000 */ 1001 1002 int 1003 setup_iopipe(mountent_t *mp) 1004 { 1005 /* 1006 * Make a stdout and stderr pipe. This should never fail. 1007 */ 1008 if (pipe(mp->sopipe) == -1) 1009 return (-1); 1010 if (pipe(mp->sepipe) == -1) { 1011 (void) close(mp->sopipe[RDPIPE]); 1012 (void) close(mp->sopipe[WRPIPE]); 1013 return (-1); 1014 } 1015 /* 1016 * Don't block on an empty pipe. 1017 */ 1018 (void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK); 1019 (void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK); 1020 return (0); 1021 } 1022 1023 /* 1024 * Called by a child to attach its stdout and stderr to the write side of 1025 * the pipes. 1026 */ 1027 void 1028 setup_output(mountent_t *mp) 1029 { 1030 (void) close(fileno(stdout)); 1031 (void) dup(mp->sopipe[WRPIPE]); 1032 (void) close(mp->sopipe[WRPIPE]); 1033 1034 (void) close(fileno(stderr)); 1035 (void) dup(mp->sepipe[WRPIPE]); 1036 (void) close(mp->sepipe[WRPIPE]); 1037 } 1038 1039 /* 1040 * Parent uses this to print any stdout or stderr output issued by 1041 * the child. 1042 */ 1043 static void 1044 doio(mountent_t *mp) 1045 { 1046 int bytes; 1047 1048 while ((bytes = read(mp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0) 1049 write(fileno(stderr), ibuf, bytes); 1050 while ((bytes = read(mp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0) 1051 write(fileno(stdout), ibuf, bytes); 1052 1053 (void) close(mp->sopipe[RDPIPE]); 1054 (void) close(mp->sepipe[RDPIPE]); 1055 } 1056 1057 void 1058 nomem(void) 1059 { 1060 fprintf(stderr, gettext("%s: out of memory\n"), myname); 1061 /* 1062 * Let the stragglers finish. 1063 */ 1064 while (nrun > 0 && (dowait() != -1)) 1065 ; 1066 exit(1); 1067 }