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