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 #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 814 /* build the full pathname of the fstype dependent command. */ 815 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname); 816 sprintf(alter_path, "%s/%s/%s", alt_path, fstype, myname); 817 newargv[1] = myname; 818 819 if (Vflg) { 820 printf("%s -F %s", newargv[1], fstype); 821 for (i = 2; newargv[i]; i++) 822 printf(" %s", newargv[i]); 823 printf("\n"); 824 fflush(stdout); 825 exit(0); 826 } 827 828 /* 829 * Try to exec the fstype dependent portion of the mount. 830 * See if the directory is there before trying to exec dependent 831 * portion. This is only useful for eliminating the 832 * '..mount: not found' message when '/usr' is mounted 833 */ 834 if (access(full_path, 0) == 0) { 835 execv(full_path, &newargv[1]); 836 if (errno == EACCES) { 837 fprintf(stderr, 838 gettext("%s: Cannot execute %s - permission denied\n"), 839 myname, full_path); 840 } 841 if (errno == ENOEXEC) { 842 newargv[0] = "sh"; 843 newargv[1] = full_path; 844 execv("/sbin/sh", &newargv[0]); 845 } 846 } 847 execv(alter_path, &newargv[1]); 848 if (errno == EACCES) { 849 fprintf(stderr, gettext( 850 "%s: Cannot execute %s - permission denied\n"), 851 myname, alter_path); 852 exit(1); 853 } 854 if (errno == ENOEXEC) { 855 newargv[0] = "sh"; 856 newargv[1] = alter_path; 857 execv("/sbin/sh", &newargv[0]); 858 } 859 fprintf(stderr, 860 gettext("%s: Operation not applicable to FSType %s\n"), 861 myname, fstype); 862 exit(1); 863 } 864 865 char *mntopts[] = { MNTOPT_IGNORE, NULL }; 866 #define IGNORE 0 867 868 /* 869 * Return 1 if "ignore" appears in the options string 870 */ 871 int 872 ignore(char *opts) 873 { 874 char *value; 875 char *saveptr, *my_opts; 876 int rval = 0; 877 878 if (opts == NULL || *opts == NULL) 879 return (0); 880 881 /* 882 * we make a copy of the option string to pass to getsubopt(), 883 * because getsubopt() modifies the string. We also save 884 * the original pointer returned by strdup, because getsubopt 885 * changes the pointer passed into it. If strdup fails (unlikely), 886 * we act as if the "ignore" option isn't set rather than fail. 887 */ 888 889 if ((saveptr = my_opts = strdup(opts)) == NULL) 890 nomem(); 891 892 while (*my_opts != '\0') { 893 if (getsubopt(&my_opts, mntopts, &value) == IGNORE) 894 rval = 1; 895 } 896 897 free(saveptr); 898 899 return (rval); 900 } 901 902 /* 903 * Perform the parallel version of mount. If count == 0, mount all 904 * vfstab filesystems with the automnt field == "yes". Use fstype if 905 * supplied. If mntlist supplied, then attempt to only mount those. 906 */ 907 908 int 909 parmount(char **mntlist, int count, char *fstype) 910 { 911 int maxfd = OPEN_MAX; 912 struct rlimit rl; 913 vfsent_t **vl, *vp; 914 915 /* 916 * Process scaling. After running a series 917 * of tests based on the number of simultaneous processes and 918 * processors available, optimum performance was achieved near or 919 * at (PROCN * 2). 920 */ 921 if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1) 922 maxrun = 4; 923 else 924 maxrun = maxrun * 2 + 1; 925 926 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 927 rl.rlim_cur = rl.rlim_max; 928 if (setrlimit(RLIMIT_NOFILE, &rl) == 0) 929 maxfd = (int)rl.rlim_cur; 930 } 931 (void) enable_extended_FILE_stdio(-1, -1); 932 933 /* 934 * The parent needs to maintain 3 of its own fd's, plus 2 for 935 * each child (the stdout and stderr pipes). 936 */ 937 maxfd = (maxfd / 2) - 6; /* 6 takes care of temporary */ 938 /* periods of open fds */ 939 if (maxfd < maxrun) 940 maxrun = maxfd; 941 if (maxrun < 4) 942 maxrun = 4; /* sanity check */ 943 944 if (count == 0) 945 mntlist = NULL; /* used as a flag later */ 946 else 947 fstype = NULL; /* mount points supplied: */ 948 /* ignore fstype */ 949 /* 950 * Read the whole vfstab into a linked list for quick processing. 951 * On average, this is the most efficient way to collect and 952 * manipulate the vfstab data. 953 */ 954 vfsll = getvfsall(fstype, mntlist == NULL); 955 956 /* 957 * Make an array out of the vfs linked list for sorting purposes. 958 */ 959 if (vfsll == NULL || 960 (vfsarray = make_vfsarray(mntlist, count)) == NULL) { 961 if (mntlist == NULL) /* not an error - just none found */ 962 return (0); 963 964 fprintf(stderr, gettext("%s: No valid entries found in %s\n"), 965 myname, vfstab); 966 return (1); 967 } 968 969 /* 970 * Sort the entries based on their resolved path names 971 * 972 * If an lofs is encountered, then the original order of the vfstab 973 * file needs to be maintained until we are done mounting lofs's. 974 */ 975 if (!lofscnt) 976 qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *), 977 mlevelcmp); 978 979 /* 980 * Shrink the vfsll linked list down to the new list. This will 981 * speed up the pid search in cleanupkid() later. 982 */ 983 vfsll = vfsarray[0]; 984 for (vl = vfsarray; vp = *vl; ) 985 vp->next = *++vl; 986 987 /* 988 * Try to handle interrupts in a reasonable way. 989 */ 990 sigset(SIGHUP, cleanup); 991 sigset(SIGQUIT, cleanup); 992 sigset(SIGINT, cleanup); 993 994 do_mounts(); /* do the mounts */ 995 996 if (failcnt > 0 && failcnt == lofsfail) 997 return (ALL_LOFS_FAILURES); 998 999 return (exitcode); 1000 } 1001 1002 /* 1003 * Read all vstab (fp) entries into memory if fstype == NULL. 1004 * If fstype is specified, than read all those that match it. 1005 * 1006 * Returns a linked list. 1007 */ 1008 vfsent_t * 1009 getvfsall(char *fstype, int takeall) 1010 { 1011 vfsent_t *vhead, *vtail; 1012 struct vfstab vget; 1013 FILE *fp; 1014 int cnt = 0, ret; 1015 1016 if ((fp = fopen(vfstab, "r")) == NULL) { 1017 fprintf(stderr, gettext("%s: Cannot open %s\n"), 1018 myname, vfstab); 1019 exit(1); 1020 } 1021 1022 vhead = vtail = NULL; 1023 1024 while ((ret = getvfsent(fp, &vget)) != -1) { 1025 vfsent_t *vp; 1026 1027 if (ret > 0) { 1028 vfserror(ret, vget.vfs_mountp); 1029 continue; 1030 } 1031 1032 /* 1033 * If mount points were not specified, then we ignore 1034 * entries that aren't marked "yes". 1035 */ 1036 if (takeall && 1037 (vget.vfs_automnt == NULL || 1038 strcmp(vget.vfs_automnt, "yes"))) 1039 continue; 1040 1041 if (fstype && vget.vfs_fstype && 1042 strcmp(fstype, vget.vfs_fstype)) 1043 continue; 1044 1045 if (vget.vfs_mountp == NULL || 1046 (vget.vfs_fstype && (strcmp(vget.vfs_fstype, "swap") == 0))) 1047 continue; 1048 1049 if (check_fields(vget.vfs_fstype, vget.vfs_mountp)) { 1050 exitcode = 1; 1051 continue; 1052 } 1053 1054 vp = new_vfsent(&vget, cnt); /* create new vfs entry */ 1055 if (vhead == NULL) 1056 vhead = vp; 1057 else 1058 vtail->next = vp; 1059 vtail = vp; 1060 cnt++; 1061 } 1062 fclose(fp); 1063 if (vtail == NULL) { 1064 vfsarraysize = 0; 1065 vfslltail = NULL; 1066 return (NULL); 1067 } 1068 vtail->next = NULL; 1069 vfslltail = vtail; /* save it in the global variable */ 1070 vfsarraysize = cnt; 1071 return (vhead); 1072 } 1073 1074 1075 /* 1076 * Returns an array of vfsent_t's based on vfsll & mntlist. 1077 */ 1078 vfsent_t ** 1079 make_vfsarray(char **mntlist, int count) 1080 { 1081 vfsent_t *vp, *vmark, *vpprev, **vpp; 1082 int ndx, found; 1083 1084 if (vfsll == NULL) 1085 return (NULL); 1086 1087 if (count > 0) 1088 vfsarraysize = count; 1089 1090 vpp = (vfsent_t **)malloc(sizeof (*vpp) * (vfsarraysize + 1)); 1091 if (vpp == NULL) 1092 nomem(); 1093 1094 if (mntlist == NULL) { 1095 /* 1096 * No mount list specified: take all vfstab mount points. 1097 */ 1098 for (ndx = 0, vp = vfsll; vp; vp = vp->next) { 1099 (void) setrpath(vp); 1100 /* 1101 * Sigh. lofs entries can complicate matters so much 1102 * that the best way to avoid problems is to 1103 * stop parallel mounting when an lofs is 1104 * encountered, so we keep a count of how many 1105 * there are. 1106 * Fortunately this is rare. 1107 */ 1108 if (vp->v.vfs_fstype && 1109 (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0)) 1110 lofscnt++; 1111 1112 vpp[ndx++] = vp; 1113 } 1114 vpp[ndx] = NULL; 1115 return (vpp); 1116 } 1117 1118 /* 1119 * A list of mount points was specified on the command line 1120 * and we need to search for each one. 1121 */ 1122 vpprev = vfslltail; 1123 vpprev->next = vfsll; /* make a circle out of it */ 1124 vmark = vp = vfsll; 1125 /* 1126 * For each specified mount point: 1127 */ 1128 for (ndx = 0; *mntlist; mntlist++) { 1129 found = 0; 1130 /* 1131 * Circle our entire linked list, looking for *mntlist. 1132 */ 1133 while (vp) { 1134 if (strcmp(*mntlist, vp->v.vfs_mountp) == 0) { 1135 vpp[ndx++] = vp; /* found it. */ 1136 (void) setrpath(vp); 1137 if (vp->v.vfs_fstype && 1138 (strcmp(vp->v.vfs_fstype, 1139 MNTTYPE_LOFS) == 0)) 1140 lofscnt++; 1141 1142 if (vp == vpprev) { /* list exhausted */ 1143 vp = NULL; 1144 found++; 1145 break; 1146 } 1147 /* 1148 * Remove it from the circular list. vpprev 1149 * remains unchanged. 1150 */ 1151 vp = vp->next; 1152 vpprev->next->next = NULL; 1153 vpprev->next = vp; 1154 /* 1155 * Set vmark to the first elem that we check 1156 * each time. 1157 */ 1158 vmark = vp; 1159 found++; 1160 break; 1161 } 1162 vpprev = vp; 1163 vp = vp->next; 1164 if (vp == vmark) /* break out if we completed */ 1165 /* the circle */ 1166 break; 1167 } 1168 1169 if (!found) { 1170 fprintf(stderr, gettext( 1171 "%s: Warning: %s not found in %s\n"), 1172 myname, *mntlist, vfstab); 1173 exitcode = 1; 1174 } 1175 } 1176 if (ndx == 0) 1177 return (NULL); 1178 1179 vpp[ndx] = NULL; /* null terminate the list */ 1180 vfsarraysize = ndx; /* adjust vfsarraysize */ 1181 return (vpp); 1182 } 1183 1184 /* 1185 * Performs the exec argument processing, all of the child forking and 1186 * execing, and child cleanup. 1187 * Sets exitcode to non-zero if any errors occurred. 1188 */ 1189 void 1190 do_mounts(void) 1191 { 1192 int i, isave, cnt; 1193 vfsent_t *vp, *vpprev, **vl; 1194 char *newargv[ARGV_MAX]; 1195 pid_t child; 1196 1197 /* 1198 * create the arg list once; the only differences among 1199 * the calls are the options, special and mountp fields. 1200 */ 1201 i = 2; 1202 if (cflg) 1203 newargv[i++] = "-c"; 1204 if (gflg) 1205 newargv[i++] = "-g"; 1206 if (mflg) 1207 newargv[i++] = "-m"; 1208 if (Oflg) 1209 newargv[i++] = "-O"; 1210 if (qflg) 1211 newargv[i++] = "-q"; 1212 if (rflg) 1213 newargv[i++] = "-r"; 1214 if (dashflg) 1215 newargv[i++] = "--"; 1216 if (oflg) { 1217 newargv[i++] = "-o"; 1218 newargv[i++] = specific_opts; 1219 } 1220 isave = i; 1221 1222 /* 1223 * Main loop for the mount processes 1224 */ 1225 vl = vfsarray; 1226 cnt = vfsarraysize; 1227 for (vpprev = *vl; vp = *vl; vpprev = vp, vl++, cnt--) { 1228 /* 1229 * Check to see if we cross a mount level: e.g., 1230 * /a/b -> /a/b/c. If so, we need to wait for all current 1231 * mounts to finish, rerun realpath on the remaining mount 1232 * points, and resort the list. 1233 * 1234 * Also, we mount serially as long as there are lofs's 1235 * to mount to avoid improper mount ordering. 1236 */ 1237 if (vp->mlevel > vpprev->mlevel || lofscnt > 0) { 1238 vfsent_t **vlp; 1239 1240 while (nrun > 0 && (dowait() != -1)) 1241 ; 1242 /* 1243 * Gads! It's possible for real path mounts points to 1244 * change after mounts are done at a lower mount 1245 * level. 1246 * Thus, we need to recalculate mount levels and 1247 * resort the list from this point. 1248 */ 1249 for (vlp = vl; *vlp; vlp++) 1250 (void) setrpath(*vlp); 1251 /* 1252 * Sort the remaining entries based on their newly 1253 * resolved path names. 1254 * Do not sort if we still have lofs's to mount. 1255 */ 1256 if (lofscnt == 0) { 1257 qsort((void *)vl, cnt, sizeof (vfsent_t *), 1258 mlevelcmp); 1259 vp = *vl; 1260 } 1261 } 1262 1263 if (vp->flag & VRPFAILED) { 1264 fprintf(stderr, gettext( 1265 "%s: Nonexistent mount point: %s\n"), 1266 myname, vp->v.vfs_mountp); 1267 vp->flag |= VNOTMOUNTED; 1268 exitcode = 1; 1269 continue; 1270 } 1271 1272 /* 1273 * If mount options were not specified on the command 1274 * line, then use the ones found in the vfstab entry, 1275 * if any. 1276 */ 1277 i = isave; 1278 if (!oflg && vp->v.vfs_mntopts) { 1279 newargv[i++] = "-o"; 1280 newargv[i++] = vp->v.vfs_mntopts; 1281 } 1282 newargv[i++] = vp->v.vfs_special; 1283 newargv[i++] = vp->rpath; 1284 newargv[i] = NULL; 1285 1286 /* 1287 * This should never really fail. 1288 */ 1289 while (setup_iopipe(vp) == -1 && (dowait() != -1)) 1290 ; 1291 1292 while (nrun >= maxrun && (dowait() != -1)) /* throttle */ 1293 ; 1294 1295 #ifdef CACHEFS_BUG 1296 if (vp->v.vfs_fstype && 1297 (strcmp(vp->v.vfs_fstype, "cachefs") == 0)) { 1298 while (cachefs_running && (dowait() != -1)) 1299 ; 1300 cachefs_running = 1; 1301 } 1302 #endif 1303 1304 if ((child = fork()) == -1) { 1305 perror("fork"); 1306 cleanup(-1); 1307 /* not reached */ 1308 } 1309 if (child == 0) { /* child */ 1310 signal(SIGHUP, SIG_IGN); 1311 signal(SIGQUIT, SIG_IGN); 1312 signal(SIGINT, SIG_IGN); 1313 setup_output(vp); 1314 doexec(vp->v.vfs_fstype, newargv); 1315 perror("exec"); 1316 exit(1); 1317 } 1318 1319 /* parent */ 1320 (void) close(vp->sopipe[WRPIPE]); 1321 (void) close(vp->sepipe[WRPIPE]); 1322 vp->pid = child; 1323 nrun++; 1324 } 1325 /* 1326 * Mostly done by now - wait and clean up the stragglers. 1327 */ 1328 cleanup(0); 1329 } 1330 1331 1332 /* 1333 * Setup stdout and stderr pipes for the children's output. 1334 */ 1335 int 1336 setup_iopipe(vfsent_t *mp) 1337 { 1338 /* 1339 * Make a stdout and stderr pipe. This should never fail. 1340 */ 1341 if (pipe(mp->sopipe) == -1) 1342 return (-1); 1343 if (pipe(mp->sepipe) == -1) { 1344 (void) close(mp->sopipe[RDPIPE]); 1345 (void) close(mp->sopipe[WRPIPE]); 1346 return (-1); 1347 } 1348 /* 1349 * Don't block on an empty pipe. 1350 */ 1351 (void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK); 1352 (void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK); 1353 /* 1354 * Don't pass extra fds into children. 1355 */ 1356 (void) fcntl(mp->sopipe[RDPIPE], F_SETFD, FD_CLOEXEC); 1357 (void) fcntl(mp->sepipe[RDPIPE], F_SETFD, FD_CLOEXEC); 1358 1359 return (0); 1360 } 1361 1362 /* 1363 * Called by a child to attach its stdout and stderr to the write side of 1364 * the pipes. 1365 */ 1366 void 1367 setup_output(vfsent_t *vp) 1368 { 1369 1370 (void) close(fileno(stdout)); 1371 (void) dup(vp->sopipe[WRPIPE]); 1372 (void) close(vp->sopipe[WRPIPE]); 1373 1374 (void) close(fileno(stderr)); 1375 (void) dup(vp->sepipe[WRPIPE]); 1376 (void) close(vp->sepipe[WRPIPE]); 1377 } 1378 1379 /* 1380 * Parent uses this to print any stdout or stderr output issued by 1381 * the child. 1382 */ 1383 static void 1384 doio(vfsent_t *vp) 1385 { 1386 int bytes; 1387 char ibuf[BUFSIZ]; 1388 1389 while ((bytes = read(vp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0) 1390 write(fileno(stderr), ibuf, bytes); 1391 while ((bytes = read(vp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0) 1392 write(fileno(stdout), ibuf, bytes); 1393 1394 (void) close(vp->sopipe[RDPIPE]); 1395 (void) close(vp->sepipe[RDPIPE]); 1396 } 1397 1398 /* 1399 * Waits for 1 child to die. 1400 * 1401 * Returns -1 if no children are left to wait for. 1402 * Returns 0 if a child died without an error. 1403 * Returns 1 if a child died with an error. 1404 */ 1405 int 1406 dowait(void) 1407 { 1408 int child, wstat; 1409 1410 if ((child = wait(&wstat)) == -1) 1411 return (-1); 1412 nrun--; 1413 return (cleanupkid(child, wstat) != 0); 1414 } 1415 1416 /* 1417 * Locates the child mount process represented by pid, outputs any io 1418 * it may have, and returns its exit code. 1419 * Sets the global exitcode if an error occurred. 1420 */ 1421 int 1422 cleanupkid(pid_t pid, int wstat) 1423 { 1424 vfsent_t *vp, *prevp; 1425 int ret; 1426 1427 if (WIFEXITED(wstat)) /* this should always be true */ 1428 ret = WEXITSTATUS(wstat); 1429 else 1430 ret = 1; /* assume some kind of error */ 1431 if (ret) { 1432 exitcode = 1; 1433 failcnt++; 1434 } 1435 1436 /* 1437 * Find our child. 1438 * This search gets smaller and smaller as children are cleaned 1439 * up. 1440 */ 1441 for (prevp = NULL, vp = vfsll; vp; vp = vp->next) { 1442 if (vp->pid != pid) { 1443 prevp = vp; 1444 continue; 1445 } 1446 /* 1447 * Found: let's remove it from this linked list. 1448 */ 1449 if (prevp) { 1450 prevp->next = vp->next; 1451 vp->next = NULL; 1452 } 1453 break; 1454 } 1455 1456 if (vp == NULL) { 1457 /* 1458 * This should never happen. 1459 */ 1460 fprintf(stderr, gettext( 1461 "%s: Unknown child %d\n"), myname, pid); 1462 exitcode = 1; 1463 return (ret); 1464 } 1465 doio(vp); /* Any output? */ 1466 1467 if (vp->v.vfs_fstype && 1468 (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0)) { 1469 lofscnt--; 1470 if (ret) 1471 lofsfail++; 1472 } 1473 1474 #ifdef CACHEFS_BUG 1475 if (vp->v.vfs_fstype && (strcmp(vp->v.vfs_fstype, "cachefs") == 0)) 1476 cachefs_running = 0; 1477 #endif 1478 1479 vp->exitcode = ret; 1480 return (ret); 1481 } 1482 1483 1484 static vfsent_t zvmount = { 0 }; 1485 1486 vfsent_t * 1487 new_vfsent(struct vfstab *vin, int order) 1488 { 1489 vfsent_t *new; 1490 1491 new = (vfsent_t *)malloc(sizeof (*new)); 1492 if (new == NULL) 1493 nomem(); 1494 1495 *new = zvmount; 1496 if (vin->vfs_special && 1497 (new->v.vfs_special = strdup(vin->vfs_special)) == NULL) 1498 nomem(); 1499 if (vin->vfs_mountp && 1500 (new->v.vfs_mountp = strdup(vin->vfs_mountp)) == NULL) 1501 nomem(); 1502 if (vin->vfs_fstype && 1503 (new->v.vfs_fstype = strdup(vin->vfs_fstype)) == NULL) 1504 nomem(); 1505 /* 1506 * If specific mount options were specified on the command 1507 * line, then use those. Else, use the ones on the vfstab 1508 * line, if any. In other words, specific options on the 1509 * command line override those in /etc/vfstab. 1510 */ 1511 if (oflg) { 1512 if ((new->v.vfs_mntopts = strdup(specific_opts)) == NULL) 1513 nomem(); 1514 } else if (vin->vfs_mntopts && 1515 (new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL) 1516 nomem(); 1517 1518 new->order = order; 1519 return (new); 1520 } 1521 1522 /* 1523 * Runs realpath on vp's mount point, records success or failure, 1524 * resets the mount level based on the new realpath, and returns 1525 * realpath()'s return value. 1526 */ 1527 char * 1528 setrpath(vfsent_t *vp) 1529 { 1530 char *rp; 1531 1532 if ((rp = realpath(vp->v.vfs_mountp, realdir)) == NULL) 1533 vp->flag |= VRPFAILED; 1534 else 1535 vp->flag &= ~VRPFAILED; 1536 1537 if (vp->rpath) 1538 free(vp->rpath); 1539 if ((vp->rpath = strdup(realdir)) == NULL) 1540 nomem(); 1541 vp->mlevel = fsgetmlevel(vp->rpath); 1542 return (rp); 1543 } 1544 1545 1546 /* 1547 * sort first by mlevel (1...N), then by vfstab order. 1548 */ 1549 int 1550 mlevelcmp(const void *a, const void *b) 1551 { 1552 vfsent_t *a1, *b1; 1553 int lcmp; 1554 1555 a1 = *(vfsent_t **)a; 1556 b1 = *(vfsent_t **)b; 1557 1558 lcmp = a1->mlevel - b1->mlevel; 1559 if (lcmp == 0) 1560 lcmp = a1->order - b1->order; 1561 return (lcmp); 1562 } 1563 1564 /* sort by vfstab order. 0..N */ 1565 static int 1566 mordercmp(const void *a, const void *b) 1567 { 1568 vfsent_t *a1, *b1; 1569 1570 a1 = *(vfsent_t **)a; 1571 b1 = *(vfsent_t **)b; 1572 return (a1->order - b1->order); 1573 } 1574 1575 /* 1576 * cleanup the existing children and exit with an error 1577 * if asig != 0. 1578 */ 1579 void 1580 cleanup(int asig) 1581 { 1582 while (nrun > 0 && (dowait() != -1)) 1583 ; 1584 1585 if (asig != 0) 1586 exit(1); 1587 } 1588 1589 1590 int 1591 check_fields(char *fstype, char *mountp) 1592 { 1593 struct stat64 stbuf; 1594 1595 if (strlen(fstype) > (size_t)FSTYPE_MAX) { 1596 fprintf(stderr, 1597 gettext("%s: FSType %s exceeds %d characters\n"), 1598 myname, fstype, FSTYPE_MAX); 1599 return (1); 1600 } 1601 1602 if (mountp == NULL) { 1603 fprintf(stderr, 1604 gettext("%s: Mount point cannot be determined\n"), 1605 myname); 1606 return (1); 1607 } 1608 if (*mountp != '/') { 1609 fprintf(stderr, gettext( 1610 "%s: Mount point %s is not an absolute pathname.\n"), 1611 myname, mountp); 1612 return (1); 1613 } 1614 /* 1615 * Don't do some of these checks if aflg because a mount point may 1616 * not exist now, but will be mounted before we get to it. 1617 * This is one of the quirks of "secondary mounting". 1618 */ 1619 if (!aflg && stat64(mountp, &stbuf) < 0) { 1620 if (errno == ENOENT || errno == ENOTDIR) 1621 fprintf(stderr, 1622 gettext("%s: Mount point %s does not exist.\n"), 1623 myname, mountp); 1624 else { 1625 fprintf(stderr, 1626 gettext("%s: Cannot stat mount point %s.\n"), 1627 myname, mountp); 1628 perror(myname); 1629 } 1630 return (1); 1631 } 1632 return (0); 1633 } 1634 1635 void 1636 nomem(void) 1637 { 1638 fprintf(stderr, gettext("%s: Out of memory\n"), myname); 1639 while (nrun > 0 && (dowait() != -1)) 1640 ; 1641 exit(1); 1642 } 1643