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 2008 Sun Microsystems, Inc. All rights reserved. 27 * Use is subject to license terms. 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" /* SVr4.0 1.82 */ 31 32 #include <stdio.h> 33 #include <stdio_ext.h> 34 #include <limits.h> 35 #include <fcntl.h> 36 #include <unistd.h> 37 #include <stdlib.h> 38 #include <string.h> 39 #include <stdarg.h> 40 #include <sys/types.h> 41 #include <sys/stat.h> 42 #include <sys/statvfs.h> 43 #include <errno.h> 44 #include <sys/mnttab.h> 45 #include <sys/mntent.h> 46 #include <sys/mount.h> 47 #include <sys/vfstab.h> 48 #include <sys/param.h> 49 #include <sys/wait.h> 50 #include <sys/signal.h> 51 #include <sys/resource.h> 52 #include <stropts.h> 53 #include <sys/conf.h> 54 #include <locale.h> 55 #include "fslib.h" 56 57 #define VFS_PATH "/usr/lib/fs" 58 #define ALT_PATH "/etc/fs" 59 #define REMOTE "/etc/dfs/fstypes" 60 61 #define ARGV_MAX 16 62 #define TIME_MAX 50 63 #define FSTYPE_MAX 8 64 #define REMOTE_MAX 64 65 66 #define OLD 0 67 #define NEW 1 68 69 #define READONLY 0 70 #define READWRITE 1 71 #define SUID 2 72 #define NOSUID 3 73 #define SETUID 4 74 #define NOSETUID 5 75 #define DEVICES 6 76 #define NODEVICES 7 77 78 #define FORMAT "%a %b %e %H:%M:%S %Y\n" /* date time format */ 79 /* a - abbreviated weekday name */ 80 /* b - abbreviated month name */ 81 /* e - day of month */ 82 /* H - hour */ 83 /* M - minute */ 84 /* S - second */ 85 /* Y - Year */ 86 /* n - newline */ 87 88 extern int optind; 89 extern char *optarg; 90 91 extern void usage(void); 92 extern char *flags(char *, int); 93 extern char *remote(char *, FILE *); 94 extern char *default_fstype(char *); 95 96 char *myopts[] = { 97 MNTOPT_RO, 98 MNTOPT_RW, 99 MNTOPT_SUID, 100 MNTOPT_NOSUID, 101 MNTOPT_SETUID, 102 MNTOPT_NOSETUID, 103 MNTOPT_DEVICES, 104 MNTOPT_NODEVICES, 105 NULL 106 }; 107 108 static char *myname; /* point to argv[0] */ 109 110 /* 111 * Set the limit to double the number of characters a user should be allowed to 112 * type in one line. 113 * This should cover the different shells, which don't use POSIX_MAX_INPUT, 114 * and should cover the case where a long option string can be in 115 * the /etc/vfstab file. 116 */ 117 char mntflags[(_POSIX_MAX_INPUT+1) * 2]; 118 119 char realdir[MAXPATHLEN]; /* buffer for realpath() calls */ 120 char *vfstab = VFSTAB; 121 char *mnttab = MNTTAB; 122 char *specific_opts; /* holds specific mount options */ 123 char *generic_opts; /* holds generic mount options */ 124 int maxrun; 125 int nrun; 126 int lofscnt; /* presence of lofs prohibits parallel */ 127 /* mounting */ 128 int exitcode; 129 int aflg, cflg, fflg, Fflg, gflg, oflg, pflg, rflg, vflg, Vflg, mflg, Oflg, 130 dashflg, questflg, dflg, qflg; 131 132 /* 133 * Currently, mounting cachefs instances simultaneously uncovers various 134 * problems. For the short term, we serialize cachefs activity while we fix 135 * these cachefs bugs. 136 */ 137 #define CACHEFS_BUG 138 #ifdef CACHEFS_BUG 139 int cachefs_running; /* parallel cachefs not supported yet */ 140 #endif 141 142 /* 143 * Each vfsent_t describes a vfstab entry. It is used to manage and cleanup 144 * each child that performs the particular mount for the entry. 145 */ 146 147 typedef struct vfsent { 148 struct vfstab v; /* the vfstab entry */ 149 char *rpath; /* resolved pathname so far */ 150 int mlevel; /* how deep is this mount point */ 151 int order; /* vfstab serial order of this vfs */ 152 int flag; 153 pid_t pid; /* the pid of this mount process */ 154 int exitcode; /* process's exitcode */ 155 #define RDPIPE 0 156 #define WRPIPE 1 157 int sopipe[2]; /* pipe attached to child's stdout */ 158 int sepipe[2]; /* pipe attached to child's stderr */ 159 struct vfsent *next; /* used when in linked list */ 160 } vfsent_t; 161 162 #define VRPFAILED 0x01 /* most recent realpath failed on */ 163 /* this mount point */ 164 #define VNOTMOUNTED 0x02 /* mount point could not be mounted */ 165 166 vfsent_t *vfsll, *vfslltail; /* head and tail of the global */ 167 /* linked list of vfstab entries */ 168 vfsent_t **vfsarray; /* global array of vfsent_t's */ 169 int vfsarraysize; /* length of the list */ 170 171 /* 172 * This structure is used to build a linked list of 173 * mnttab structures from /etc/mnttab. 174 */ 175 typedef struct mountent { 176 struct extmnttab *ment; 177 int flag; 178 struct mountent *next; 179 } mountent_t; 180 181 #define MSORTED 0x1 182 183 static vfsent_t **make_vfsarray(char **, int); 184 static vfsent_t *new_vfsent(struct vfstab *, int); 185 static vfsent_t *getvfsall(char *, int); 186 187 static void doexec(char *, char **); 188 static void nomem(); 189 static void cleanup(int); 190 static char *setrpath(vfsent_t *); 191 static int dowait(); 192 static int setup_iopipe(vfsent_t *); 193 static void setup_output(vfsent_t *); 194 static void doio(vfsent_t *); 195 static void do_mounts(); 196 static int parmount(char **, int, char *); 197 static int mlevelcmp(const void *, const void *); 198 static int mordercmp(const void *, const void *); 199 static int check_fields(char *, char *); 200 static int cleanupkid(pid_t, int); 201 static void print_mnttab(int, int); 202 static void vfserror(int, char *); 203 static void mnterror(int); 204 static int ignore(char *); 205 206 /* 207 * This is /usr/sbin/mount: the generic command that in turn 208 * execs the appropriate /usr/lib/fs/{fstype}/mount. 209 * The -F flag and argument are NOT passed. 210 * If the usr file system is not mounted a duplicate copy 211 * can be found in /sbin and this version execs the 212 * appropriate /etc/fs/{fstype}/mount 213 * 214 * If the -F fstype, special or directory are missing, 215 * /etc/vfstab is searched to fill in the missing arguments. 216 * 217 * -V will print the built command on the stdout. 218 * It isn't passed either. 219 */ 220 int 221 main(int argc, char *argv[]) 222 { 223 char *special, /* argument of special/resource */ 224 *mountp, /* argument of mount directory */ 225 *fstype, /* wherein the fstype name is filled */ 226 *newargv[ARGV_MAX], /* arg list for specific command */ 227 *farg = NULL, *Farg = NULL; 228 int ii, ret, cc, fscnt; 229 struct stat64 stbuf; 230 struct vfstab vget, vref; 231 mode_t mode; 232 FILE *fd; 233 234 (void) setlocale(LC_ALL, ""); 235 236 #if !defined(TEXT_DOMAIN) 237 #define TEXT_DOMAIN "SYS_TEST" 238 #endif 239 (void) textdomain(TEXT_DOMAIN); 240 241 myname = strrchr(argv[0], '/'); 242 if (myname) 243 myname++; 244 else 245 myname = argv[0]; 246 if (myname == 0) myname = "path unknown"; 247 248 /* Process the args. */ 249 250 while ((cc = getopt(argc, argv, "?acd:f:F:gmno:pqrvVO")) != -1) 251 switch (cc) { 252 case 'a': 253 aflg++; 254 break; 255 case 'c': 256 cflg++; 257 break; 258 259 #ifdef DEBUG 260 case 'd': 261 dflg = atoi(optarg); 262 break; 263 #endif 264 265 case 'f': 266 fflg++; 267 farg = optarg; 268 break; 269 case 'F': 270 Fflg++; 271 Farg = optarg; 272 break; 273 case 'g': 274 gflg++; 275 break; 276 case 'm': 277 mflg++; 278 break; /* do not update /etc/mnttab */ 279 case 'o': 280 oflg++; 281 if ((specific_opts = strdup(optarg)) == NULL) 282 nomem(); 283 break; /* fstype dependent options */ 284 case 'O': 285 Oflg++; 286 break; 287 case 'p': 288 pflg++; 289 break; 290 case 'q': 291 qflg++; 292 break; 293 case 'r': 294 rflg++; 295 generic_opts = "ro"; 296 break; 297 case 'v': 298 vflg++; 299 break; 300 case 'V': 301 Vflg++; 302 break; 303 case '?': 304 questflg++; 305 break; 306 } 307 308 /* copy '--' to specific */ 309 if (strcmp(argv[optind-1], "--") == 0) 310 dashflg++; 311 312 /* option checking */ 313 /* more than two args not allowed if !aflg */ 314 if (!aflg && (argc - optind > 2)) 315 usage(); 316 317 /* pv mututally exclusive */ 318 if (pflg + vflg + aflg > 1) { 319 fprintf(stderr, gettext 320 ("%s: -a, -p, and -v are mutually exclusive\n"), 321 myname); 322 usage(); 323 } 324 325 /* 326 * Can't have overlaying mounts on the same mount point during 327 * a parallel mount. 328 */ 329 if (aflg && Oflg) { 330 fprintf(stderr, gettext 331 ("%s: -a and -O are mutually exclusive\n"), myname); 332 usage(); 333 } 334 335 /* dfF mutually exclusive */ 336 if (fflg + Fflg > 1) { 337 fprintf(stderr, gettext 338 ("%s: More than one FSType specified\n"), myname); 339 usage(); 340 } 341 342 /* no arguments, only allow p,v,V or [F]? */ 343 if (!aflg && optind == argc) { 344 if (cflg || fflg || mflg || oflg || rflg || qflg) 345 usage(); 346 347 if (Fflg && !questflg) 348 usage(); 349 350 if (questflg) { 351 if (Fflg) { 352 newargv[2] = "-?"; 353 newargv[3] = NULL; 354 doexec(Farg, newargv); 355 } 356 usage(); 357 } 358 } 359 360 if (questflg) 361 usage(); 362 363 /* one or two args, allow any but p,v */ 364 if (optind != argc && (pflg || vflg)) { 365 fprintf(stderr, 366 gettext("%s: Cannot use -p and -v with arguments\n"), myname); 367 usage(); 368 } 369 370 371 /* if only reporting mnttab, generic prints mnttab and exits */ 372 if (!aflg && optind == argc) { 373 if (Vflg) { 374 printf("%s", myname); 375 if (pflg) 376 printf(" -p"); 377 if (vflg) 378 printf(" -v"); 379 printf("\n"); 380 exit(0); 381 } 382 383 print_mnttab(vflg, pflg); 384 exit(0); 385 } 386 387 /* 388 * Get filesystem type here. If "-F FStype" is specified, use 389 * that fs type. Otherwise, determine the fs type from /etc/vfstab 390 * if the entry exists. Otherwise, determine the local or remote 391 * fs type from /etc/default/df or /etc/dfs/fstypes respectively. 392 */ 393 if (fflg) { 394 if ((strcmp(farg, "S51K") != 0) && 395 (strcmp(farg, "S52K") != 0)) { 396 fstype = farg; 397 } 398 else 399 fstype = "ufs"; 400 } else /* if (Fflg) */ 401 fstype = Farg; 402 403 fscnt = argc - optind; 404 if (aflg && (fscnt != 1)) 405 exit(parmount(argv + optind, fscnt, fstype)); 406 407 /* 408 * Then don't bother with the parallel over head. Everything 409 * from this point is simple/normal single execution. 410 */ 411 aflg = 0; 412 413 /* get special and/or mount-point from arg(s) */ 414 if (fscnt == 2) 415 special = argv[optind++]; 416 else 417 special = NULL; 418 if (optind < argc) 419 mountp = argv[optind++]; 420 else 421 mountp = NULL; 422 423 /* lookup only if we need to */ 424 if (fstype == NULL || specific_opts == NULL || special == NULL || 425 mountp == NULL) { 426 if ((fd = fopen(vfstab, "r")) == NULL) { 427 if (fstype == NULL || special == NULL || 428 mountp == NULL) { 429 fprintf(stderr, gettext( 430 "%s: Cannot open %s\n"), 431 myname, vfstab); 432 exit(1); 433 } else { 434 /* 435 * No vfstab, but we know what we want 436 * to mount. 437 */ 438 goto out; 439 } 440 } 441 vfsnull(&vref); 442 vref.vfs_special = special; 443 vref.vfs_mountp = mountp; 444 vref.vfs_fstype = fstype; 445 446 /* get a vfstab entry matching mountp or special */ 447 while ((ret = getvfsany(fd, &vget, &vref)) > 0) 448 vfserror(ret, vget.vfs_special); 449 450 /* if no entry and there was only one argument */ 451 /* then the argument could be the special */ 452 /* and not mount point as we thought earlier */ 453 if (ret == -1 && special == NULL) { 454 rewind(fd); 455 special = vref.vfs_special = mountp; 456 mountp = vref.vfs_mountp = NULL; 457 /* skip erroneous lines; they were reported above */ 458 while ((ret = getvfsany(fd, &vget, &vref)) > 0) 459 ; 460 } 461 462 fclose(fd); 463 464 if (ret == 0) { 465 if (fstype == NULL) 466 fstype = vget.vfs_fstype; 467 if (special == NULL) 468 special = vget.vfs_special; 469 if (mountp == NULL) 470 mountp = vget.vfs_mountp; 471 if (oflg == 0 && vget.vfs_mntopts) { 472 oflg++; 473 specific_opts = vget.vfs_mntopts; 474 } 475 } else if (special == NULL) { 476 if (stat64(mountp, &stbuf) == -1) { 477 fprintf(stderr, gettext("%s: cannot stat %s\n"), 478 myname, mountp); 479 exit(2); 480 } 481 if (((mode = (stbuf.st_mode & S_IFMT)) == S_IFBLK) || 482 (mode == S_IFCHR)) { 483 fprintf(stderr, 484 gettext("%s: mount point cannot be determined\n"), 485 myname); 486 exit(1); 487 } else 488 { 489 fprintf(stderr, 490 gettext("%s: special cannot be determined\n"), 491 myname); 492 exit(1); 493 } 494 } else if (fstype == NULL) 495 fstype = default_fstype(special); 496 } 497 498 out: 499 if (check_fields(fstype, mountp)) 500 exit(1); 501 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 /* create the new arg list, and end the list with a null pointer */ 512 ii = 2; 513 if (cflg) 514 newargv[ii++] = "-c"; 515 if (gflg) 516 newargv[ii++] = "-g"; 517 if (mflg) 518 newargv[ii++] = "-m"; 519 /* 520 * The q option needs to go before the -o option as some 521 * filesystems complain during first pass option parsing. 522 */ 523 if (qflg) 524 newargv[ii++] = "-q"; 525 if (oflg) { 526 newargv[ii++] = "-o"; 527 newargv[ii++] = specific_opts; 528 } 529 if (Oflg) 530 newargv[ii++] = "-O"; 531 if (rflg) 532 newargv[ii++] = "-r"; 533 if (dashflg) 534 newargv[ii++] = "--"; 535 newargv[ii++] = special; 536 newargv[ii++] = mountp; 537 newargv[ii] = NULL; 538 539 doexec(fstype, newargv); 540 return (0); 541 } 542 543 void 544 usage(void) 545 { 546 fprintf(stderr, gettext("Usage:\n%s [-v | -p]\n"), myname); 547 fprintf(stderr, gettext( 548 "%s [-F FSType] [-V] [current_options] [-o specific_options]"), 549 myname); 550 fprintf(stderr, gettext("\n\t{special | mount_point}\n")); 551 552 fprintf(stderr, gettext( 553 "%s [-F FSType] [-V] [current_options] [-o specific_options]"), 554 myname); 555 fprintf(stderr, gettext("\n\tspecial mount_point\n")); 556 557 fprintf(stderr, gettext( 558 "%s -a [-F FSType ] [-V] [current_options] [-o specific_options]\n"), 559 myname); 560 fprintf(stderr, gettext("\t[mount_point ...]\n")); 561 562 exit(1); 563 } 564 565 /* 566 * Get rid of "dev=[hex string]" clause, if any. It's not legal 567 * when printing in vfstab format. 568 */ 569 void 570 elide_dev(char *mntopts) 571 { 572 char *dev, *other; 573 574 if (mntopts != NULL) { 575 dev = strstr(mntopts, "dev="); 576 if (dev != NULL) { 577 other = strpbrk(dev, ","); 578 if (other == NULL) { 579 /* last option */ 580 if (dev != mntopts) { 581 *--dev = '\0'; 582 } else { 583 *dev = '\0'; 584 } 585 } else { 586 /* first or intermediate option */ 587 memmove(dev, other+1, strlen(other+1)+1); 588 } 589 } 590 } 591 } 592 593 void 594 print_mnttab(int vflg, int pflg) 595 { 596 FILE *fd; 597 FILE *rfp; /* this will be NULL if fopen fails */ 598 int ret; 599 char time_buf[TIME_MAX]; /* array to hold date and time */ 600 struct extmnttab mget; 601 time_t ltime; 602 603 if ((fd = fopen(mnttab, "r")) == NULL) { 604 fprintf(stderr, gettext("%s: Cannot open mnttab\n"), myname); 605 exit(1); 606 } 607 rfp = fopen(REMOTE, "r"); 608 while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab))) 609 == 0) { 610 if (ignore(mget.mnt_mntopts)) 611 continue; 612 if (mget.mnt_special && mget.mnt_mountp && 613 mget.mnt_fstype && mget.mnt_time) { 614 ltime = atol(mget.mnt_time); 615 cftime(time_buf, FORMAT, <ime); 616 if (pflg) { 617 elide_dev(mget.mnt_mntopts); 618 printf("%s - %s %s - no %s\n", 619 mget.mnt_special, 620 mget.mnt_mountp, 621 mget.mnt_fstype, 622 mget.mnt_mntopts != NULL ? 623 mget.mnt_mntopts : "-"); 624 } else if (vflg) { 625 printf("%s on %s type %s %s%s on %s", 626 mget.mnt_special, 627 mget.mnt_mountp, 628 mget.mnt_fstype, 629 remote(mget.mnt_fstype, rfp), 630 flags(mget.mnt_mntopts, NEW), 631 time_buf); 632 } else 633 printf("%s on %s %s%s on %s", 634 mget.mnt_mountp, 635 mget.mnt_special, 636 remote(mget.mnt_fstype, rfp), 637 flags(mget.mnt_mntopts, OLD), 638 time_buf); 639 } 640 } 641 if (ret > 0) 642 mnterror(ret); 643 } 644 645 char * 646 flags(char *mntopts, int flag) 647 { 648 char opts[sizeof (mntflags)]; 649 char *value; 650 int rdwr = 1; 651 int suid = 1; 652 int devices = 1; 653 int setuid = 1; 654 655 if (mntopts == NULL || *mntopts == '\0') 656 return ("read/write/setuid/devices"); 657 658 strcpy(opts, ""); 659 while (*mntopts != '\0') { 660 switch (getsubopt(&mntopts, myopts, &value)) { 661 case READONLY: 662 rdwr = 0; 663 break; 664 case READWRITE: 665 rdwr = 1; 666 break; 667 case SUID: 668 suid = 1; 669 break; 670 case NOSUID: 671 suid = 0; 672 break; 673 case SETUID: 674 setuid = 1; 675 break; 676 case NOSETUID: 677 setuid = 0; 678 break; 679 case DEVICES: 680 devices = 1; 681 break; 682 case NODEVICES: 683 devices = 0; 684 break; 685 default: 686 /* cat '/' separator to mntflags */ 687 if (*opts != '\0' && value != NULL) 688 strcat(opts, "/"); 689 strcat(opts, value); 690 break; 691 } 692 } 693 694 strcpy(mntflags, ""); 695 if (rdwr) 696 strcat(mntflags, "read/write"); 697 else if (flag == OLD) 698 strcat(mntflags, "read only"); 699 else 700 strcat(mntflags, "read-only"); 701 if (suid) { 702 if (setuid) 703 strcat(mntflags, "/setuid"); 704 else 705 strcat(mntflags, "/nosetuid"); 706 if (devices) 707 strcat(mntflags, "/devices"); 708 else 709 strcat(mntflags, "/nodevices"); 710 } else { 711 strcat(mntflags, "/nosetuid/nodevices"); 712 } 713 if (*opts != '\0') { 714 strcat(mntflags, "/"); 715 strcat(mntflags, opts); 716 } 717 718 /* 719 * The assumed assertion 720 * assert (strlen(mntflags) < sizeof mntflags); 721 * is valid at this point in the code. Note that a call to "assert" 722 * is not appropriate in production code since it halts the program. 723 */ 724 return (mntflags); 725 } 726 727 char * 728 remote(char *fstype, FILE *rfp) 729 { 730 char buf[BUFSIZ]; 731 char *fs; 732 extern char *strtok(); 733 734 if (rfp == NULL || fstype == NULL || 735 strlen(fstype) > (size_t)FSTYPE_MAX) 736 return (""); /* not a remote */ 737 rewind(rfp); 738 while (fgets(buf, sizeof (buf), rfp) != NULL) { 739 fs = strtok(buf, " \t\n"); 740 if (strcmp(fstype, fs) == 0) 741 return ("remote/"); /* is a remote fs */ 742 } 743 return (""); /* not a remote */ 744 } 745 746 747 void 748 vfserror(int flag, char *special) 749 { 750 if (special == NULL) 751 special = "<null>"; 752 switch (flag) { 753 case VFS_TOOLONG: 754 fprintf(stderr, 755 gettext("%s: Warning: Line in vfstab for \"%s\" exceeds %d characters\n"), 756 myname, special, VFS_LINE_MAX-1); 757 break; 758 case VFS_TOOFEW: 759 fprintf(stderr, 760 gettext("%s: Warning: Line for \"%s\" in vfstab has too few entries\n"), 761 myname, special); 762 break; 763 case VFS_TOOMANY: 764 fprintf(stderr, 765 gettext("%s: Warning: Line for \"%s\" in vfstab has too many entries\n"), 766 myname, special); 767 break; 768 default: 769 fprintf(stderr, gettext( 770 "%s: Warning: Error in line for \"%s\" in vfstab\n"), 771 myname, special); 772 } 773 } 774 775 void 776 mnterror(int flag) 777 { 778 switch (flag) { 779 case MNT_TOOLONG: 780 fprintf(stderr, 781 gettext("%s: Line in mnttab exceeds %d characters\n"), 782 myname, MNT_LINE_MAX-2); 783 break; 784 case MNT_TOOFEW: 785 fprintf(stderr, 786 gettext("%s: Line in mnttab has too few entries\n"), 787 myname); 788 break; 789 case MNT_TOOMANY: 790 fprintf(stderr, 791 gettext("%s: Line in mnttab has too many entries\n"), 792 myname); 793 break; 794 } 795 exit(1); 796 } 797 798 void 799 doexec(char *fstype, char *newargv[]) 800 { 801 char full_path[PATH_MAX]; 802 char alter_path[PATH_MAX]; 803 char *vfs_path = VFS_PATH; 804 char *alt_path = ALT_PATH; 805 int i; 806 int smbfs; 807 808 /* 809 * Special case smbfs file system. 810 * Execute command in profile if possible. 811 */ 812 smbfs = strcmp(fstype, "smbfs") == 0; 813 814 /* build the full pathname of the fstype dependent command. */ 815 sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname); 816 sprintf(alter_path, "%s/%s/%s", alt_path, fstype, myname); 817 newargv[1] = myname; 818 819 if (Vflg) { 820 printf("%s -F %s", newargv[1], fstype); 821 for (i = 2; newargv[i]; i++) 822 printf(" %s", newargv[i]); 823 printf("\n"); 824 fflush(stdout); 825 exit(0); 826 } 827 828 /* 829 * Try to exec the fstype dependent portion of the mount. 830 * See if the directory is there before trying to exec dependent 831 * portion. This is only useful for eliminating the 832 * '..mount: not found' message when '/usr' is mounted 833 */ 834 if (access(full_path, 0) == 0) { 835 if (smbfs) { 836 /* 837 * Run mount_smbfs(1m) with pfexec so that we can 838 * add sys_mount privilege, (via exec_attr, etc.) 839 * allowing normal users to mount on any directory 840 * they own. 841 */ 842 newargv[0] = "pfexec"; 843 newargv[1] = full_path; 844 execv("/usr/bin/pfexec", &newargv[0]); 845 newargv[1] = myname; 846 } 847 execv(full_path, &newargv[1]); 848 if (errno == EACCES) { 849 fprintf(stderr, 850 gettext("%s: Cannot execute %s - permission denied\n"), 851 myname, full_path); 852 } 853 if (errno == ENOEXEC) { 854 newargv[0] = "sh"; 855 newargv[1] = full_path; 856 execv("/sbin/sh", &newargv[0]); 857 } 858 } 859 if (smbfs) { 860 newargv[0] = "pfexec"; 861 newargv[1] = alter_path; 862 execv("/usr/bin/pfexec", &newargv[0]); 863 newargv[1] = myname; 864 } 865 execv(alter_path, &newargv[1]); 866 if (errno == EACCES) { 867 fprintf(stderr, gettext( 868 "%s: Cannot execute %s - permission denied\n"), 869 myname, alter_path); 870 exit(1); 871 } 872 if (errno == ENOEXEC) { 873 newargv[0] = "sh"; 874 newargv[1] = alter_path; 875 execv("/sbin/sh", &newargv[0]); 876 } 877 fprintf(stderr, 878 gettext("%s: Operation not applicable to FSType %s\n"), 879 myname, fstype); 880 exit(1); 881 } 882 883 char *mntopts[] = { MNTOPT_IGNORE, NULL }; 884 #define IGNORE 0 885 886 /* 887 * Return 1 if "ignore" appears in the options string 888 */ 889 int 890 ignore(char *opts) 891 { 892 char *value; 893 char *saveptr, *my_opts; 894 int rval = 0; 895 896 if (opts == NULL || *opts == NULL) 897 return (0); 898 899 /* 900 * we make a copy of the option string to pass to getsubopt(), 901 * because getsubopt() modifies the string. We also save 902 * the original pointer returned by strdup, because getsubopt 903 * changes the pointer passed into it. If strdup fails (unlikely), 904 * we act as if the "ignore" option isn't set rather than fail. 905 */ 906 907 if ((saveptr = my_opts = strdup(opts)) == NULL) 908 nomem(); 909 910 while (*my_opts != '\0') { 911 if (getsubopt(&my_opts, mntopts, &value) == IGNORE) 912 rval = 1; 913 } 914 915 free(saveptr); 916 917 return (rval); 918 } 919 920 /* 921 * Perform the parallel version of mount. If count == 0, mount all 922 * vfstab filesystems with the automnt field == "yes". Use fstype if 923 * supplied. If mntlist supplied, then attempt to only mount those. 924 */ 925 926 int 927 parmount(char **mntlist, int count, char *fstype) 928 { 929 int maxfd = OPEN_MAX; 930 struct rlimit rl; 931 vfsent_t **vl, *vp; 932 933 /* 934 * Process scaling. After running a series 935 * of tests based on the number of simultaneous processes and 936 * processors available, optimum performance was achieved near or 937 * at (PROCN * 2). 938 */ 939 if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1) 940 maxrun = 4; 941 else 942 maxrun = maxrun * 2 + 1; 943 944 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) { 945 rl.rlim_cur = rl.rlim_max; 946 if (setrlimit(RLIMIT_NOFILE, &rl) == 0) 947 maxfd = (int)rl.rlim_cur; 948 } 949 (void) enable_extended_FILE_stdio(-1, -1); 950 951 /* 952 * The parent needs to maintain 3 of its own fd's, plus 2 for 953 * each child (the stdout and stderr pipes). 954 */ 955 maxfd = (maxfd / 2) - 6; /* 6 takes care of temporary */ 956 /* periods of open fds */ 957 if (maxfd < maxrun) 958 maxrun = maxfd; 959 if (maxrun < 4) 960 maxrun = 4; /* sanity check */ 961 962 if (count == 0) 963 mntlist = NULL; /* used as a flag later */ 964 else 965 fstype = NULL; /* mount points supplied: */ 966 /* ignore fstype */ 967 /* 968 * Read the whole vfstab into a linked list for quick processing. 969 * On average, this is the most efficient way to collect and 970 * manipulate the vfstab data. 971 */ 972 vfsll = getvfsall(fstype, mntlist == NULL); 973 974 /* 975 * Make an array out of the vfs linked list for sorting purposes. 976 */ 977 if (vfsll == NULL || 978 (vfsarray = make_vfsarray(mntlist, count)) == NULL) { 979 if (mntlist == NULL) /* not an error - just none found */ 980 return (0); 981 982 fprintf(stderr, gettext("%s: No valid entries found in %s\n"), 983 myname, vfstab); 984 return (1); 985 } 986 987 /* 988 * Sort the entries based on their resolved path names 989 * 990 * If an lofs is encountered, then the original order of the vfstab 991 * file needs to be maintained until we are done mounting lofs's. 992 */ 993 if (!lofscnt) 994 qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *), 995 mlevelcmp); 996 997 /* 998 * Shrink the vfsll linked list down to the new list. This will 999 * speed up the pid search in cleanupkid() later. 1000 */ 1001 vfsll = vfsarray[0]; 1002 for (vl = vfsarray; vp = *vl; ) 1003 vp->next = *++vl; 1004 1005 /* 1006 * Try to handle interrupts in a reasonable way. 1007 */ 1008 sigset(SIGHUP, cleanup); 1009 sigset(SIGQUIT, cleanup); 1010 sigset(SIGINT, cleanup); 1011 1012 do_mounts(); /* do the mounts */ 1013 return (exitcode); 1014 } 1015 1016 /* 1017 * Read all vstab (fp) entries into memory if fstype == NULL. 1018 * If fstype is specified, than read all those that match it. 1019 * 1020 * Returns a linked list. 1021 */ 1022 vfsent_t * 1023 getvfsall(char *fstype, int takeall) 1024 { 1025 vfsent_t *vhead, *vtail; 1026 struct vfstab vget; 1027 FILE *fp; 1028 int cnt = 0, ret; 1029 1030 if ((fp = fopen(vfstab, "r")) == NULL) { 1031 fprintf(stderr, gettext("%s: Cannot open %s\n"), 1032 myname, vfstab); 1033 exit(1); 1034 } 1035 1036 vhead = vtail = NULL; 1037 1038 while ((ret = getvfsent(fp, &vget)) != -1) { 1039 vfsent_t *vp; 1040 1041 if (ret > 0) { 1042 vfserror(ret, vget.vfs_mountp); 1043 continue; 1044 } 1045 1046 /* 1047 * If mount points were not specified, then we ignore 1048 * entries that aren't marked "yes". 1049 */ 1050 if (takeall && 1051 (vget.vfs_automnt == NULL || 1052 strcmp(vget.vfs_automnt, "yes"))) 1053 continue; 1054 1055 if (fstype && vget.vfs_fstype && 1056 strcmp(fstype, vget.vfs_fstype)) 1057 continue; 1058 1059 if (vget.vfs_mountp == NULL || 1060 (vget.vfs_fstype && (strcmp(vget.vfs_fstype, "swap") == 0))) 1061 continue; 1062 1063 if (check_fields(vget.vfs_fstype, vget.vfs_mountp)) { 1064 exitcode = 1; 1065 continue; 1066 } 1067 1068 vp = new_vfsent(&vget, cnt); /* create new vfs entry */ 1069 if (vhead == NULL) 1070 vhead = vp; 1071 else 1072 vtail->next = vp; 1073 vtail = vp; 1074 cnt++; 1075 } 1076 fclose(fp); 1077 if (vtail == NULL) { 1078 vfsarraysize = 0; 1079 vfslltail = NULL; 1080 return (NULL); 1081 } 1082 vtail->next = NULL; 1083 vfslltail = vtail; /* save it in the global variable */ 1084 vfsarraysize = cnt; 1085 return (vhead); 1086 } 1087 1088 1089 /* 1090 * Returns an array of vfsent_t's based on vfsll & mntlist. 1091 */ 1092 vfsent_t ** 1093 make_vfsarray(char **mntlist, int count) 1094 { 1095 vfsent_t *vp, *vmark, *vpprev, **vpp; 1096 int ndx, found; 1097 1098 if (vfsll == NULL) 1099 return (NULL); 1100 1101 if (count > 0) 1102 vfsarraysize = count; 1103 1104 vpp = (vfsent_t **)malloc(sizeof (*vpp) * (vfsarraysize + 1)); 1105 if (vpp == NULL) 1106 nomem(); 1107 1108 if (mntlist == NULL) { 1109 /* 1110 * No mount list specified: take all vfstab mount points. 1111 */ 1112 for (ndx = 0, vp = vfsll; vp; vp = vp->next) { 1113 (void) setrpath(vp); 1114 /* 1115 * Sigh. lofs entries can complicate matters so much 1116 * that the best way to avoid problems is to 1117 * stop parallel mounting when an lofs is 1118 * encountered, so we keep a count of how many 1119 * there are. 1120 * Fortunately this is rare. 1121 */ 1122 if (vp->v.vfs_fstype && 1123 (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0)) 1124 lofscnt++; 1125 1126 vpp[ndx++] = vp; 1127 } 1128 vpp[ndx] = NULL; 1129 return (vpp); 1130 } 1131 1132 /* 1133 * A list of mount points was specified on the command line 1134 * and we need to search for each one. 1135 */ 1136 vpprev = vfslltail; 1137 vpprev