4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
31 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
32 * Use is subject to license terms.
36 #include <stdio_ext.h>
43 #include <sys/types.h>
45 #include <sys/statvfs.h>
47 #include <sys/mnttab.h>
48 #include <sys/mntent.h>
49 #include <sys/mount.h>
50 #include <sys/vfstab.h>
51 #include <sys/param.h>
53 #include <sys/signal.h>
54 #include <sys/resource.h>
60 #define VFS_PATH "/usr/lib/fs"
61 #define ALT_PATH "/etc/fs"
62 #define REMOTE "/etc/dfs/fstypes"
81 #define FORMAT "%a %b %e %H:%M:%S %Y\n" /* date time format */
82 /* a - abbreviated weekday name */
83 /* b - abbreviated month name */
84 /* e - day of month */
92 * The fs-local method understands this exit code to mean that one or
93 * more failures occurred and that all the failures were of attempted
96 #define ALL_LOFS_FAILURES 111
101 extern void usage(void);
102 extern char *flags(char *, int);
103 extern char *remote(char *, FILE *);
104 extern char *default_fstype(char *);
118 static char *myname
; /* point to argv[0] */
121 * Set the limit to double the number of characters a user should be allowed to
123 * This should cover the different shells, which don't use POSIX_MAX_INPUT,
124 * and should cover the case where a long option string can be in
125 * the /etc/vfstab file.
127 char mntflags
[(_POSIX_MAX_INPUT
+1) * 2];
129 char realdir
[MAXPATHLEN
]; /* buffer for realpath() calls */
130 char *vfstab
= VFSTAB
;
131 char *mnttab
= MNTTAB
;
132 char *specific_opts
; /* holds specific mount options */
133 char *generic_opts
; /* holds generic mount options */
136 int failcnt
; /* total count of failures */
137 int lofscnt
; /* presence of lofs prohibits parallel */
139 int lofsfail
; /* count of failures of lofs mounts */
141 int aflg
, cflg
, fflg
, Fflg
, oflg
, pflg
, rflg
, vflg
, Vflg
, mflg
, Oflg
,
142 dashflg
, questflg
, dflg
, qflg
;
146 * Each vfsent_t describes a vfstab entry. It is used to manage and cleanup
147 * each child that performs the particular mount for the entry.
150 typedef struct vfsent
{
151 struct vfstab v
; /* the vfstab entry */
152 char *rpath
; /* resolved pathname so far */
153 int mlevel
; /* how deep is this mount point */
154 int order
; /* vfstab serial order of this vfs */
156 pid_t pid
; /* the pid of this mount process */
157 int exitcode
; /* process's exitcode */
160 int sopipe
[2]; /* pipe attached to child's stdout */
161 int sepipe
[2]; /* pipe attached to child's stderr */
162 struct vfsent
*next
; /* used when in linked list */
165 #define VRPFAILED 0x01 /* most recent realpath failed on */
166 /* this mount point */
167 #define VNOTMOUNTED 0x02 /* mount point could not be mounted */
169 vfsent_t
*vfsll
, *vfslltail
; /* head and tail of the global */
170 /* linked list of vfstab entries */
171 vfsent_t
**vfsarray
; /* global array of vfsent_t's */
172 int vfsarraysize
; /* length of the list */
175 * This structure is used to build a linked list of
176 * mnttab structures from /etc/mnttab.
178 typedef struct mountent
{
179 struct extmnttab
*ment
;
181 struct mountent
*next
;
186 static vfsent_t
**make_vfsarray(char **, int);
187 static vfsent_t
*new_vfsent(struct vfstab
*, int);
188 static vfsent_t
*getvfsall(char *, int);
190 static void doexec(char *, char **);
192 static void cleanup(int);
193 static char *setrpath(vfsent_t
*);
195 static int setup_iopipe(vfsent_t
*);
196 static void setup_output(vfsent_t
*);
197 static void doio(vfsent_t
*);
198 static void do_mounts();
199 static int parmount(char **, int, char *);
200 static int mlevelcmp(const void *, const void *);
201 static int mordercmp(const void *, const void *);
202 static int check_fields(char *, char *);
203 static int cleanupkid(pid_t
, int);
204 static void print_mnttab(int, int);
205 static void vfserror(int, char *);
206 static void mnterror(int);
207 static int ignore(char *);
210 * This is /usr/sbin/mount: the generic command that in turn
211 * execs the appropriate /usr/lib/fs/{fstype}/mount.
212 * The -F flag and argument are NOT passed.
213 * If the usr file system is not mounted a duplicate copy
214 * can be found in /sbin and this version execs the
215 * appropriate /etc/fs/{fstype}/mount
217 * If the -F fstype, special or directory are missing,
218 * /etc/vfstab is searched to fill in the missing arguments.
220 * -V will print the built command on the stdout.
221 * It isn't passed either.
224 main(int argc
, char *argv
[])
226 char *special
, /* argument of special/resource */
227 *mountp
, /* argument of mount directory */
228 *fstype
, /* wherein the fstype name is filled */
229 *newargv
[ARGV_MAX
], /* arg list for specific command */
230 *farg
= NULL
, *Farg
= NULL
;
231 int ii
, ret
, cc
, fscnt
;
233 struct vfstab vget
, vref
;
237 (void) setlocale(LC_ALL
, "");
239 #if !defined(TEXT_DOMAIN)
240 #define TEXT_DOMAIN "SYS_TEST"
242 (void) textdomain(TEXT_DOMAIN
);
244 myname
= strrchr(argv
[0], '/');
249 if (myname
== 0) myname
= "path unknown";
251 /* Process the args. */
253 while ((cc
= getopt(argc
, argv
, "?acd:f:F:mno:pqrt:vVO")) != -1)
279 break; /* do not update /etc/mnttab */
282 if ((specific_opts
= strdup(optarg
)) == NULL
)
284 break; /* fstype dependent options */
309 /* copy '--' to specific */
310 if (strcmp(argv
[optind
-1], "--") == 0)
313 /* option checking */
314 /* more than two args not allowed if !aflg */
315 if (!aflg
&& (argc
- optind
> 2))
318 /* pv mututally exclusive */
319 if (pflg
+ vflg
+ aflg
> 1) {
320 fprintf(stderr
, gettext
321 ("%s: -a, -p, and -v are mutually exclusive\n"),
327 * Can't have overlaying mounts on the same mount point during
331 fprintf(stderr
, gettext
332 ("%s: -a and -O are mutually exclusive\n"), myname
);
336 /* dfF mutually exclusive */
337 if (fflg
+ Fflg
> 1) {
338 fprintf(stderr
, gettext
339 ("%s: More than one FSType specified\n"), myname
);
343 /* no arguments, only allow p,v,V or [F]? */
344 if (!aflg
&& optind
== argc
) {
345 if (cflg
|| fflg
|| mflg
|| oflg
|| rflg
|| qflg
)
348 if (Fflg
&& !questflg
)
355 doexec(Farg
, newargv
);
364 /* one or two args, allow any but p,v */
365 if (optind
!= argc
&& (pflg
|| vflg
)) {
367 gettext("%s: Cannot use -p and -v with arguments\n"), myname
);
372 /* if only reporting mnttab, generic prints mnttab and exits */
373 if (!aflg
&& optind
== argc
) {
375 printf("%s", myname
);
384 print_mnttab(vflg
, pflg
);
389 * Get filesystem type here. If "-F FStype" is specified, use
390 * that fs type. Otherwise, determine the fs type from /etc/vfstab
391 * if the entry exists. Otherwise, determine the local or remote
392 * fs type from /etc/default/df or /etc/dfs/fstypes respectively.
395 if ((strcmp(farg
, "S51K") != 0) &&
396 (strcmp(farg
, "S52K") != 0)) {
401 } else /* if (Fflg) */
404 fscnt
= argc
- optind
;
405 if (aflg
&& (fscnt
!= 1))
406 exit(parmount(argv
+ optind
, fscnt
, fstype
));
409 * Then don't bother with the parallel over head. Everything
410 * from this point is simple/normal single execution.
414 /* get special and/or mount-point from arg(s) */
416 special
= argv
[optind
++];
420 mountp
= argv
[optind
++];
424 /* lookup only if we need to */
425 if (fstype
== NULL
|| specific_opts
== NULL
|| special
== NULL
||
427 if ((fd
= fopen(vfstab
, "r")) == NULL
) {
428 if (fstype
== NULL
|| special
== NULL
||
430 fprintf(stderr
, gettext(
431 "%s: Cannot open %s\n"),
436 * No vfstab, but we know what we want
443 vref
.vfs_special
= special
;
444 vref
.vfs_mountp
= mountp
;
445 vref
.vfs_fstype
= fstype
;
447 /* get a vfstab entry matching mountp or special */
448 while ((ret
= getvfsany(fd
, &vget
, &vref
)) > 0)
449 vfserror(ret
, vget
.vfs_special
);
451 /* if no entry and there was only one argument */
452 /* then the argument could be the special */
453 /* and not mount point as we thought earlier */
454 if (ret
== -1 && special
== NULL
) {
456 special
= vref
.vfs_special
= mountp
;
457 mountp
= vref
.vfs_mountp
= NULL
;
458 /* skip erroneous lines; they were reported above */
459 while ((ret
= getvfsany(fd
, &vget
, &vref
)) > 0)
467 fstype
= vget
.vfs_fstype
;
469 special
= vget
.vfs_special
;
471 mountp
= vget
.vfs_mountp
;
472 if (oflg
== 0 && vget
.vfs_mntopts
) {
474 specific_opts
= vget
.vfs_mntopts
;
476 } else if (special
== NULL
) {
477 if (stat64(mountp
, &stbuf
) == -1) {
478 fprintf(stderr
, gettext("%s: cannot stat %s\n"),
482 if (((mode
= (stbuf
.st_mode
& S_IFMT
)) == S_IFBLK
) ||
485 gettext("%s: mount point cannot be determined\n"),
491 gettext("%s: special cannot be determined\n"),
495 } else if (fstype
== NULL
)
496 fstype
= default_fstype(special
);
500 if (realpath(mountp
, realdir
) == NULL
) {
501 (void) fprintf(stderr
, "mount: ");
506 if ((mountp
= strdup(realdir
)) == NULL
)
509 if (check_fields(fstype
, mountp
))
512 /* create the new arg list, and end the list with a null pointer */
515 newargv
[ii
++] = "-c";
517 newargv
[ii
++] = "-m";
519 * The q option needs to go before the -o option as some
520 * filesystems complain during first pass option parsing.
523 newargv
[ii
++] = "-q";
525 newargv
[ii
++] = "-o";
526 newargv
[ii
++] = specific_opts
;
529 newargv
[ii
++] = "-O";
531 newargv
[ii
++] = "-r";
533 newargv
[ii
++] = "--";
534 newargv
[ii
++] = special
;
535 newargv
[ii
++] = mountp
;
538 doexec(fstype
, newargv
);
545 fprintf(stderr
, gettext("Usage:\n%s [-v | -p]\n"), myname
);
546 fprintf(stderr
, gettext(
547 "%s [-F FSType] [-V] [current_options] [-o specific_options]"),
549 fprintf(stderr
, gettext("\n\t{special | mount_point}\n"));
551 fprintf(stderr
, gettext(
552 "%s [-F FSType] [-V] [current_options] [-o specific_options]"),
554 fprintf(stderr
, gettext("\n\tspecial mount_point\n"));
556 fprintf(stderr
, gettext(
557 "%s -a [-F FSType ] [-V] [current_options] [-o specific_options]\n"),
559 fprintf(stderr
, gettext("\t[mount_point ...]\n"));
565 * Get rid of "dev=[hex string]" clause, if any. It's not legal
566 * when printing in vfstab format.
569 elide_dev(char *mntopts
)
573 if (mntopts
!= NULL
) {
574 dev
= strstr(mntopts
, "dev=");
576 other
= strpbrk(dev
, ",");
579 if (dev
!= mntopts
) {
585 /* first or intermediate option */
586 memmove(dev
, other
+1, strlen(other
+1)+1);
593 print_mnttab(int vflg
, int pflg
)
596 FILE *rfp
; /* this will be NULL if fopen fails */
598 char time_buf
[TIME_MAX
]; /* array to hold date and time */
599 struct extmnttab mget
;
602 if ((fd
= fopen(mnttab
, "r")) == NULL
) {
603 fprintf(stderr
, gettext("%s: Cannot open mnttab\n"), myname
);
606 rfp
= fopen(REMOTE
, "r");
607 while ((ret
= getextmntent(fd
, &mget
, sizeof (struct extmnttab
)))
609 if (ignore(mget
.mnt_mntopts
))
611 if (mget
.mnt_special
&& mget
.mnt_mountp
&&
612 mget
.mnt_fstype
&& mget
.mnt_time
) {
613 ltime
= atol(mget
.mnt_time
);
614 cftime(time_buf
, FORMAT
, <ime
);
616 elide_dev(mget
.mnt_mntopts
);
617 printf("%s - %s %s - no %s\n",
621 mget
.mnt_mntopts
!= NULL
?
622 mget
.mnt_mntopts
: "-");
624 printf("%s on %s type %s %s%s on %s",
628 remote(mget
.mnt_fstype
, rfp
),
629 flags(mget
.mnt_mntopts
, NEW
),
632 printf("%s on %s %s%s on %s",
635 remote(mget
.mnt_fstype
, rfp
),
636 flags(mget
.mnt_mntopts
, OLD
),
645 flags(char *mntopts
, int flag
)
647 char opts
[sizeof (mntflags
)];
654 if (mntopts
== NULL
|| *mntopts
== '\0')
655 return ("read/write/setuid/devices");
658 while (*mntopts
!= '\0') {
659 switch (getsubopt(&mntopts
, myopts
, &value
)) {
685 /* cat '/' separator to mntflags */
686 if (*opts
!= '\0' && value
!= NULL
)
693 strcpy(mntflags
, "");
695 strcat(mntflags
, "read/write");
696 else if (flag
== OLD
)
697 strcat(mntflags
, "read only");
699 strcat(mntflags
, "read-only");
702 strcat(mntflags
, "/setuid");
704 strcat(mntflags
, "/nosetuid");
706 strcat(mntflags
, "/devices");
708 strcat(mntflags
, "/nodevices");
710 strcat(mntflags
, "/nosetuid/nodevices");
713 strcat(mntflags
, "/");
714 strcat(mntflags
, opts
);
718 * The assumed assertion
719 * assert (strlen(mntflags) < sizeof mntflags);
720 * is valid at this point in the code. Note that a call to "assert"
721 * is not appropriate in production code since it halts the program.
727 remote(char *fstype
, FILE *rfp
)
731 extern char *strtok();
733 if (rfp
== NULL
|| fstype
== NULL
||
734 strlen(fstype
) > (size_t)FSTYPE_MAX
)
735 return (""); /* not a remote */
737 while (fgets(buf
, sizeof (buf
), rfp
) != NULL
) {
738 fs
= strtok(buf
, " \t\n");
739 if (strcmp(fstype
, fs
) == 0)
740 return ("remote/"); /* is a remote fs */
742 return (""); /* not a remote */
747 vfserror(int flag
, char *special
)
754 gettext("%s: Warning: Line in vfstab for \"%s\" exceeds %d characters\n"),
755 myname
, special
, VFS_LINE_MAX
-1);
759 gettext("%s: Warning: Line for \"%s\" in vfstab has too few entries\n"),
764 gettext("%s: Warning: Line for \"%s\" in vfstab has too many entries\n"),
768 fprintf(stderr
, gettext(
769 "%s: Warning: Error in line for \"%s\" in vfstab\n"),
780 gettext("%s: Line in mnttab exceeds %d characters\n"),
781 myname
, MNT_LINE_MAX
-2);
785 gettext("%s: Line in mnttab has too few entries\n"),
790 gettext("%s: Line in mnttab has too many entries\n"),
798 doexec(char *fstype
, char *newargv
[])
800 char full_path
[PATH_MAX
];
801 char alter_path
[PATH_MAX
];
802 char *vfs_path
= VFS_PATH
;
803 char *alt_path
= ALT_PATH
;
806 /* build the full pathname of the fstype dependent command. */
807 sprintf(full_path
, "%s/%s/%s", vfs_path
, fstype
, myname
);
808 sprintf(alter_path
, "%s/%s/%s", alt_path
, fstype
, myname
);
812 printf("%s -F %s", newargv
[1], fstype
);
813 for (i
= 2; newargv
[i
]; i
++)
814 printf(" %s", newargv
[i
]);
821 * Try to exec the fstype dependent portion of the mount.
822 * See if the directory is there before trying to exec dependent
823 * portion. This is only useful for eliminating the
824 * '..mount: not found' message when '/usr' is mounted
826 if (access(full_path
, 0) == 0) {
827 execv(full_path
, &newargv
[1]);
828 if (errno
== EACCES
) {
830 gettext("%s: Cannot execute %s - permission denied\n"),
833 if (errno
== ENOEXEC
) {
835 newargv
[1] = full_path
;
836 execv("/sbin/sh", &newargv
[0]);
839 execv(alter_path
, &newargv
[1]);
840 if (errno
== EACCES
) {
841 fprintf(stderr
, gettext(
842 "%s: Cannot execute %s - permission denied\n"),
846 if (errno
== ENOEXEC
) {
848 newargv
[1] = alter_path
;
849 execv("/sbin/sh", &newargv
[0]);
852 gettext("%s: Operation not applicable to FSType %s\n"),
857 char *mntopts
[] = { MNTOPT_IGNORE
, NULL
};
861 * Return 1 if "ignore" appears in the options string
867 char *saveptr
, *my_opts
;
870 if (opts
== NULL
|| *opts
== '\0')
874 * we make a copy of the option string to pass to getsubopt(),
875 * because getsubopt() modifies the string. We also save
876 * the original pointer returned by strdup, because getsubopt
877 * changes the pointer passed into it. If strdup fails (unlikely),
878 * we act as if the "ignore" option isn't set rather than fail.
881 if ((saveptr
= my_opts
= strdup(opts
)) == NULL
)
884 while (*my_opts
!= '\0') {
885 if (getsubopt(&my_opts
, mntopts
, &value
) == IGNORE
)
895 * Perform the parallel version of mount. If count == 0, mount all
896 * vfstab filesystems with the automnt field == "yes". Use fstype if
897 * supplied. If mntlist supplied, then attempt to only mount those.
901 parmount(char **mntlist
, int count
, char *fstype
)
903 int maxfd
= OPEN_MAX
;
908 * Process scaling. After running a series
909 * of tests based on the number of simultaneous processes and
910 * processors available, optimum performance was achieved near or
913 if ((maxrun
= sysconf(_SC_NPROCESSORS_ONLN
)) == -1)
916 maxrun
= maxrun
* 2 + 1;
918 if (getrlimit(RLIMIT_NOFILE
, &rl
) == 0) {
919 rl
.rlim_cur
= rl
.rlim_max
;
920 if (setrlimit(RLIMIT_NOFILE
, &rl
) == 0)
921 maxfd
= (int)rl
.rlim_cur
;
923 (void) enable_extended_FILE_stdio(-1, -1);
926 * The parent needs to maintain 3 of its own fd's, plus 2 for
927 * each child (the stdout and stderr pipes).
929 maxfd
= (maxfd
/ 2) - 6; /* 6 takes care of temporary */
930 /* periods of open fds */
934 maxrun
= 4; /* sanity check */
937 mntlist
= NULL
; /* used as a flag later */
939 fstype
= NULL
; /* mount points supplied: */
942 * Read the whole vfstab into a linked list for quick processing.
943 * On average, this is the most efficient way to collect and
944 * manipulate the vfstab data.
946 vfsll
= getvfsall(fstype
, mntlist
== NULL
);
949 * Make an array out of the vfs linked list for sorting purposes.
952 (vfsarray
= make_vfsarray(mntlist
, count
)) == NULL
) {
953 if (mntlist
== NULL
) /* not an error - just none found */
956 fprintf(stderr
, gettext("%s: No valid entries found in %s\n"),
962 * Sort the entries based on their resolved path names
964 * If an lofs is encountered, then the original order of the vfstab
965 * file needs to be maintained until we are done mounting lofs's.
968 qsort((void *)vfsarray
, vfsarraysize
, sizeof (vfsent_t
*),
972 * Shrink the vfsll linked list down to the new list. This will
973 * speed up the pid search in cleanupkid() later.
976 for (vl
= vfsarray
; vp
= *vl
; )
980 * Try to handle interrupts in a reasonable way.
982 sigset(SIGHUP
, cleanup
);
983 sigset(SIGQUIT
, cleanup
);
984 sigset(SIGINT
, cleanup
);
986 do_mounts(); /* do the mounts */
988 if (failcnt
> 0 && failcnt
== lofsfail
)
989 return (ALL_LOFS_FAILURES
);
995 * Read all vstab (fp) entries into memory if fstype == NULL.
996 * If fstype is specified, than read all those that match it.
998 * Returns a linked list.
1001 getvfsall(char *fstype
, int takeall
)
1003 vfsent_t
*vhead
, *vtail
;
1008 if ((fp
= fopen(vfstab
, "r")) == NULL
) {
1009 fprintf(stderr
, gettext("%s: Cannot open %s\n"),
1014 vhead
= vtail
= NULL
;
1016 while ((ret
= getvfsent(fp
, &vget
)) != -1) {
1020 vfserror(ret
, vget
.vfs_mountp
);
1025 * If mount points were not specified, then we ignore
1026 * entries that aren't marked "yes".
1029 (vget
.vfs_automnt
== NULL
||
1030 strcmp(vget
.vfs_automnt
, "yes")))
1033 if (fstype
&& vget
.vfs_fstype
&&
1034 strcmp(fstype
, vget
.vfs_fstype
))
1037 if (vget
.vfs_mountp
== NULL
||
1038 (vget
.vfs_fstype
&& (strcmp(vget
.vfs_fstype
, "swap") == 0)))
1041 if (check_fields(vget
.vfs_fstype
, vget
.vfs_mountp
)) {
1046 vp
= new_vfsent(&vget
, cnt
); /* create new vfs entry */
1055 if (vtail
== NULL
) {
1061 vfslltail
= vtail
; /* save it in the global variable */
1068 * Returns an array of vfsent_t's based on vfsll & mntlist.
1071 make_vfsarray(char **mntlist
, int count
)
1073 vfsent_t
*vp
, *vmark
, *vpprev
, **vpp
;
1080 vfsarraysize
= count
;
1082 vpp
= (vfsent_t
**)malloc(sizeof (*vpp
) * (vfsarraysize
+ 1));
1086 if (mntlist
== NULL
) {
1088 * No mount list specified: take all vfstab mount points.
1090 for (ndx
= 0, vp
= vfsll
; vp
; vp
= vp
->next
) {
1091 (void) setrpath(vp
);
1093 * Sigh. lofs entries can complicate matters so much
1094 * that the best way to avoid problems is to
1095 * stop parallel mounting when an lofs is
1096 * encountered, so we keep a count of how many
1098 * Fortunately this is rare.
1100 if (vp
->v
.vfs_fstype
&&
1101 (strcmp(vp
->v
.vfs_fstype
, MNTTYPE_LOFS
) == 0))
1111 * A list of mount points was specified on the command line
1112 * and we need to search for each one.
1115 vpprev
->next
= vfsll
; /* make a circle out of it */
1118 * For each specified mount point:
1120 for (ndx
= 0; *mntlist
; mntlist
++) {
1123 * Circle our entire linked list, looking for *mntlist.
1126 if (strcmp(*mntlist
, vp
->v
.vfs_mountp
) == 0) {
1127 vpp
[ndx
++] = vp
; /* found it. */
1128 (void) setrpath(vp
);
1129 if (vp
->v
.vfs_fstype
&&
1130 (strcmp(vp
->v
.vfs_fstype
,
1131 MNTTYPE_LOFS
) == 0))
1134 if (vp
== vpprev
) { /* list exhausted */
1140 * Remove it from the circular list. vpprev
1141 * remains unchanged.
1144 vpprev
->next
->next
= NULL
;
1147 * Set vmark to the first elem that we check
1156 if (vp
== vmark
) /* break out if we completed */
1162 fprintf(stderr
, gettext(
1163 "%s: Warning: %s not found in %s\n"),
1164 myname
, *mntlist
, vfstab
);
1171 vpp
[ndx
] = NULL
; /* null terminate the list */
1172 vfsarraysize
= ndx
; /* adjust vfsarraysize */
1177 * Performs the exec argument processing, all of the child forking and
1178 * execing, and child cleanup.
1179 * Sets exitcode to non-zero if any errors occurred.
1185 vfsent_t
*vp
, *vpprev
, **vl
;
1186 char *newargv
[ARGV_MAX
];
1190 * create the arg list once; the only differences among
1191 * the calls are the options, special and mountp fields.
1195 newargv
[i
++] = "-c";
1197 newargv
[i
++] = "-m";
1199 newargv
[i
++] = "-O";
1201 newargv
[i
++] = "-q";
1203 newargv
[i
++] = "-r";
1205 newargv
[i
++] = "--";
1207 newargv
[i
++] = "-o";
1208 newargv
[i
++] = specific_opts
;
1213 * Main loop for the mount processes
1217 for (vpprev
= *vl
; vp
= *vl
; vpprev
= vp
, vl
++, cnt
--) {
1219 * Check to see if we cross a mount level: e.g.,
1220 * /a/b -> /a/b/c. If so, we need to wait for all current
1221 * mounts to finish, rerun realpath on the remaining mount
1222 * points, and resort the list.
1224 * Also, we mount serially as long as there are lofs's
1225 * to mount to avoid improper mount ordering.
1227 if (vp
->mlevel
> vpprev
->mlevel
|| lofscnt
> 0) {
1230 while (nrun
> 0 && (dowait() != -1))
1233 * Gads! It's possible for real path mounts points to
1234 * change after mounts are done at a lower mount
1236 * Thus, we need to recalculate mount levels and
1237 * resort the list from this point.
1239 for (vlp
= vl
; *vlp
; vlp
++)
1240 (void) setrpath(*vlp
);
1242 * Sort the remaining entries based on their newly
1243 * resolved path names.
1244 * Do not sort if we still have lofs's to mount.
1247 qsort((void *)vl
, cnt
, sizeof (vfsent_t
*),
1253 if (vp
->flag
& VRPFAILED
) {
1254 fprintf(stderr
, gettext(
1255 "%s: Nonexistent mount point: %s\n"),
1256 myname
, vp
->v
.vfs_mountp
);
1257 vp
->flag
|= VNOTMOUNTED
;
1263 * If mount options were not specified on the command
1264 * line, then use the ones found in the vfstab entry,
1268 if (!oflg
&& vp
->v
.vfs_mntopts
) {
1269 newargv
[i
++] = "-o";
1270 newargv
[i
++] = vp
->v
.vfs_mntopts
;
1272 newargv
[i
++] = vp
->v
.vfs_special
;
1273 newargv
[i
++] = vp
->rpath
;
1277 * This should never really fail.
1279 while (setup_iopipe(vp
) == -1 && (dowait() != -1))
1282 while (nrun
>= maxrun
&& (dowait() != -1)) /* throttle */
1285 if ((child
= fork()) == -1) {
1290 if (child
== 0) { /* child */
1291 signal(SIGHUP
, SIG_IGN
);
1292 signal(SIGQUIT
, SIG_IGN
);
1293 signal(SIGINT
, SIG_IGN
);
1295 doexec(vp
->v
.vfs_fstype
, newargv
);
1301 (void) close(vp
->sopipe
[WRPIPE
]);
1302 (void) close(vp
->sepipe
[WRPIPE
]);
1307 * Mostly done by now - wait and clean up the stragglers.
1314 * Setup stdout and stderr pipes for the children's output.
1317 setup_iopipe(vfsent_t
*mp
)
1320 * Make a stdout and stderr pipe. This should never fail.
1322 if (pipe(mp
->sopipe
) == -1)
1324 if (pipe(mp
->sepipe
) == -1) {
1325 (void) close(mp
->sopipe
[RDPIPE
]);
1326 (void) close(mp
->sopipe
[WRPIPE
]);
1330 * Don't block on an empty pipe.
1332 (void) fcntl(mp
->sopipe
[RDPIPE
], F_SETFL
, O_NDELAY
|O_NONBLOCK
);
1333 (void) fcntl(mp
->sepipe
[RDPIPE
], F_SETFL
, O_NDELAY
|O_NONBLOCK
);
1335 * Don't pass extra fds into children.
1337 (void) fcntl(mp
->sopipe
[RDPIPE
], F_SETFD
, FD_CLOEXEC
);
1338 (void) fcntl(mp
->sepipe
[RDPIPE
], F_SETFD
, FD_CLOEXEC
);
1344 * Called by a child to attach its stdout and stderr to the write side of
1348 setup_output(vfsent_t
*vp
)
1351 (void) close(fileno(stdout
));
1352 (void) dup(vp
->sopipe
[WRPIPE
]);
1353 (void) close(vp
->sopipe
[WRPIPE
]);
1355 (void) close(fileno(stderr
));
1356 (void) dup(vp
->sepipe
[WRPIPE
]);
1357 (void) close(vp
->sepipe
[WRPIPE
]);
1361 * Parent uses this to print any stdout or stderr output issued by
1370 while ((bytes
= read(vp
->sepipe
[RDPIPE
], ibuf
, sizeof (ibuf
))) > 0)
1371 write(fileno(stderr
), ibuf
, bytes
);
1372 while ((bytes
= read(vp
->sopipe
[RDPIPE
], ibuf
, sizeof (ibuf
))) > 0)
1373 write(fileno(stdout
), ibuf
, bytes
);
1375 (void) close(vp
->sopipe
[RDPIPE
]);
1376 (void) close(vp
->sepipe
[RDPIPE
]);
1380 * Waits for 1 child to die.
1382 * Returns -1 if no children are left to wait for.
1383 * Returns 0 if a child died without an error.
1384 * Returns 1 if a child died with an error.
1391 if ((child
= wait(&wstat
)) == -1)
1394 return (cleanupkid(child
, wstat
) != 0);
1398 * Locates the child mount process represented by pid, outputs any io
1399 * it may have, and returns its exit code.
1400 * Sets the global exitcode if an error occurred.
1403 cleanupkid(pid_t pid
, int wstat
)
1405 vfsent_t
*vp
, *prevp
;
1408 if (WIFEXITED(wstat
)) /* this should always be true */
1409 ret
= WEXITSTATUS(wstat
);
1411 ret
= 1; /* assume some kind of error */
1419 * This search gets smaller and smaller as children are cleaned
1422 for (prevp
= NULL
, vp
= vfsll
; vp
; vp
= vp
->next
) {
1423 if (vp
->pid
!= pid
) {
1428 * Found: let's remove it from this linked list.
1431 prevp
->next
= vp
->next
;
1439 * This should never happen.
1441 fprintf(stderr
, gettext(
1442 "%s: Unknown child %d\n"), myname
, pid
);
1446 doio(vp
); /* Any output? */
1448 if (vp
->v
.vfs_fstype
&&
1449 (strcmp(vp
->v
.vfs_fstype
, MNTTYPE_LOFS
) == 0)) {
1460 static vfsent_t zvmount
= { 0 };
1463 new_vfsent(struct vfstab
*vin
, int order
)
1467 new = (vfsent_t
*)malloc(sizeof (*new));
1472 if (vin
->vfs_special
&&
1473 (new->v
.vfs_special
= strdup(vin
->vfs_special
)) == NULL
)
1475 if (vin
->vfs_mountp
&&
1476 (new->v
.vfs_mountp
= strdup(vin
->vfs_mountp
)) == NULL
)
1478 if (vin
->vfs_fstype
&&
1479 (new->v
.vfs_fstype
= strdup(vin
->vfs_fstype
)) == NULL
)
1482 * If specific mount options were specified on the command
1483 * line, then use those. Else, use the ones on the vfstab
1484 * line, if any. In other words, specific options on the
1485 * command line override those in /etc/vfstab.
1488 if ((new->v
.vfs_mntopts
= strdup(specific_opts
)) == NULL
)
1490 } else if (vin
->vfs_mntopts
&&
1491 (new->v
.vfs_mntopts
= strdup(vin
->vfs_mntopts
)) == NULL
)
1499 * Runs realpath on vp's mount point, records success or failure,
1500 * resets the mount level based on the new realpath, and returns
1501 * realpath()'s return value.
1504 setrpath(vfsent_t
*vp
)
1508 if ((rp
= realpath(vp
->v
.vfs_mountp
, realdir
)) == NULL
)
1509 vp
->flag
|= VRPFAILED
;
1511 vp
->flag
&= ~VRPFAILED
;
1514 if ((vp
->rpath
= strdup(realdir
)) == NULL
)
1516 vp
->mlevel
= fsgetmlevel(vp
->rpath
);
1522 * sort first by mlevel (1...N), then by vfstab order.
1525 mlevelcmp(const void *a
, const void *b
)
1530 a1
= *(vfsent_t
**)a
;
1531 b1
= *(vfsent_t
**)b
;
1533 lcmp
= a1
->mlevel
- b1
->mlevel
;
1535 lcmp
= a1
->order
- b1
->order
;
1539 /* sort by vfstab order. 0..N */
1541 mordercmp(const void *a
, const void *b
)
1545 a1
= *(vfsent_t
**)a
;
1546 b1
= *(vfsent_t
**)b
;
1547 return (a1
->order
- b1
->order
);
1551 * cleanup the existing children and exit with an error
1557 while (nrun
> 0 && (dowait() != -1))
1566 check_fields(char *fstype
, char *mountp
)
1568 struct stat64 stbuf
;
1570 if (fstype
== NULL
) {
1572 gettext("%s: FSType cannot be determined\n"),
1576 if (strlen(fstype
) > (size_t)FSTYPE_MAX
) {
1578 gettext("%s: FSType %s exceeds %d characters\n"),
1579 myname
, fstype
, FSTYPE_MAX
);
1583 if (mountp
== NULL
) {
1585 gettext("%s: Mount point cannot be determined\n"),
1589 if (*mountp
!= '/') {
1590 fprintf(stderr
, gettext(
1591 "%s: Mount point %s is not an absolute pathname.\n"),
1596 * Don't do some of these checks if aflg because a mount point may
1597 * not exist now, but will be mounted before we get to it.
1598 * This is one of the quirks of "secondary mounting".
1600 if (!aflg
&& stat64(mountp
, &stbuf
) < 0) {
1601 if (errno
== ENOENT
|| errno
== ENOTDIR
)
1603 gettext("%s: Mount point %s does not exist.\n"),
1607 gettext("%s: Cannot stat mount point %s.\n"),
1619 fprintf(stderr
, gettext("%s: Out of memory\n"), myname
);
1620 while (nrun
> 0 && (dowait() != -1))