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 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ 22 /* All Rights Reserved */ 23 24 25 /* 26 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 #include <stdio.h> 31 #include <stdio_ext.h> 32 #include <limits.h> 33 #include <fcntl.h> 34 #include <unistd.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <stdarg.h> 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 #include <sys/statvfs.h> 41 #include <errno.h> 42 #include <sys/mnttab.h> 43 #include <sys/mntent.h> 44 #include <sys/mount.h> 45 #include <sys/vfstab.h> 46 #include <sys/param.h> 47 #include <sys/wait.h> 48 #include <sys/signal.h> 49 #include <sys/resource.h> 50 #include <stropts.h> 51 #include <sys/conf.h> 52 #include <locale.h> 53 #include "fslib.h" 54 55 #define VFS_PATH "/usr/lib/fs" 56 #define ALT_PATH "/etc/fs" 57 #define REMOTE "/etc/dfs/fstypes" 58 59 #define ARGV_MAX 16 60 #define TIME_MAX 50 61 #define FSTYPE_MAX 8 62 #define REMOTE_MAX 64 63 64 #define OLD 0 65 #define NEW 1 66 67 #define READONLY 0 68 #define READWRITE 1 69 #define SUID 2 70 #define NOSUID 3 71 #define SETUID 4 72 #define NOSETUID 5 73 #define DEVICES 6 74 #define NODEVICES 7 75 76 #define FORMAT "%a %b %e %H:%M:%S %Y\n" /* date time format */ 77 /* a - abbreviated weekday name */ 78 /* b - abbreviated month name */ 79 /* e - day of month */ 80 /* H - hour */ 81 /* M - minute */ 82 /* S - second */ 83 /* Y - Year */ 84 /* n - newline */ 85 86 /* 87 * The fs-local method understands this exit code to mean that one or 88 * more failures occurred and that all the failures were of attempted 89 * lofs mounts. 90 */ 91 #define ALL_LOFS_FAILURES 111 92 93 extern int optind; 94 extern char *optarg; 95 96 extern void usage(void); 97 extern char *flags(char *, int); 98 extern char *remote(char *, FILE *); 99 extern char *default_fstype(char *); 100 101 char *myopts[] = { 102 MNTOPT_RO, 103 MNTOPT_RW, 104 MNTOPT_SUID, 105 MNTOPT_NOSUID, 106 MNTOPT_SETUID, 107 MNTOPT_NOSETUID, 108 MNTOPT_DEVICES, 109 MNTOPT_NODEVICES, 110 NULL 111 }; 112 113 static char *myname; /* point to argv[0] */ 114 115 /* 116 * Set the limit to double the number of characters a user should be allowed to 117 * type in one line. 118 * This should cover the different shells, which don't use POSIX_MAX_INPUT, 119 * and should cover the case where a long option string can be in 120 * the /etc/vfstab file. 121 */ 122 char mntflags[(_POSIX_MAX_INPUT+1) * 2]; 123 124 char realdir[MAXPATHLEN]; /* buffer for realpath() calls */ 125 char *vfstab = VFSTAB; 126 char *mnttab = MNTTAB; 127 char *specific_opts; /* holds specific mount options */ 128 char *generic_opts; /* holds generic mount options */ 129 int maxrun; 130 int nrun; 131 int failcnt; /* total count of failures */ 132 int lofscnt; /* presence of lofs prohibits parallel */ 133 /* mounting */ 134 int lofsfail; /* count of failures of lofs mounts */ 135 int exitcode; 136 int aflg, cflg, fflg, Fflg, gflg, oflg, pflg, rflg, vflg, Vflg, mflg, Oflg, 137 dashflg, questflg, dflg, qflg; 138 139 /* 140 * Currently, mounting cachefs instances simultaneously uncovers various 141 * problems. For the short term, we serialize cachefs activity while we fix 142 * these cachefs bugs. 143 */ 144 #define CACHEFS_BUG 145 #ifdef CACHEFS_BUG 146 int cachefs_running; /* parallel cachefs not supported yet */ 147 #endif 148 149 /* 150 * Each vfsent_t describes a vfstab entry. It is used to manage and cleanup 151 * each child that performs the particular mount for the entry. 152 */ 153 154 typedef struct vfsent { 155 struct vfstab v; /* the vfstab entry */ 156 char *rpath; /* resolved pathname so far */ 157 int mlevel; /* how deep is this mount point */ 158 int order; /* vfstab serial order of this vfs */ 159 int flag; 160 pid_t pid; /* the pid of this mount process */ 161 int exitcode; /* process's exitcode */ 162 #define RDPIPE 0 163 #define WRPIPE 1 164 int sopipe[2]; /* pipe attached to child's stdout */ 165 int sepipe[2]; /* pipe attached to child's stderr */ 166 struct vfsent *next; /* used when in linked list */ 167 } vfsent_t; 168 169 #define VRPFAILED 0x01 /* most recent realpath failed on */ 170 /* this mount point */ 171 #define VNOTMOUNTED 0x02 /* mount point could not be mounted */ 172 173 vfsent_t *vfsll, *vfslltail; /* head and tail of the global */ 174 /* linked list of vfstab entries */ 175 vfsent_t **vfsarray; /* global array of vfsent_t's */ 176 int vfsarraysize; /* length of the list */ 177 178 /* 179 * This structure is used to build a linked list of 180 * mnttab structures from /etc/mnttab. 181 */ 182 typedef struct mountent { 183 struct extmnttab *ment; 184 int flag; 185 struct mountent *next; 186 } mountent_t; 187 188 #define MSORTED 0x1 189 190 static vfsent_t **make_vfsarray(char **, int); 191 static vfsent_t *new_vfsent(struct vfstab *, int); 192 static vfsent_t *getvfsall(char *, int); 193 194 static void doexec(char *, char **); 195 static void nomem(); 196 static void cleanup(int); 197 static char *setrpath(vfsent_t *); 198 static int dowait(); 199 static int setup_iopipe(vfsent_t *); 200 static void setup_output(vfsent_t *); 201 static void doio(vfsent_t *); 202 static void do_mounts(); 203 static int parmount(char **, int, char *); 204 static int mlevelcmp(const void *, const void *); 205 static int mordercmp(const void *, const void *); 206 static int check_fields(char *, char *); 207 static int cleanupkid(pid_t, int); 208 static void print_mnttab(int, int); 209 static void vfserror(int, char *); 210 static void mnterror(int); 211 static int ignore(char *); 212 213 /* 214 * This is /usr/sbin/mount: the generic command that in turn 215 * execs the appropriate /usr/lib/fs/{fstype}/mount. 216 * The -F flag and argument are NOT passed. 217 * If the usr file system is not mounted a duplicate copy 218 * can be found in /sbin and this version execs the 219 * appropriate /etc/fs/{fstype}/mount 220 * 221 * If the -F fstype, special or directory are missing, 222 * /etc/vfstab is searched to fill in the missing arguments. 223 * 224 * -V will print the built command on the stdout. 225 * It isn't passed either. 226 */ 227 int 228 main(int argc, char *argv[]) 229 { 230 char *special, /* argument of special/resource */ 231 *mountp, /* argument of mount directory */ 232 *fstype, /* wherein the fstype name is filled */ 233 *newargv[ARGV_MAX], /* arg list for specific command */ 234 *farg = NULL, *Farg = NULL; 235 int ii, ret, cc, fscnt; 236 struct stat64 stbuf; 237 struct vfstab vget, vref; 238 mode_t mode; 239 FILE *fd; 240 241 (void) setlocale(LC_ALL, ""); 242 243 #if !defined(TEXT_DOMAIN) 244 #define TEXT_DOMAIN "SYS_TEST" 245 #endif 246 (void) textdomain(TEXT_DOMAIN); 247 248 myname = strrchr(argv[0], '/'); 249 if (myname) 250 myname++; 251 else 252 myname = argv[0]; 253 if (myname == 0) myname = "path unknown"; 254 255 /* Process the args. */ 256 257 while ((cc = getopt(argc, argv, "?acd:f:F:gmno:pqrvVO")) != -1) 258 switch (cc) { 259 case 'a': 260 aflg++; 261 break; 262 case 'c': 263 cflg++; 264 break; 265 266 #ifdef DEBUG 267 case 'd': 268 dflg = atoi(optarg); 269 break; 270 #endif 271 272 case 'f': 273 fflg++; 274 farg = optarg; 275 break; 276 case 'F': 277 Fflg++; 278 Farg = optarg; 279 break; 280 case 'g': 281 gflg++; 282 break; 283 case 'm': 284 mflg++; 285 break; /* do not update /etc/mnttab */ 286 case 'o': 287 oflg++; 288 if ((specific_opts = strdup(optarg)) == NULL) 289 nomem(); 290 break; /* fstype dependent options */ 291 case 'O': 292 Oflg++; 293 break; 294 case 'p': 295 pflg++; 296 break; 297 case 'q': 298 qflg++; 299 break; 300 case 'r': 301 rflg++; 302 generic_opts = "ro"; 303 break; 304 case 'v': 305 vflg++; 306 break; 307 case 'V': 308 Vflg++; 309 break; 310 case '?': 311 questflg++; 312 break; 313 } 314 315 /* copy '--' to specific */ 316 if (strcmp(argv[optind-1], "--") == 0) 317 dashflg++; 318 319 /* option checking */ 320 /* more than two args not allowed if !aflg */ 321 if (!aflg && (argc - optind > 2)) 322 usage(); 323 324 /* pv mututally exclusive */ 325 if (pflg + vflg + aflg > 1) { 326 fprintf(stderr, gettext 327 ("%s: -a, -p, and -v are mutually exclusive\n"), 328 myname); 329 usage(); 330 } 331 332 /* 333 * Can't have overlaying mounts on the same mount point during 334 * a parallel mount. 335 */ 336 if (aflg && Oflg) { 337 fprintf(stderr, gettext 338 ("%s: -a and -O are mutually exclusive\n"), myname); 339 usage(); 340 } 341 342 /* dfF mutually exclusive */ 343 if (fflg + Fflg > 1) { 344 fprintf(stderr, gettext 345 ("%s: More than one FSType specified\n"), myname); 346 usage(); 347 } 348 349 /* no arguments, only allow p,v,V or [F]? */ 350 if (!aflg && optind == argc) { 351 if (cflg || fflg || mflg || oflg || rflg || qflg) 352 usage(); 353 354 if (Fflg && !questflg) 355 usage(); 356 357 if (questflg) { 358 if (Fflg) { 359 newargv[2] = "-?"; 360 newargv[3] = NULL; 361 doexec(Farg, newargv); 362 } 363 usage(); 364 } 365 } 366 367 if (questflg) 368 usage(); 369 370 /* one or two args, allow any but p,v */ 371 if (optind != argc && (pflg || vflg)) { 372 fprintf(stderr, 373 gettext("%s: Cannot use -p and -v with arguments\n"), myname); 374 usage(); 375 } 376 377 378 /* if only reporting mnttab, generic prints mnttab and exits */ 379 if (!aflg && optind == argc) { 380 if (Vflg) { 381 printf("%s", myname); 382 if (pflg) 383 printf(" -p"); 384 if (vflg) 385 printf(" -v"); 386 printf("\n"); 387 exit(0); 388 } 389 390 print_mnttab(vflg, pflg); 391 exit(0); 392 } 393 394 /* 395 * Get filesystem type here. If "-F FStype" is specified, use 396 * that fs type. Otherwise, determine the fs type from /etc/vfstab 397 * if the entry exists. Otherwise, determine the local or remote 398 * fs type from /etc/default/df or /etc/dfs/fstypes respectively. 399 */ 400 if (fflg) { 401 if ((strcmp(farg, "S51K") != 0) && 402 (strcmp(farg, "S52K") != 0)) { 403 fstype = farg; 404 } 405 else 406 fstype = "ufs"; 407 } else /* if (Fflg) */ 408 fstype = Farg; 409 410 fscnt = argc - optind; 411 if (aflg && (fscnt != 1)) 412 exit(parmount(argv + optind, fscnt, fstype)); 413 414 /* 415 * Then don't bother with the parallel over head. Everything 416 * from this point is simple/normal single execution. 417 */ 418 aflg = 0; 419 420 /* get special and/or mount-point from arg(s) */ 421 if (fscnt == 2) 422 special = argv[optind++]; 423 else 424 special = NULL; 425 if (optind < argc) 426 mountp = argv[optind++]; 427 else 428 mountp = NULL; 429 430 /* lookup only if we need to */ 431 if (fstype == NULL || specific_opts == NULL || special == NULL || 432 mountp == NULL) { 433 if ((fd = fopen(vfstab, "r")) == NULL) { 434 if (fstype == NULL || special == NULL || 435 mountp == NULL) { 436 fprintf(stderr, gettext( 437 "%s: Cannot open %s\n"), 438 myname, vfstab); 439 exit(1); 440 } else { 441 /* 442 * No vfstab, but we know what we want 443 * to mount. 444 */ 445 goto out; 446 } 447 } 448 vfsnull(&vref); 449 vref.vfs_special = special; 450 vref.vfs_mountp = mountp; 451 vref.vfs_fstype = fstype; 452 453 /* get a vfstab entry matching mountp or special */ 454 while ((ret = getvfsany(fd, &vget, &vref)) > 0) 455 vfserror(ret, vget.vfs_special); 456 457 /* if no entry and there was only one argument */ 458 /* then the argument could be the special */ 459 /* and not mount point as we thought earlier */ 460 if (ret == -1 && special == NULL) { 461 rewind(fd); 462 special = vref.vfs_special = mountp; 463 mountp = vref.vfs_mountp = NULL; 464 /* skip erroneous lines; they were reported above */ 465 while ((ret = getvfsany(fd, &vget, &vref)) > 0) 466 ; 467 } 468 469 fclose(fd); 470 471 if (ret == 0) { 472 if (fstype == NULL) 473 fstype = vget.vfs_fstype; 474 if (special == NULL) 475 special = vget.vfs_special; 476 if (mountp == NULL) 477 mountp = vget.vfs_mountp; 478 if (oflg == 0 && vget.vfs_mntopts) { 479 oflg++; 480 specific_opts = vget.vfs_mntopts; 481 } 482 } else if (special == NULL) { 483 if (stat64(mountp, &stbuf) == -1) { 484 fprintf(stderr, gettext("%s: cannot stat %s\n"), 485 myname, mountp); 486 exit(2); 487 } 488 if (((mode = (stbuf.st_mode & S_IFMT)) == S_IFBLK) || 489 (mode == S_IFCHR)) { 490 fprintf(stderr, 491 gettext("%s: mount point cannot be determined\n"), 492 myname); 493 exit(1); 494 } else 495 { 496 fprintf(stderr, 497 gettext("%s: special cannot be determined\n"), 498 myname); 499 exit(1); 500 } 501 } else if (fstype == NULL) 502 fstype = default_fstype(special); 503 } 504 505 out: 506 if (check_fields(fstype, mountp)) 507 exit(1); 508 509 if (realpath(mountp, realdir) == NULL) { 510 (void) fprintf(stderr, "mount: "); 511 perror(mountp); 512 exit(1); 513 } 514 515 if ((mountp = strdup(realdir)) == NULL) 516 nomem(); 517 518 /* create the new arg list, and end the list with a null pointer */ 519 ii = 2; 520 if (cflg) 521 newargv[ii++] = "-c"; 522 if (gflg) 523 newargv[ii++] = "-g"; 524 if (mflg) 525 newargv[ii++] = "-m"; 526 /* 527 * The q option needs to go before the -o option as some 528 * filesystems complain during first pass option parsing. 529 */ 530 if (qflg) 531 newargv[ii++] = "-q"; 532 if (oflg) { 533 newargv[ii++] = "-o"; 534 newargv[ii++] = specific_opts; 535 } 536 if (Oflg) 537 newargv[ii++] = "-O"; 538 if (rflg) 539 newargv[ii++] = "-r"; 540 if (dashflg) 541 newargv[ii++] = "--"; 542 newargv[ii++] = special; 543 newargv[ii++] = mountp; 544 newargv[ii] = NULL; 545 546 doexec(fstype, newargv); 547 return (0); 548 } 549 550 void 551 usage(void) 552 { 553 fprintf(stderr, gettext("Usage:\n%s [-v | -p]\n"), myname); 554 fprintf(stderr, gettext( 555 "%s [-F FSType] [-V] [current_options] [-o specific_options]"), 556 myname); 557 fprintf(stderr, gettext("\n\t{special | mount_point}\n")); 558 559 fprintf(stderr, gettext( 560 "%s [-F FSType] [-V] [current_options] [-o specific_options]"), 561 myname); 562 fprintf(stderr, gettext("\n\tspecial mount_point\n")); 563 564 fprintf(stderr, gettext( 565 "%s -a [-F FSType ] [-V] [current_options] [-o specific_options]\n"), 566 myname); 567 fprintf(stderr, gettext("\t[mount_point ...]\n")); 568 569 exit(1); 570 } 571 572 /* 573 * Get rid of "dev=[hex string]" clause, if any. It's not legal 574 * when printing in vfstab format. 575 */ 576 void 577 elide_dev(char *mntopts) 578 { 579 char *dev, *other; 580 581 if (mntopts != NULL) { 582 dev = strstr(mntopts, "dev="); 583 if (dev != NULL) { 584 other = strpbrk(dev, ","); 585 if (other == NULL) { 586 /* last option */ 587 if (dev != mntopts) { 588 *--dev = '\0'; 589 } else { 590 *dev = '\0'; 591 } 592 } else { 593 /* first or intermediate option */ 594 memmove(dev, other+1, strlen(other+1)+1); 595 } 596 } 597 } 598 } 599 600 void 601 print_mnttab(int vflg, int pflg) 602 { 603 FILE *fd; 604 FILE *rfp; /* this will be NULL if fopen fails */ 605 int ret; 606 char time_buf[TIME_MAX]; /* array to hold date and time */ 607 struct extmnttab mget; 608 time_t ltime; 609 610 if ((fd = fopen(mnttab, "r")) == NULL) { 611 fprintf(stderr, gettext("%s: Cannot open mnttab\n"), myname); 612 exit(1); 613 } 614 rfp = fopen(REMOTE, "r"); 615 while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab))) 616 == 0) { 617 if (ignore(mget.mnt_mntopts)) 618 continue; 619 if (mget.mnt_special && mget.mnt_mountp && 620 mget.mnt_fstype && mget.mnt_time) { 621 ltime = atol(mget.mnt_time); 622 cftime(time_buf, FORMAT, <ime); 623 if (pflg) { 624 elide_dev(mget.mnt_mntopts); 625 printf("%s - %s %s - no %s\n", 626 mget.mnt_special, 627 mget.mnt_mountp, 628 mget.mnt_fstype, 629 mget.mnt_mntopts != NULL ? 630 mget.mnt_mntopts : "-"); 631 } else if (vflg) { 632 printf("%s on %s type %s %s%s on %s", 633 mget.mnt_special, 634 mget.mnt_mountp, 635 mget.mnt_fstype, 636 remote(mget.mnt_fstype, rfp), 637 flags(mget.mnt_mntopts, NEW), 638 time_buf); 639 } else 640 printf("%s on %s %s%s on %s", 641 mget.mnt_mountp, 642 mget.mnt_special, 643 remote(mget.mnt_fstype, rfp), 644 flags(mget.mnt_mntopts, OLD), 645 time_buf); 646 } 647 } 648 if (ret > 0) 649 mnterror(ret); 650 } 651 652 char * 653 flags(char *mntopts, int flag) 654 { 655 char opts[sizeof (mntflags)]; 656 char *value; 657 int rdwr = 1; 658 int suid = 1; 659 int devices = 1; 660 int setuid = 1; 661 662 if (mntopts == NULL || *mntopts == '\0') 663 return ("read/write/setuid/devices"); 664 665 strcpy(opts, ""); 666 while (*mntopts != '\0') { 667 switch (getsubopt(&mntopts, myopts, &value)) { 668 case READONLY: 669 rdwr = 0; 670 break; 671 case READWRITE: 672 rdwr = 1; 673 break; 674 case SUID: 675 suid = 1; 676 break; 677 case NOSUID: 678 suid = 0; 679 break; 680 case SETUID: 681 setuid = 1; 682 break; 683 case NOSETUID: 684 setuid = 0; 685 break; 686 case DEVICES: 687 devices = 1; 688 break; 689 case NODEVICES: 690 devices = 0; 691 break; 692 default: 693 /* cat '/' separator to mntflags */ 694 if (*opts != '\0' && value != NULL) 695 strcat(opts, "/"); 696 strcat(opts, value); 697 break; 698 } 699 } 700 701 strcpy(mntflags, ""); 702 if (rdwr) 703 strcat(mntflags, "read/write"); 704 else if (flag == OLD) 705 strcat(mntflags, "read only"); 706 else 707 strcat(mntflags, "read-only"); 708 if (suid) { 709 if (setuid) 710 strcat(mntflags, "/setuid"); 711 else 712 strcat(mntflags, "/nosetuid"); 713 if (devices) 714 strcat(mntflags, "/devices"); 715 else 716 strcat(mntflags, "/nodevices"); 717 } else { 718 strcat(mntflags, "/nosetuid/nodevices"); 719 } 720 if (*opts != '\0') { 721 strcat(mntflags, "/"); 722 strcat(mntflags, opts); 723 } 724 725 /* 726 * The assumed assertion 727 * assert (strlen(mntflags) < sizeof mntflags); 728 * is valid at this point in the code. Note that a call to "assert" 729 * is not appropriate in production code since it halts the program. 730 */ 731 return (mntflags); 732 } 733 734 char * 735 remote(char *fstype, FILE *rfp) 736 { 737 char buf[BUFSIZ]; 738 char *fs; 739 extern char *strtok(); 740 741 if (rfp == NULL || fstype == NULL || 742 strlen(fstype) > (size_t)FSTYPE_MAX) 743 return (""); /* not a remote */ 744 rewind(rfp); 745 while (fgets(buf, sizeof (buf), rfp) != NULL) { 746 fs = strtok(buf, " \t\n"); 747 if (strcmp(fstype, fs) == 0) 748 return ("remote/"); /* is a remote fs */ 749 } 750 return (""); /* not a remote */ 751 } 752 753 754 void 755 vfserror(int flag, char *special) 756 { 757 if (special == NULL) 758 special = "<null>"; 759 switch (flag) { 760 case VFS_TOOLONG: 761 fprintf(stderr, 762 gettext("%s: Warning: Line in vfstab for \"%s\" exceeds %d characters\n"), 763 myname, special, VFS_LINE_MAX-1); 764 break; 765 case VFS_TOOFEW: 766 fprintf(stderr, 767 gettext("%s: Warning: Line for \"%s\" in vfstab has too few entries\n"), 768 myname, special); 769 break; 770 case VFS_TOOMANY: 771 fprintf(stderr, 772 gettext("%s: Warning: Line for \"%s\" in vfstab has too many entries\n"), 773 myname, special); 774 break; 775 default: 776 fprintf(stderr, gettext( 777 "%s: Warning: Error in line for \"%s\" in vfstab\n"), 778 myname, special); 779 } 780 } 781 782 void 783 mnterror(int flag) 784 { 785 switch (flag) { 786 case MNT_TOOLONG: 787 fprintf(stderr, 788 gettext("%s: Line in mnttab exceeds %d characters\n"), 789 myname, MNT_LINE_MAX-2); 790 break; 791 case MNT_TOOFEW: 792 fprintf(stderr, 793 gettext("%s: Line in mnttab has too few entries\n"), 794 myname); 795 break; 796 case MNT_TOOMANY: 797 fprintf(stderr, 798 gettext("%s: Line in mnttab has too many entries\n"), 799 myname); 800 break; 801 } 802 exit(1); 803 } 804 805 void 806 doexec(char *fstype, char *newargv[]) 807 { 808 char full_path[PATH_MAX]; 809 char alter_path[PATH_MAX]; 810 char *vfs_path = VFS_PATH; 811 char *alt_path = ALT_PATH; 812 int i; 813 int smbfs; 814 815 /* 816 * Special case smbfs file system. 817 * Execute command in profile if possible. 818 */ 819 smbfs = strcmp(fstype, "smbfs") == 0; 820 821 /* build the full pathname of the fstype dependent command. */ 822 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname); 823 sprintf(alter_path, "%s/%s/%s", alt_path, fstype, myname); 824 newargv[1] = myname; 825 826 if (Vflg) { 827 printf("%s -F %s", newargv[1], fstype); 828 for (i = 2; newargv[i]; i++) 829 printf(" %s", newargv[i]); 830 printf("\n"); 831 fflush(stdout); 832 exit(0); 833 } 834 835 /* 836 * Try to exec the fstype dependent portion of the mount. 837 * See if the directory is there before trying to exec dependent 838 * portion. This is only useful for eliminating the 839 * '..mount: not found' message when '/usr' is mounted 840 */ 841 if (access(full_path, 0) == 0) { 842 if (smbfs) { 843 /* 844 * Run mount_smbfs(1m) with pfexec so that we can 845 * add sys_mount privilege, (via exec_attr, etc.) 846 * allowing normal users to mount on any directory 847 * they own. 848 */ 849 newargv[0] = "pfexec"; 850 newargv[1] = full_path; 851 execv("/usr/bin/pfexec", &newargv[0]); 852 newargv[1] = myname; 853 } 854 execv(full_path, &newargv[1]); 855 if (errno == EACCES) { 856 fprintf(stderr, 857 gettext("%s: Cannot execute %s - permission denied\n"), 858 myname, full_path); 859 } 860 if (errno == ENOEXEC) { 861 newargv[0] = "sh"; 862 newargv[1] = full_path; 863 execv("/sbin/sh", &newargv[0]); 864 } 865 } 866 if (smbfs) { 867 newargv[0] = "pfexec"; 868 newargv[1] = alter_path; 869 execv("/usr/bin/pfexec", &newargv[0]); 870 newargv[1] = myname; 871 } 872 execv(alter_path, &newargv[1]); 873 if (errno == EACCES) { 874 fprintf(stderr, gettext( 875 "%s: Cannot execute %s - permission denied\n"), 876 myname, alter_path); 877 exit(1); 878 } 879 if (errno == ENOEXEC) { 880 newargv[0] = "sh"; 881 newargv[1] = alter_path; 882 execv("/sbin/sh", &newargv[0]); 883 } 884 fprintf(stderr, 885 gettext("%s: Operation not applicable to FSType %s\n"), 886 myname, fstype); 887 exit(1); 888 } 889 890 char *mntopts[] = { MNTOPT_IGNORE, NULL }; 891 #define IGNORE 0 892 893 /* 894 * Return 1 if "ignore" appears in the options string 895 */ 896 int 897 ignore(char *opts) 898 { 899 char *value; 900 char *saveptr, *my_opts; 901 int rval = 0; 902 903 if (opts == NULL || *opts == NULL) 904 return (0); 905 906 /* 907 * we make a copy of the option string to pass to getsubopt(), 908 * because getsubopt() modifies the string. We also save 909 * the original pointer returned by strdup, because getsubopt 910 * changes the pointer passed into it. If strdup fails (unlikely), 911 * we act as if the "ignore" option isn't set rather than fail. 912 */ 913 914 if ((saveptr = my_opts = strdup(opts)) == NULL) 915 nomem(); 916 917 while (*my_opts != '\0') { 918 if (getsubopt(&my_opts, mntopts, &value) == IGNORE) 919 rval = 1; 920 } 921 922 free(saveptr); 923 924 return (rval); 925 } 926 927 /* 928 * Perform the parallel version of mount. If count == 0, mount all 929 * vfstab filesystems with the automnt field == "yes". Use fstype if 930 * supplied. If mntlist supplied, then attempt to only mount those. 931 */ 932 933 int 934 parmount(char **mntlist, int count, char *fstype) 935 { 936 int maxfd = OPEN_MAX; 937 struct rlimit rl; 938 vfsent_t **vl, *vp; 939 940 /* 941 * Process scaling. After running a series 942 * of tests based on the number of simultaneous processes and 943 * processors available, optimum performance was achieved near or 944 * at (PROCN * 2). 945 */ 946 if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1) 947 maxrun = 4; 948 else 949 maxrun = maxrun * 2 + 1; 950 951 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 952 rl.rlim_cur = rl.rlim_max; 953 if (setrlimit(RLIMIT_NOFILE, &rl) == 0) 954 maxfd = (int)rl.rlim_cur; 955 } 956 (void) enable_extended_FILE_stdio(-1, -1); 957 958 /* 959 * The parent needs to maintain 3 of its own fd's, plus 2 for 960 * each child (the stdout and stderr pipes). 961 */ 962 maxfd = (maxfd / 2) - 6; /* 6 takes care of temporary */ 963 /* periods of open fds */ 964 if (maxfd < maxrun) 965 maxrun = maxfd; 966 if (maxrun < 4) 967 maxrun = 4; /* sanity check */ 968 969 if (count == 0) 970 mntlist = NULL; /* used as a flag later */ 971 else 972 fstype = NULL; /* mount points supplied: */ 973 /* ignore fstype */ 974 /* 975 * Read the whole vfstab into a linked list for quick processing. 976 * On average, this is the most efficient way to collect and 977 * manipulate the vfstab data. 978 */ 979 vfsll = getvfsall(fstype, mntlist == NULL); 980 981 /* 982 * Make an array out of the vfs linked list for sorting purposes. 983 */ 984 if (vfsll == NULL || 985 (vfsarray = make_vfsarray(mntlist, count)) == NULL) { 986 if (mntlist == NULL) /* not an error - just none found */ 987 return (0); 988 989 fprintf(stderr, gettext("%s: No valid entries found in %s\n"), 990 myname, vfstab); 991 return (1); 992 } 993 994 /* 995 * Sort the entries based on their resolved path names 996 * 997 * If an lofs is encountered, then the original order of the vfstab 998 * file needs to be maintained until we are done mounting lofs's. 999 */ 1000 if (!lofscnt) 1001 qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *), 1002 mlevelcmp); 1003 1004 /* 1005 * Shrink the vfsll linked list down to the new list. This will 1006 * speed up the pid search in cleanupkid() later. 1007 */ 1008 vfsll = vfsarray[0]; 1009 for (vl = vfsarray; vp = *vl; ) 1010 vp->next = *++vl; 1011 1012 /* 1013 * Try to handle interrupts in a reasonable way. 1014 */ 1015 sigset(SIGHUP, cleanup); 1016 sigset(SIGQUIT, cleanup); 1017 sigset(SIGINT, cleanup); 1018 1019 do_mounts(); /* do the mounts */ 1020 1021 if (failcnt > 0 && failcnt == lofsfail) 1022 return (ALL_LOFS_FAILURES); 1023 1024 return (exitcode); 1025 } 1026 1027 /* 1028 * Read all vstab (fp) entries into memory if fstype == NULL. 1029 * If fstype is specified, than read all those that match it. 1030 * 1031 * Returns a linked list. 1032 */ 1033 vfsent_t * 1034 getvfsall(char *fstype, int takeall) 1035 { 1036 vfsent_t *vhead, *vtail; 1037 struct vfstab vget; 1038 FILE *fp; 1039 int cnt = 0, ret; 1040 1041 if ((fp = fopen(vfstab, "r")) == NULL) { 1042 fprintf(stderr, gettext("%s: Cannot open %s\n"), 1043 myname, vfstab); 1044 exit(1); 1045 } 1046 1047 vhead = vtail = NULL; 1048 1049 while ((ret = getvfsent(fp, &vget)) != -1) { 1050 vfsent_t *vp; 1051 1052 if (ret > 0) { 1053 vfserror(ret, vget.vfs_mountp); 1054 continue; 1055 } 1056 1057 /* 1058 * If mount points were not specified, then we ignore 1059 * entries that aren't marked "yes". 1060 */ 1061 if (takeall && 1062 (vget.vfs_automnt == NULL || 1063 strcmp(vget.vfs_automnt, "yes"))) 1064 continue; 1065 1066 if (fstype && vget.vfs_fstype && 1067 strcmp(fstype, vget.vfs_fstype)) 1068 continue; 1069 1070 if (vget.vfs_mountp == NULL || 1071 (vget.vfs_fstype && (strcmp(vget.vfs_fstype, "swap") == 0))) 1072 continue; 1073 1074 if (check_fields(vget.vfs_fstype, vget.vfs_mountp)) { 1075 exitcode = 1; 1076 continue; 1077 } 1078 1079 vp = new_vfsent(&vget, cnt); /* create new vfs entry */ 1080 if (vhead == NULL) 1081 vhead = vp; 1082 else 1083 vtail->next = vp; 1084 vtail = vp; 1085 cnt++; 1086 } 1087 fclose(fp); 1088 if (vtail == NULL) { 1089 vfsarraysize = 0; 1090 vfslltail = NULL; 1091 return (NULL); 1092 } 1093 vtail->next = NULL; 1094 vfslltail = vtail; /* save it in the global variable */ 1095 vfsarraysize = cnt; 1096 return (vhead); 1097 } 1098 1099 1100 /* 1101 * Returns an array of vfsent_t's based on vfsll & mntlist. 1102 */ 1103 vfsent_t ** 1104 make_vfsarray(char **mntlist, int count) 1105 { 1106 vfsent_t *vp, *vmark, *vpprev, **vpp; 1107 int ndx, found; 1108 1109 if (vfsll == NULL) 1110 return (NULL); 1111 1112 if (count > 0) 1113 vfsarraysize = count; 1114 1115 vpp = (vfsent_t **)malloc(sizeof (*vpp) * (vfsarraysize + 1)); 1116 if (vpp == NULL) 1117 nomem(); 1118 1119 if (mntlist == NULL) { 1120 /* 1121 * No mount list specified: take all vfstab mount points. 1122 */ 1123 for (ndx = 0, vp = vfsll; vp; vp = vp->next) { 1124 (void) setrpath(vp); 1125 /* 1126 * Sigh. lofs entries can complicate matters so much 1127 * that the best way to avoid problems is to 1128 * stop parallel mounting when an lofs is 1129 * encountered, so we keep a count of how many 1130 * there are. 1131 * Fortunately this is rare. 1132 */ 1133 if (vp->v.vfs_fstype && 1134 (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0)) 1135 lofscnt++; 1136 1137 vpp[ndx++] = vp; 1138 } 1139 vpp[ndx] = NULL; 1140 return (vpp); 1141 } 1142 1143 /* 1144 * A list of mount points was specified on the command line 1145 * and we need to search for each one. 1146 */ 1147 vpprev = vfslltail; 1148 vpprev->next = vfsll; /* make a circle out of it */ 1149 vmark = vp = vfsll; 1150 /* 1151 * For each specified mount point: 1152 */ 1153 for (ndx = 0; *mntlist; mntlist++) { 1154 found = 0; 1155 /* 1156 * Circle our entire linked list, looking for *mntlist. 1157 */ 1158 while (vp) { 1159 if (strcmp(*mntlist, vp->v.vfs_mountp) == 0) { 1160 vpp[ndx++] = vp; /* found it. */ 1161 (void) setrpath(vp); 1162 if (vp->v.vfs_fstype && 1163 (strcmp(vp->v.vfs_fstype, 1164 MNTTYPE_LOFS) == 0)) 1165 lofscnt++; 1166 1167 if (vp == vpprev) { /* list exhausted */ 1168 vp = NULL; 1169 found++; 1170 break; 1171 } 1172 /* 1173 * Remove it from the circular list. vpprev 1174 * remains unchanged. 1175 */ 1176 vp = vp->next; 1177 vpprev->next->next = NULL; 1178 vpprev->next = vp; 1179 /* 1180 * Set vmark to the first elem that we check 1181 * each time. 1182 */ 1183 vmark = vp; 1184 found++; 1185 break; 1186 } 1187 vpprev = vp; 1188 vp = vp->next; 1189 if (vp == vmark) /* break out if we completed */ 1190 /* the circle */ 1191 break; 1192 } 1193 1194 if (!found) { 1195 fprintf(stderr, gettext( 1196 "%s: Warning: %s not found in %s\n"), 1197 myname, *mntlist, vfstab); 1198 exitcode = 1; 1199 } 1200 } 1201 if (ndx == 0) 1202 return (NULL); 1203 1204 vpp[ndx] = NULL; /* null terminate the list */ 1205 vfsarraysize = ndx; /* adjust vfsarraysize */ 1206 return (vpp); 1207 } 1208 1209 /* 1210 * Performs the exec argument processing, all of the child forking and 1211 * execing, and child cleanup. 1212 * Sets exitcode to non-zero if any errors occurred. 1213 */ 1214 void 1215 do_mounts(void) 1216 { 1217 int i, isave, cnt; 1218 vfsent_t *vp, *vpprev, **vl; 1219 char *newargv[ARGV_MAX]; 1220 pid_t child; 1221 1222 /* 1223 * create the arg list once; the only differences among 1224 * the calls are the options, special and mountp fields. 1225 */ 1226 i = 2; 1227 if (cflg) 1228 newargv[i++] = "-c"; 1229 if (gflg) 1230 newargv[i++] = "-g"; 1231 if (mflg) 1232 newargv[i++] = "-m"; 1233 if (Oflg) 1234 newargv[i++] = "-O"; 1235 if (qflg) 1236 newargv[i++] = "-q"; 1237 if (rflg) 1238 newargv[i++] = "-r"; 1239 if (dashflg) 1240 newargv[i++] = "--"; 1241 if (oflg) { 1242 newargv[i++] = "-o"; 1243 newargv[i++] = specific_opts; 1244 } 1245 isave = i; 1246 1247 /* 1248 * Main loop for the mount processes 1249 */ 1250 vl = vfsarray; 1251 cnt = vfsarraysize; 1252 for (vpprev = *vl; vp = *vl; vpprev = vp, vl++, cnt--) { 1253 /* 1254 * Check to see if we cross a mount level: e.g., 1255 * /a/b -> /a/b/c. If so, we need to wait for all current 1256 * mounts to finish, rerun realpath on the remaining mount 1257 * points, and resort the list. 1258 * 1259 * Also, we mount serially as long as there are lofs's 1260 * to mount to avoid improper mount ordering. 1261 */ 1262 if (vp->mlevel > vpprev->mlevel || lofscnt > 0) { 1263 vfsent_t **vlp; 1264 1265 while (nrun > 0 && (dowait() != -1)) 1266 ; 1267 /* 1268 * Gads! It's possible for real path mounts points to 1269 * change after mounts are done at a lower mount 1270 * level. 1271 * Thus, we need to recalculate mount levels and 1272 * resort the list from this point. 1273 */ 1274 for (vlp = vl; *vlp; vlp++) 1275 (void) setrpath(*vlp); 1276 /* 1277 * Sort the remaining entries based on their newly 1278 * resolved path names. 1279 * Do not sort if we still have lofs's to mount. 1280 */ 1281 if (lofscnt == 0) { 1282 qsort((void *)vl, cnt, sizeof (vfsent_t *), 1283 mlevelcmp); 1284 vp = *vl; 1285 } 1286 } 1287 1288 if (vp->flag & VRPFAILED) { 1289 fprintf(stderr, gettext( 1290 "%s: Nonexistent mount point: %s\n"), 1291 myname, vp->v.vfs_mountp); 1292 vp->flag |= VNOTMOUNTED; 1293 exitcode = 1; 1294 continue; 1295 } 1296 1297 /* 1298 * If mount options were not specified on the command 1299 * line, then use the ones found in the vfstab entry, 1300 * if any. 1301 */ 1302 i = isave; 1303 if (!oflg && vp->v.vfs_mntopts) { 1304 newargv[i++] = "-o"; 1305 newargv[i++] = vp->v.vfs_mntopts; 1306 } 1307 newargv[i++] = vp->v.vfs_special; 1308 newargv[i++] = vp->rpath; 1309 newargv[i] = NULL; 1310 1311 /* 1312 * This should never really fail. 1313 */ 1314 while (setup_iopipe(vp) == -1 && (dowait() != -1)) 1315 ; 1316 1317 while (nrun >= maxrun && (dowait() != -1)) /* throttle */ 1318 ; 1319 1320 #ifdef CACHEFS_BUG 1321 if (vp->v.vfs_fstype && 1322 (strcmp(vp->v.vfs_fstype, "cachefs") == 0)) { 1323 while (cachefs_running && (dowait() != -1)) 1324 ; 1325 cachefs_running = 1; 1326 } 1327 #endif 1328 1329 if ((child = fork()) == -1) { 1330 perror("fork"); 1331 cleanup(-1); 1332 /* not reached */ 1333 } 1334 if (child == 0) { /* child */ 1335 signal(SIGHUP, SIG_IGN); 1336 signal(SIGQUIT, SIG_IGN); 1337 signal(SIGINT, SIG_IGN); 1338 setup_output(vp); 1339 doexec(vp->v.vfs_fstype, newargv); 1340 perror("exec"); 1341 exit(1); 1342 } 1343 1344 /* parent */ 1345 (void) close(vp->sopipe[WRPIPE]); 1346 (void) close(vp->sepipe[WRPIPE]); 1347 vp->pid = child; 1348 nrun++; 1349 } 1350 /* 1351 * Mostly done by now - wait and clean up the stragglers. 1352 */ 1353 cleanup(0); 1354 } 1355 1356 1357 /* 1358 * Setup stdout and stderr pipes for the children's output. 1359 */ 1360 int 1361 setup_iopipe(vfsent_t *mp) 1362 { 1363 /* 1364 * Make a stdout and stderr pipe. This should never fail. 1365 */ 1366 if (pipe(mp->sopipe) == -1) 1367 return (-1); 1368 if (pipe(mp->sepipe) == -1) { 1369 (void) close(mp->sopipe[RDPIPE]); 1370 (void) close(mp->sopipe[WRPIPE]); 1371 return (-1); 1372 } 1373 /* 1374 * Don't block on an empty pipe. 1375 */ 1376 (void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK); 1377 (void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK); 1378 /* 1379 * Don't pass extra fds into children. 1380 */ 1381 (void) fcntl(mp->sopipe[RDPIPE], F_SETFD, FD_CLOEXEC); 1382 (void) fcntl(mp->sepipe[RDPIPE], F_SETFD, FD_CLOEXEC); 1383 1384 return (0); 1385 } 1386 1387 /* 1388 * Called by a child to attach its stdout and stderr to the write side of 1389 * the pipes. 1390 */ 1391 void 1392 setup_output(vfsent_t *vp) 1393 { 1394 1395 (void) close(fileno(stdout)); 1396 (void) dup(vp->sopipe[WRPIPE]); 1397 (void) close(vp->sopipe[WRPIPE]); 1398 1399 (void) close(fileno(stderr)); 1400 (void) dup(vp->sepipe[WRPIPE]); 1401 (void) close(vp->sepipe[WRPIPE]); 1402 } 1403 1404 /* 1405 * Parent uses this to print any stdout or stderr output issued by 1406 * the child. 1407 */ 1408 static void 1409 doio(vfsent_t *vp) 1410 { 1411 int bytes; 1412 char ibuf[BUFSIZ]; 1413 1414 while ((bytes = read(vp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0) 1415 write(fileno(stderr), ibuf, bytes); 1416 while ((bytes = read(vp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0) 1417 write(fileno(stdout), ibuf, bytes); 1418 1419 (void) close(vp->sopipe[RDPIPE]); 1420 (void) close(vp->sepipe[RDPIPE]); 1421 } 1422 1423 /* 1424 * Waits for 1 child to die. 1425 * 1426 * Returns -1 if no children are left to wait for. 1427 * Returns 0 if a child died without an error. 1428 * Returns 1 if a child died with an error. 1429 */ 1430 int 1431 dowait(void) 1432 { 1433 int child, wstat; 1434 1435 if ((child = wait(&wstat)) == -1) 1436 return (-1); 1437 nrun--; 1438 return (cleanupkid(child, wstat) != 0); 1439 } 1440 1441 /* 1442 * Locates the child mount process represented by pid, outputs any io 1443 * it may have, and returns its exit code. 1444 * Sets the global exitcode if an error occurred. 1445 */ 1446 int 1447 cleanupkid(pid_t pid, int wstat) 1448 { 1449 vfsent_t *vp, *prevp; 1450 int ret; 1451 1452 if (WIFEXITED(wstat)) /* this should always be true */ 1453 ret = WEXITSTATUS(wstat); 1454 else 1455 ret = 1; /* assume some kind of error */ 1456 if (ret) { 1457 exitcode = 1; 1458 failcnt++; 1459 } 1460 1461 /* 1462 * Find our child. 1463 * This search gets smaller and smaller as children are cleaned 1464 * up. 1465 */ 1466 for (prevp = NULL, vp = vfsll; vp; vp = vp->next) { 1467 if (vp->pid != pid) { 1468 prevp = vp; 1469 continue; 1470 } 1471 /* 1472 * Found: let's remove it from this linked list. 1473 */ 1474 if (prevp) { 1475 prevp->next = vp->next; 1476 vp->next = NULL; 1477 } 1478 break; 1479 } 1480 1481 if (vp == NULL) { 1482 /* 1483 * This should never happen. 1484 */ 1485 fprintf(stderr, gettext( 1486 "%s: Unknown child %d\n"), myname, pid); 1487 exitcode = 1; 1488 return (ret); 1489 } 1490 doio(vp); /* Any output? */ 1491 1492 if (vp->v.vfs_fstype && 1493 (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0)) { 1494 lofscnt--; 1495 if (ret) 1496 lofsfail++; 1497 } 1498 1499 #ifdef CACHEFS_BUG 1500 if (vp->v.vfs_fstype && (strcmp(vp->v.vfs_fstype, "cachefs") == 0)) 1501 cachefs_running = 0; 1502 #endif 1503 1504 vp->exitcode = ret; 1505 return (ret); 1506 } 1507 1508 1509 static vfsent_t zvmount = { 0 }; 1510 1511 vfsent_t * 1512 new_vfsent(struct vfstab *vin, int order) 1513 { 1514 vfsent_t *new; 1515 1516 new = (vfsent_t *)malloc(sizeof (*new)); 1517 if (new == NULL) 1518 nomem(); 1519 1520 *new = zvmount; 1521 if (vin->vfs_special && 1522 (new->v.vfs_special = strdup(vin->vfs_special)) == NULL) 1523 nomem(); 1524 if (vin->vfs_mountp && 1525 (new->v.vfs_mountp = strdup(vin->vfs_mountp)) == NULL) 1526 nomem(); 1527 if (vin->vfs_fstype && 1528 (new->v.vfs_fstype = strdup(vin->vfs_fstype)) == NULL) 1529 nomem(); 1530 /* 1531 * If specific mount options were specified on the command 1532 * line, then use those. Else, use the ones on the vfstab 1533 * line, if any. In other words, specific options on the 1534 * command line override those in /etc/vfstab. 1535 */ 1536 if (oflg) { 1537 if ((new->v.vfs_mntopts = strdup(specific_opts)) == NULL) 1538 nomem(); 1539 } else if (vin->vfs_mntopts && 1540 (new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL) 1541 nomem(); 1542 1543 new->order = order; 1544 return (new); 1545 } 1546 1547 /* 1548 * Runs realpath on vp's mount point, records success or failure, 1549 * resets the mount level based on the new realpath, and returns 1550 * realpath()'s return value. 1551 */ 1552 char * 1553 setrpath(vfsent_t *vp) 1554 { 1555 char *rp; 1556 1557 if ((rp = realpath(vp->v.vfs_mountp, realdir)) == NULL) 1558 vp->flag |= VRPFAILED; 1559 else 1560 vp->flag &= ~VRPFAILED; 1561 1562 if (vp->rpath) 1563 free(vp->rpath); 1564 if ((vp->rpath = strdup(realdir)) == NULL) 1565 nomem(); 1566 vp->mlevel = fsgetmlevel(vp->rpath); 1567 return (rp); 1568 } 1569 1570 1571 /* 1572 * sort first by mlevel (1...N), then by vfstab order. 1573 */ 1574 int 1575 mlevelcmp(const void *a, const void *b) 1576 { 1577 vfsent_t *a1, *b1; 1578 int lcmp; 1579 1580 a1 = *(vfsent_t **)a; 1581 b1 = *(vfsent_t **)b; 1582 1583 lcmp = a1->mlevel - b1->mlevel; 1584 if (lcmp == 0) 1585 lcmp = a1->order - b1->order; 1586 return (lcmp); 1587 } 1588 1589 /* sort by vfstab order. 0..N */ 1590 static int 1591 mordercmp(const void *a, const void *b) 1592 { 1593 vfsent_t *a1, *b1; 1594 1595 a1 = *(vfsent_t **)a; 1596 b1 = *(vfsent_t **)b; 1597 return (a1->order - b1->order); 1598 } 1599 1600 /* 1601 * cleanup the existing children and exit with an error 1602 * if asig != 0. 1603 */ 1604 void 1605 cleanup(int asig) 1606 { 1607 while (nrun > 0 && (dowait() != -1)) 1608 ; 1609 1610 if (asig != 0) 1611 exit(1); 1612 } 1613 1614 1615 int 1616 check_fields(char *fstype, char *mountp) 1617 { 1618 struct stat64 stbuf; 1619 1620 if (strlen(fstype) > (size_t)FSTYPE_MAX) { 1621 fprintf(stderr, 1622 gettext("%s: FSType %s exceeds %d characters\n"), 1623 myname, fstype, FSTYPE_MAX); 1624 return (1); 1625 } 1626 1627 if (mountp == NULL) { 1628 fprintf(stderr, 1629 gettext("%s: Mount point cannot be determined\n"), 1630 myname); 1631 return (1); 1632 } 1633 if (*mountp != '/') { 1634 fprintf(stderr, gettext( 1635 "%s: Mount point %s is not an absolute pathname.\n"), 1636 myname, mountp); 1637 return (1); 1638 } 1639 /* 1640 * Don't do some of these checks if aflg because a mount point may 1641 * not exist now, but will be mounted before we get to it. 1642 * This is one of the quirks of "secondary mounting". 1643 */ 1644 if (!aflg && stat64(mountp, &stbuf) < 0) { 1645 if (errno == ENOENT || errno == ENOTDIR) 1646 fprintf(stderr, 1647 gettext("%s: Mount point %s does not exist.\n"), 1648 myname, mountp); 1649 else { 1650 fprintf(stderr, 1651 gettext("%s: Cannot stat mount point %s.\n"), 1652 myname, mountp); 1653 perror(myname); 1654 } 1655 return (1); 1656 } 1657 return (0); 1658 } 1659 1660 void 1661 nomem(void) 1662 { 1663 fprintf(stderr, gettext("%s: Out of memory\n"), myname); 1664 while (nrun > 0 && (dowait() != -1)) 1665 ; 1666 exit(1); 1667 } 1668