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