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