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