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