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