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