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 /*
  30  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
  31  */
  32 
  33 #include        <stdio.h>
  34 #include        <stdio_ext.h>
  35 #include        <limits.h>
  36 #include        <fcntl.h>
  37 #include        <unistd.h>
  38 #include        <stdlib.h>
  39 #include        <string.h>
  40 #include        <stdarg.h>
  41 #include        <sys/types.h>
  42 #include        <sys/stat.h>
  43 #include        <sys/statvfs.h>
  44 #include        <errno.h>
  45 #include        <sys/mnttab.h>
  46 #include        <sys/mntent.h>
  47 #include        <sys/mount.h>
  48 #include        <sys/vfstab.h>
  49 #include        <sys/param.h>
  50 #include        <sys/wait.h>
  51 #include        <sys/signal.h>
  52 #include        <sys/resource.h>
  53 #include        <stropts.h>
  54 #include        <sys/conf.h>
  55 #include        <locale.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, &ltime);
 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          * Try to exec the fstype dependent portion of the mount.
 824          * See if the directory is there before trying to exec dependent
 825          * portion.  This is only useful for eliminating the
 826          * '..mount: not found' message when '/usr' is mounted
 827          */
 828         if (access(full_path, 0) == 0) {
 829                 execv(full_path, &newargv[1]);
 830                 if (errno == EACCES) {
 831                         fprintf(stderr,
 832                         gettext("%s: Cannot execute %s - permission denied\n"),
 833                             myname, full_path);
 834                 }
 835                 if (errno == ENOEXEC) {
 836                         newargv[0] = "sh";
 837                         newargv[1] = full_path;
 838                         execv("/sbin/sh", &newargv[0]);
 839                 }
 840         }
 841         execv(alter_path, &newargv[1]);
 842         if (errno == EACCES) {
 843                 fprintf(stderr, gettext(
 844                     "%s: Cannot execute %s - permission denied\n"),
 845                     myname, alter_path);
 846                 exit(1);
 847         }
 848         if (errno == ENOEXEC) {
 849                 newargv[0] = "sh";
 850                 newargv[1] = alter_path;
 851                 execv("/sbin/sh", &newargv[0]);
 852         }
 853         fprintf(stderr,
 854             gettext("%s: Operation not applicable to FSType %s\n"),
 855             myname, fstype);
 856         exit(1);
 857 }
 858 
 859 char *mntopts[] = { MNTOPT_IGNORE, NULL };
 860 #define IGNORE    0
 861 
 862 /*
 863  * Return 1 if "ignore" appears in the options string
 864  */
 865 int
 866 ignore(char *opts)
 867 {
 868         char *value;
 869         char *saveptr, *my_opts;
 870         int rval = 0;
 871 
 872         if (opts == NULL || *opts == NULL)
 873                 return (0);
 874 
 875         /*
 876          * we make a copy of the option string to pass to getsubopt(),
 877          * because getsubopt() modifies the string.  We also save
 878          * the original pointer returned by strdup, because getsubopt
 879          * changes the pointer passed into it.  If strdup fails (unlikely),
 880          * we act as if the "ignore" option isn't set rather than fail.
 881          */
 882 
 883         if ((saveptr = my_opts = strdup(opts)) == NULL)
 884                 nomem();
 885 
 886         while (*my_opts != '\0') {
 887                 if (getsubopt(&my_opts, mntopts, &value) == IGNORE)
 888                         rval = 1;
 889         }
 890 
 891         free(saveptr);
 892 
 893         return (rval);
 894 }
 895 
 896 /*
 897  * Perform the parallel version of mount.  If count == 0, mount all
 898  * vfstab filesystems with the automnt field == "yes".  Use fstype if
 899  * supplied.  If mntlist supplied, then attempt to only mount those.
 900  */
 901 
 902 int
 903 parmount(char **mntlist, int count, char *fstype)
 904 {
 905         int             maxfd = OPEN_MAX;
 906         struct          rlimit rl;
 907         vfsent_t        **vl, *vp;
 908 
 909         /*
 910          * Process scaling.  After running a series
 911          * of tests based on the number of simultaneous processes and
 912          * processors available, optimum performance was achieved near or
 913          * at (PROCN * 2).
 914          */
 915         if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1)
 916                 maxrun = 4;
 917         else
 918                 maxrun = maxrun * 2 + 1;
 919 
 920         if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
 921                 rl.rlim_cur = rl.rlim_max;
 922                 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
 923                         maxfd = (int)rl.rlim_cur;
 924         }
 925         (void) enable_extended_FILE_stdio(-1, -1);
 926 
 927         /*
 928          * The parent needs to maintain 3 of its own fd's, plus 2 for
 929          * each child (the stdout and stderr pipes).
 930          */
 931         maxfd = (maxfd / 2) - 6;        /* 6 takes care of temporary  */
 932                                         /* periods of open fds */
 933         if (maxfd < maxrun)
 934                 maxrun = maxfd;
 935         if (maxrun < 4)
 936                 maxrun = 4;             /* sanity check */
 937 
 938         if (count == 0)
 939                 mntlist = NULL;         /* used as a flag later */
 940         else
 941                 fstype = NULL;          /* mount points supplied: */
 942                                         /* ignore fstype */
 943         /*
 944          * Read the whole vfstab into a linked list for quick processing.
 945          * On average, this is the most efficient way to collect and
 946          * manipulate the vfstab data.
 947          */
 948         vfsll = getvfsall(fstype, mntlist == NULL);
 949 
 950         /*
 951          * Make an array out of the vfs linked list for sorting purposes.
 952          */
 953         if (vfsll == NULL ||
 954             (vfsarray = make_vfsarray(mntlist, count)) == NULL) {
 955                 if (mntlist == NULL)    /* not an error - just none found */
 956                         return (0);
 957 
 958                 fprintf(stderr, gettext("%s: No valid entries found in %s\n"),
 959                     myname, vfstab);
 960                 return (1);
 961         }
 962 
 963         /*
 964          * Sort the entries based on their resolved path names
 965          *
 966          * If an lofs is encountered, then the original order of the vfstab
 967          * file needs to be maintained until we are done mounting lofs's.
 968          */
 969         if (!lofscnt)
 970                 qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *),
 971                     mlevelcmp);
 972 
 973         /*
 974          * Shrink the vfsll linked list down to the new list.  This will
 975          * speed up the pid search in cleanupkid() later.
 976          */
 977         vfsll = vfsarray[0];
 978         for (vl = vfsarray; vp = *vl; )
 979                 vp->next = *++vl;
 980 
 981         /*
 982          * Try to handle interrupts in a reasonable way.
 983          */
 984         sigset(SIGHUP, cleanup);
 985         sigset(SIGQUIT, cleanup);
 986         sigset(SIGINT, cleanup);
 987 
 988         do_mounts();            /* do the mounts */
 989 
 990         if (failcnt > 0 && failcnt == lofsfail)
 991                 return (ALL_LOFS_FAILURES);
 992 
 993         return (exitcode);
 994 }
 995 
 996 /*
 997  * Read all vstab (fp) entries into memory if fstype == NULL.
 998  * If fstype is specified, than read all those that match it.
 999  *
1000  * Returns a linked list.
1001  */
1002 vfsent_t *
1003 getvfsall(char *fstype, int takeall)
1004 {
1005         vfsent_t        *vhead, *vtail;
1006         struct vfstab   vget;
1007         FILE            *fp;
1008         int             cnt = 0, ret;
1009 
1010         if ((fp = fopen(vfstab, "r")) == NULL) {
1011                 fprintf(stderr, gettext("%s: Cannot open %s\n"),
1012                     myname, vfstab);
1013                 exit(1);
1014         }
1015 
1016         vhead = vtail = NULL;
1017 
1018         while ((ret = getvfsent(fp, &vget)) != -1) {
1019                 vfsent_t *vp;
1020 
1021                 if (ret > 0) {
1022                         vfserror(ret, vget.vfs_mountp);
1023                         continue;
1024                 }
1025 
1026                 /*
1027                  * If mount points were not specified, then we ignore
1028                  * entries that aren't marked "yes".
1029                  */
1030                 if (takeall &&
1031                     (vget.vfs_automnt == NULL ||
1032                     strcmp(vget.vfs_automnt, "yes")))
1033                         continue;
1034 
1035                 if (fstype && vget.vfs_fstype &&
1036                     strcmp(fstype, vget.vfs_fstype))
1037                         continue;
1038 
1039                 if (vget.vfs_mountp == NULL ||
1040                     (vget.vfs_fstype && (strcmp(vget.vfs_fstype, "swap") == 0)))
1041                         continue;
1042 
1043                 if (check_fields(vget.vfs_fstype, vget.vfs_mountp)) {
1044                         exitcode = 1;
1045                         continue;
1046                 }
1047 
1048                 vp = new_vfsent(&vget, cnt);        /* create new vfs entry */
1049                 if (vhead == NULL)
1050                         vhead = vp;
1051                 else
1052                         vtail->next = vp;
1053                 vtail = vp;
1054                 cnt++;
1055         }
1056         fclose(fp);
1057         if (vtail == NULL) {
1058                 vfsarraysize = 0;
1059                 vfslltail = NULL;
1060                 return (NULL);
1061         }
1062         vtail->next = NULL;
1063         vfslltail = vtail;      /* save it in the global variable */
1064         vfsarraysize = cnt;
1065         return (vhead);
1066 }
1067 
1068 
1069 /*
1070  * Returns an array of vfsent_t's based on vfsll & mntlist.
1071  */
1072 vfsent_t **
1073 make_vfsarray(char **mntlist, int count)
1074 {
1075         vfsent_t        *vp, *vmark, *vpprev, **vpp;
1076         int             ndx, found;
1077 
1078         if (vfsll == NULL)
1079                 return (NULL);
1080 
1081         if (count > 0)
1082                 vfsarraysize = count;
1083 
1084         vpp = (vfsent_t **)malloc(sizeof (*vpp) * (vfsarraysize + 1));
1085         if (vpp == NULL)
1086                 nomem();
1087 
1088         if (mntlist == NULL) {
1089                 /*
1090                  * No mount list specified: take all vfstab mount points.
1091                  */
1092                 for (ndx = 0, vp = vfsll; vp; vp = vp->next) {
1093                         (void) setrpath(vp);
1094                         /*
1095                          * Sigh. lofs entries can complicate matters so much
1096                          * that the best way to avoid problems is to
1097                          * stop parallel mounting when an lofs is
1098                          * encountered, so we keep a count of how many
1099                          * there are.
1100                          * Fortunately this is rare.
1101                          */
1102                         if (vp->v.vfs_fstype &&
1103                             (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0))
1104                                 lofscnt++;
1105 
1106                         vpp[ndx++] = vp;
1107                 }
1108                 vpp[ndx] = NULL;
1109                 return (vpp);
1110         }
1111 
1112         /*
1113          * A list of mount points was specified on the command line
1114          * and we need to search for each one.
1115          */
1116         vpprev = vfslltail;
1117         vpprev->next = vfsll;        /* make a circle out of it */
1118         vmark = vp = vfsll;
1119         /*
1120          * For each specified mount point:
1121          */
1122         for (ndx = 0; *mntlist; mntlist++) {
1123                 found = 0;
1124                 /*
1125                  * Circle our entire linked list, looking for *mntlist.
1126                  */
1127                 while (vp) {
1128                         if (strcmp(*mntlist, vp->v.vfs_mountp) == 0) {
1129                                 vpp[ndx++] = vp;        /* found it. */
1130                                 (void) setrpath(vp);
1131                                 if (vp->v.vfs_fstype &&
1132                                     (strcmp(vp->v.vfs_fstype,
1133                                     MNTTYPE_LOFS) == 0))
1134                                         lofscnt++;
1135 
1136                                 if (vp == vpprev) {     /* list exhausted */
1137                                         vp = NULL;
1138                                         found++;
1139                                         break;
1140                                 }
1141                                 /*
1142                                  * Remove it from the circular list.  vpprev
1143                                  * remains unchanged.
1144                                  */
1145                                 vp = vp->next;
1146                                 vpprev->next->next = NULL;
1147                                 vpprev->next = vp;
1148                                 /*
1149                                  * Set vmark to the first elem that we check
1150                                  * each time.
1151                                  */
1152                                 vmark = vp;
1153                                 found++;
1154                                 break;
1155                         }
1156                         vpprev = vp;
1157                         vp = vp->next;
1158                         if (vp == vmark)        /* break out if we completed */
1159                                                 /* the circle */
1160                                 break;
1161                 }
1162 
1163                 if (!found) {
1164                         fprintf(stderr, gettext(
1165                             "%s: Warning: %s not found in %s\n"),
1166                             myname, *mntlist, vfstab);
1167                         exitcode = 1;
1168                 }
1169         }
1170         if (ndx == 0)
1171                 return (NULL);
1172 
1173         vpp[ndx] = NULL;        /* null terminate the list */
1174         vfsarraysize = ndx;     /* adjust vfsarraysize */
1175         return (vpp);
1176 }
1177 
1178 /*
1179  * Performs the exec argument processing, all  of the child forking and
1180  * execing, and child cleanup.
1181  * Sets exitcode to non-zero if any errors occurred.
1182  */
1183 void
1184 do_mounts(void)
1185 {
1186         int             i, isave, cnt;
1187         vfsent_t        *vp, *vpprev, **vl;
1188         char            *newargv[ARGV_MAX];
1189         pid_t           child;
1190 
1191         /*
1192          * create the arg list once;  the only differences among
1193          * the calls are the options, special and mountp fields.
1194          */
1195         i = 2;
1196         if (cflg)
1197                 newargv[i++] = "-c";
1198         if (gflg)
1199                 newargv[i++] = "-g";
1200         if (mflg)
1201                 newargv[i++] = "-m";
1202         if (Oflg)
1203                 newargv[i++] = "-O";
1204         if (qflg)
1205                 newargv[i++] = "-q";
1206         if (rflg)
1207                 newargv[i++] = "-r";
1208         if (dashflg)
1209                 newargv[i++] = "--";
1210         if (oflg) {
1211                 newargv[i++] = "-o";
1212                 newargv[i++] = specific_opts;
1213         }
1214         isave = i;
1215 
1216         /*
1217          * Main loop for the mount processes
1218          */
1219         vl = vfsarray;
1220         cnt = vfsarraysize;
1221         for (vpprev = *vl; vp = *vl; vpprev = vp, vl++, cnt--) {
1222                 /*
1223                  * Check to see if we cross a mount level: e.g.,
1224                  * /a/b -> /a/b/c.  If so, we need to wait for all current
1225                  * mounts to finish, rerun realpath on the remaining mount
1226                  * points, and resort the list.
1227                  *
1228                  * Also, we mount serially as long as there are lofs's
1229                  * to mount to avoid improper mount ordering.
1230                  */
1231                 if (vp->mlevel > vpprev->mlevel || lofscnt > 0) {
1232                         vfsent_t **vlp;
1233 
1234                         while (nrun > 0 && (dowait() != -1))
1235                                 ;
1236                         /*
1237                          * Gads! It's possible for real path mounts points to
1238                          * change after mounts are done at a lower mount
1239                          * level.
1240                          * Thus, we need to recalculate mount levels and
1241                          * resort the list from this point.
1242                          */
1243                         for (vlp = vl; *vlp; vlp++)
1244                                 (void) setrpath(*vlp);
1245                         /*
1246                          * Sort the remaining entries based on their newly
1247                          * resolved path names.
1248                          * Do not sort if we still have lofs's to mount.
1249                          */
1250                         if (lofscnt == 0) {
1251                                 qsort((void *)vl, cnt, sizeof (vfsent_t *),
1252                                     mlevelcmp);
1253                                 vp = *vl;
1254                         }
1255                 }
1256 
1257                 if (vp->flag & VRPFAILED) {
1258                         fprintf(stderr, gettext(
1259                             "%s: Nonexistent mount point: %s\n"),
1260                             myname, vp->v.vfs_mountp);
1261                         vp->flag |= VNOTMOUNTED;
1262                         exitcode = 1;
1263                         continue;
1264                 }
1265 
1266                 /*
1267                  * If mount options were not specified on the command
1268                  * line, then use the ones found in the vfstab entry,
1269                  * if any.
1270                  */
1271                 i = isave;
1272                 if (!oflg && vp->v.vfs_mntopts) {
1273                         newargv[i++] = "-o";
1274                         newargv[i++] = vp->v.vfs_mntopts;
1275                 }
1276                 newargv[i++] = vp->v.vfs_special;
1277                 newargv[i++] = vp->rpath;
1278                 newargv[i] = NULL;
1279 
1280                 /*
1281                  * This should never really fail.
1282                  */
1283                 while (setup_iopipe(vp) == -1 && (dowait() != -1))
1284                         ;
1285 
1286                 while (nrun >= maxrun && (dowait() != -1))   /* throttle */
1287                         ;
1288 
1289                 if ((child = fork()) == -1) {
1290                         perror("fork");
1291                         cleanup(-1);
1292                         /* not reached */
1293                 }
1294                 if (child == 0) {               /* child */
1295                         signal(SIGHUP, SIG_IGN);
1296                         signal(SIGQUIT, SIG_IGN);
1297                         signal(SIGINT, SIG_IGN);
1298                         setup_output(vp);
1299                         doexec(vp->v.vfs_fstype, newargv);
1300                         perror("exec");
1301                         exit(1);
1302                 }
1303 
1304                 /* parent */
1305                 (void) close(vp->sopipe[WRPIPE]);
1306                 (void) close(vp->sepipe[WRPIPE]);
1307                 vp->pid = child;
1308                 nrun++;
1309         }
1310         /*
1311          * Mostly done by now - wait and clean up the stragglers.
1312          */
1313         cleanup(0);
1314 }
1315 
1316 
1317 /*
1318  * Setup stdout and stderr pipes for the children's output.
1319  */
1320 int
1321 setup_iopipe(vfsent_t *mp)
1322 {
1323         /*
1324          * Make a stdout and stderr pipe.  This should never fail.
1325          */
1326         if (pipe(mp->sopipe) == -1)
1327                 return (-1);
1328         if (pipe(mp->sepipe) == -1) {
1329                 (void) close(mp->sopipe[RDPIPE]);
1330                 (void) close(mp->sopipe[WRPIPE]);
1331                 return (-1);
1332         }
1333         /*
1334          * Don't block on an empty pipe.
1335          */
1336         (void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1337         (void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1338         /*
1339          * Don't pass extra fds into children.
1340          */
1341         (void) fcntl(mp->sopipe[RDPIPE], F_SETFD, FD_CLOEXEC);
1342         (void) fcntl(mp->sepipe[RDPIPE], F_SETFD, FD_CLOEXEC);
1343 
1344         return (0);
1345 }
1346 
1347 /*
1348  * Called by a child to attach its stdout and stderr to the write side of
1349  * the pipes.
1350  */
1351 void
1352 setup_output(vfsent_t *vp)
1353 {
1354 
1355         (void) close(fileno(stdout));
1356         (void) dup(vp->sopipe[WRPIPE]);
1357         (void) close(vp->sopipe[WRPIPE]);
1358 
1359         (void) close(fileno(stderr));
1360         (void) dup(vp->sepipe[WRPIPE]);
1361         (void) close(vp->sepipe[WRPIPE]);
1362 }
1363 
1364 /*
1365  * Parent uses this to print any stdout or stderr output issued by
1366  * the child.
1367  */
1368 static void
1369 doio(vfsent_t *vp)
1370 {
1371         int bytes;
1372         char ibuf[BUFSIZ];
1373 
1374         while ((bytes = read(vp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1375                 write(fileno(stderr), ibuf, bytes);
1376         while ((bytes = read(vp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1377                 write(fileno(stdout), ibuf, bytes);
1378 
1379         (void) close(vp->sopipe[RDPIPE]);
1380         (void) close(vp->sepipe[RDPIPE]);
1381 }
1382 
1383 /*
1384  * Waits for 1 child to die.
1385  *
1386  * Returns -1 if no children are left to wait for.
1387  * Returns 0 if a child died without an error.
1388  * Returns 1 if a child died with an error.
1389  */
1390 int
1391 dowait(void)
1392 {
1393         int child, wstat;
1394 
1395         if ((child = wait(&wstat)) == -1)
1396                 return (-1);
1397         nrun--;
1398         return (cleanupkid(child, wstat) != 0);
1399 }
1400 
1401 /*
1402  * Locates the child mount process represented by pid, outputs any io
1403  * it may have, and returns its exit code.
1404  * Sets the global exitcode if an error occurred.
1405  */
1406 int
1407 cleanupkid(pid_t pid, int wstat)
1408 {
1409         vfsent_t *vp, *prevp;
1410         int ret;
1411 
1412         if (WIFEXITED(wstat))           /* this should always be true */
1413                 ret = WEXITSTATUS(wstat);
1414         else
1415                 ret = 1;                /* assume some kind of error */
1416         if (ret) {
1417                 exitcode = 1;
1418                 failcnt++;
1419         }
1420 
1421         /*
1422          * Find our child.
1423          * This search gets smaller and smaller as children are cleaned
1424          * up.
1425          */
1426         for (prevp = NULL, vp = vfsll; vp; vp = vp->next) {
1427                 if (vp->pid != pid) {
1428                         prevp = vp;
1429                         continue;
1430                 }
1431                 /*
1432                  * Found: let's remove it from this linked list.
1433                  */
1434                 if (prevp) {
1435                         prevp->next = vp->next;
1436                         vp->next = NULL;
1437                 }
1438                 break;
1439         }
1440 
1441         if (vp == NULL) {
1442                 /*
1443                  * This should never happen.
1444                  */
1445                 fprintf(stderr, gettext(
1446                     "%s: Unknown child %d\n"), myname, pid);
1447                 exitcode = 1;
1448                 return (ret);
1449         }
1450         doio(vp);       /* Any output? */
1451 
1452         if (vp->v.vfs_fstype &&
1453             (strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0)) {
1454                 lofscnt--;
1455                 if (ret)
1456                         lofsfail++;
1457         }
1458 
1459         vp->exitcode = ret;
1460         return (ret);
1461 }
1462 
1463 
1464 static vfsent_t zvmount = { 0 };
1465 
1466 vfsent_t *
1467 new_vfsent(struct vfstab *vin, int order)
1468 {
1469         vfsent_t *new;
1470 
1471         new = (vfsent_t *)malloc(sizeof (*new));
1472         if (new == NULL)
1473                 nomem();
1474 
1475         *new = zvmount;
1476         if (vin->vfs_special &&
1477             (new->v.vfs_special = strdup(vin->vfs_special)) == NULL)
1478                 nomem();
1479         if (vin->vfs_mountp &&
1480             (new->v.vfs_mountp = strdup(vin->vfs_mountp)) == NULL)
1481                 nomem();
1482         if (vin->vfs_fstype &&
1483             (new->v.vfs_fstype = strdup(vin->vfs_fstype)) == NULL)
1484                 nomem();
1485         /*
1486          * If specific mount options were specified on the command
1487          * line, then use those.  Else, use the ones on the vfstab
1488          * line, if any.  In other words, specific options on the
1489          * command line override those in /etc/vfstab.
1490          */
1491         if (oflg) {
1492                 if ((new->v.vfs_mntopts = strdup(specific_opts)) == NULL)
1493                         nomem();
1494         } else if (vin->vfs_mntopts &&
1495             (new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL)
1496                         nomem();
1497 
1498         new->order = order;
1499         return (new);
1500 }
1501 
1502 /*
1503  * Runs realpath on vp's mount point, records success or failure,
1504  * resets the mount level based on the new realpath, and returns
1505  * realpath()'s return value.
1506  */
1507 char *
1508 setrpath(vfsent_t *vp)
1509 {
1510         char *rp;
1511 
1512         if ((rp = realpath(vp->v.vfs_mountp, realdir)) == NULL)
1513                 vp->flag |= VRPFAILED;
1514         else
1515                 vp->flag &= ~VRPFAILED;
1516 
1517         if (vp->rpath)
1518                 free(vp->rpath);
1519         if ((vp->rpath = strdup(realdir)) == NULL)
1520                 nomem();
1521         vp->mlevel = fsgetmlevel(vp->rpath);
1522         return (rp);
1523 }
1524 
1525 
1526 /*
1527  * sort first by mlevel (1...N), then by vfstab order.
1528  */
1529 int
1530 mlevelcmp(const void *a, const void *b)
1531 {
1532         vfsent_t *a1, *b1;
1533         int     lcmp;
1534 
1535         a1 = *(vfsent_t **)a;
1536         b1 = *(vfsent_t **)b;
1537 
1538         lcmp = a1->mlevel - b1->mlevel;
1539         if (lcmp == 0)
1540                 lcmp = a1->order - b1->order;
1541         return (lcmp);
1542 }
1543 
1544 /* sort by vfstab order.  0..N */
1545 static int
1546 mordercmp(const void *a, const void *b)
1547 {
1548         vfsent_t *a1, *b1;
1549 
1550         a1 = *(vfsent_t **)a;
1551         b1 = *(vfsent_t **)b;
1552         return (a1->order - b1->order);
1553 }
1554 
1555 /*
1556  * cleanup the existing children and exit with an error
1557  * if asig != 0.
1558  */
1559 void
1560 cleanup(int asig)
1561 {
1562         while (nrun > 0 && (dowait() != -1))
1563                 ;
1564 
1565         if (asig != 0)
1566                 exit(1);
1567 }
1568 
1569 
1570 int
1571 check_fields(char *fstype, char *mountp)
1572 {
1573         struct stat64 stbuf;
1574 
1575         if (strlen(fstype) > (size_t)FSTYPE_MAX) {
1576                 fprintf(stderr,
1577                     gettext("%s: FSType %s exceeds %d characters\n"),
1578                     myname, fstype, FSTYPE_MAX);
1579                 return (1);
1580         }
1581 
1582         if (mountp == NULL) {
1583                 fprintf(stderr,
1584                     gettext("%s: Mount point cannot be determined\n"),
1585                     myname);
1586                 return (1);
1587         }
1588         if (*mountp != '/') {
1589                 fprintf(stderr, gettext(
1590                     "%s: Mount point %s is not an absolute pathname.\n"),
1591                     myname, mountp);
1592                 return (1);
1593         }
1594         /*
1595          * Don't do some of these checks if aflg because a mount point may
1596          * not exist now, but will be mounted before we get to it.
1597          * This is one of the quirks of "secondary mounting".
1598          */
1599         if (!aflg && stat64(mountp, &stbuf) < 0) {
1600                 if (errno == ENOENT || errno == ENOTDIR)
1601                         fprintf(stderr,
1602                             gettext("%s: Mount point %s does not exist.\n"),
1603                             myname, mountp);
1604                 else {
1605                         fprintf(stderr,
1606                             gettext("%s: Cannot stat mount point %s.\n"),
1607                             myname, mountp);
1608                         perror(myname);
1609                 }
1610                 return (1);
1611         }
1612         return (0);
1613 }
1614 
1615 void
1616 nomem(void)
1617 {
1618         fprintf(stderr, gettext("%s: Out of memory\n"), myname);
1619         while (nrun > 0 && (dowait() != -1))
1620                 ;
1621         exit(1);
1622 }