#include <stdio.h>
#include <stdio_ext.h>
#include <limits.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/statvfs.h>
#include <errno.h>
#include <sys/mnttab.h>
#include <sys/mntent.h>
#include <sys/mount.h>
#include <sys/vfstab.h>
#include <sys/param.h>
#include <sys/wait.h>
#include <sys/signal.h>
#include <sys/resource.h>
#include <stropts.h>
#include <sys/conf.h>
#include <locale.h>
#include <priv.h>
#include "fslib.h"
#define VFS_PATH "/usr/lib/fs"
#define ALT_PATH "/etc/fs"
#define REMOTE "/etc/dfs/fstypes"
#define ARGV_MAX 16
#define TIME_MAX 50
#define FSTYPE_MAX 8
#define REMOTE_MAX 64
#define OLD 0
#define NEW 1
#define READONLY 0
#define READWRITE 1
#define SUID 2
#define NOSUID 3
#define SETUID 4
#define NOSETUID 5
#define DEVICES 6
#define NODEVICES 7
#define FORMAT "%a %b %e %H:%M:%S %Y\n"
#define ALL_LOFS_FAILURES 111
extern int optind;
extern char *optarg;
extern void usage(void);
extern char *flags(char *, int);
extern char *remote(char *, FILE *);
extern char *default_fstype(char *);
char *myopts[] = {
MNTOPT_RO,
MNTOPT_RW,
MNTOPT_SUID,
MNTOPT_NOSUID,
MNTOPT_SETUID,
MNTOPT_NOSETUID,
MNTOPT_DEVICES,
MNTOPT_NODEVICES,
NULL
};
static char *myname;
char mntflags[(_POSIX_MAX_INPUT+1) * 2];
char realdir[MAXPATHLEN];
char *vfstab = VFSTAB;
char *mnttab = MNTTAB;
char *specific_opts;
char *generic_opts;
int maxrun;
int nrun;
int failcnt;
int lofscnt;
int lofsfail;
int exitcode;
int aflg, cflg, fflg, Fflg, gflg, oflg, pflg, rflg, vflg, Vflg, mflg, Oflg,
dashflg, questflg, dflg, qflg;
typedef struct vfsent {
struct vfstab v;
char *rpath;
int mlevel;
int order;
int flag;
pid_t pid;
int exitcode;
#define RDPIPE 0
#define WRPIPE 1
int sopipe[2];
int sepipe[2];
struct vfsent *next;
} vfsent_t;
#define VRPFAILED 0x01
#define VNOTMOUNTED 0x02
vfsent_t *vfsll, *vfslltail;
vfsent_t **vfsarray;
int vfsarraysize;
typedef struct mountent {
struct extmnttab *ment;
int flag;
struct mountent *next;
} mountent_t;
#define MSORTED 0x1
static vfsent_t **make_vfsarray(char **, int);
static vfsent_t *new_vfsent(struct vfstab *, int);
static vfsent_t *getvfsall(char *, int);
static void doexec(char *, char **);
static void nomem();
static void cleanup(int);
static char *setrpath(vfsent_t *);
static int dowait();
static int setup_iopipe(vfsent_t *);
static void setup_output(vfsent_t *);
static void doio(vfsent_t *);
static void do_mounts();
static int parmount(char **, int, char *);
static int mlevelcmp(const void *, const void *);
static int mordercmp(const void *, const void *);
static int check_fields(char *, char *);
static int cleanupkid(pid_t, int);
static void print_mnttab(int, int);
static void vfserror(int, char *);
static void mnterror(int);
static int ignore(char *);
int
main(int argc, char *argv[])
{
char *special,
*mountp,
*fstype,
*newargv[ARGV_MAX],
*farg = NULL, *Farg = NULL;
int ii, ret, cc, fscnt;
struct stat64 stbuf;
struct vfstab vget, vref;
mode_t mode;
FILE *fd;
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
myname = strrchr(argv[0], '/');
if (myname)
myname++;
else
myname = argv[0];
if (myname == 0) myname = "path unknown";
while ((cc = getopt(argc, argv, "?acd:f:F:gmno:pqrvVO")) != -1)
switch (cc) {
case 'a':
aflg++;
break;
case 'c':
cflg++;
break;
#ifdef DEBUG
case 'd':
dflg = atoi(optarg);
break;
#endif
case 'f':
fflg++;
farg = optarg;
break;
case 'F':
Fflg++;
Farg = optarg;
break;
case 'g':
gflg++;
break;
case 'm':
mflg++;
break;
case 'o':
oflg++;
if ((specific_opts = strdup(optarg)) == NULL)
nomem();
break;
case 'O':
Oflg++;
break;
case 'p':
pflg++;
break;
case 'q':
qflg++;
break;
case 'r':
rflg++;
generic_opts = "ro";
break;
case 'v':
vflg++;
break;
case 'V':
Vflg++;
break;
case '?':
questflg++;
break;
}
if (strcmp(argv[optind-1], "--") == 0)
dashflg++;
if (!aflg && (argc - optind > 2))
usage();
if (pflg + vflg + aflg > 1) {
fprintf(stderr, gettext
("%s: -a, -p, and -v are mutually exclusive\n"),
myname);
usage();
}
if (aflg && Oflg) {
fprintf(stderr, gettext
("%s: -a and -O are mutually exclusive\n"), myname);
usage();
}
if (fflg + Fflg > 1) {
fprintf(stderr, gettext
("%s: More than one FSType specified\n"), myname);
usage();
}
if (!aflg && optind == argc) {
if (cflg || fflg || mflg || oflg || rflg || qflg)
usage();
if (Fflg && !questflg)
usage();
if (questflg) {
if (Fflg) {
newargv[2] = "-?";
newargv[3] = NULL;
doexec(Farg, newargv);
}
usage();
}
}
if (questflg)
usage();
if (optind != argc && (pflg || vflg)) {
fprintf(stderr,
gettext("%s: Cannot use -p and -v with arguments\n"), myname);
usage();
}
if (!aflg && optind == argc) {
if (Vflg) {
printf("%s", myname);
if (pflg)
printf(" -p");
if (vflg)
printf(" -v");
printf("\n");
exit(0);
}
print_mnttab(vflg, pflg);
exit(0);
}
if (fflg) {
if ((strcmp(farg, "S51K") != 0) &&
(strcmp(farg, "S52K") != 0)) {
fstype = farg;
}
else
fstype = "ufs";
} else
fstype = Farg;
fscnt = argc - optind;
if (aflg && (fscnt != 1))
exit(parmount(argv + optind, fscnt, fstype));
aflg = 0;
if (fscnt == 2)
special = argv[optind++];
else
special = NULL;
if (optind < argc)
mountp = argv[optind++];
else
mountp = NULL;
if (fstype == NULL || specific_opts == NULL || special == NULL ||
mountp == NULL) {
if ((fd = fopen(vfstab, "r")) == NULL) {
if (fstype == NULL || special == NULL ||
mountp == NULL) {
fprintf(stderr, gettext(
"%s: Cannot open %s\n"),
myname, vfstab);
exit(1);
} else {
goto out;
}
}
vfsnull(&vref);
vref.vfs_special = special;
vref.vfs_mountp = mountp;
vref.vfs_fstype = fstype;
while ((ret = getvfsany(fd, &vget, &vref)) > 0)
vfserror(ret, vget.vfs_special);
if (ret == -1 && special == NULL) {
rewind(fd);
special = vref.vfs_special = mountp;
mountp = vref.vfs_mountp = NULL;
while ((ret = getvfsany(fd, &vget, &vref)) > 0)
;
}
fclose(fd);
if (ret == 0) {
if (fstype == NULL)
fstype = vget.vfs_fstype;
if (special == NULL)
special = vget.vfs_special;
if (mountp == NULL)
mountp = vget.vfs_mountp;
if (oflg == 0 && vget.vfs_mntopts) {
oflg++;
specific_opts = vget.vfs_mntopts;
}
} else if (special == NULL) {
if (stat64(mountp, &stbuf) == -1) {
fprintf(stderr, gettext("%s: cannot stat %s\n"),
myname, mountp);
exit(2);
}
if (((mode = (stbuf.st_mode & S_IFMT)) == S_IFBLK) ||
(mode == S_IFCHR)) {
fprintf(stderr,
gettext("%s: mount point cannot be determined\n"),
myname);
exit(1);
} else
{
fprintf(stderr,
gettext("%s: special cannot be determined\n"),
myname);
exit(1);
}
} else if (fstype == NULL)
fstype = default_fstype(special);
}
out:
if (realpath(mountp, realdir) == NULL) {
(void) fprintf(stderr, "mount: ");
perror(mountp);
exit(1);
}
if ((mountp = strdup(realdir)) == NULL)
nomem();
if (check_fields(fstype, mountp))
exit(1);
ii = 2;
if (cflg)
newargv[ii++] = "-c";
if (gflg)
newargv[ii++] = "-g";
if (mflg)
newargv[ii++] = "-m";
if (qflg)
newargv[ii++] = "-q";
if (oflg) {
newargv[ii++] = "-o";
newargv[ii++] = specific_opts;
}
if (Oflg)
newargv[ii++] = "-O";
if (rflg)
newargv[ii++] = "-r";
if (dashflg)
newargv[ii++] = "--";
newargv[ii++] = special;
newargv[ii++] = mountp;
newargv[ii] = NULL;
doexec(fstype, newargv);
return (0);
}
void
usage(void)
{
fprintf(stderr, gettext("Usage:\n%s [-v | -p]\n"), myname);
fprintf(stderr, gettext(
"%s [-F FSType] [-V] [current_options] [-o specific_options]"),
myname);
fprintf(stderr, gettext("\n\t{special | mount_point}\n"));
fprintf(stderr, gettext(
"%s [-F FSType] [-V] [current_options] [-o specific_options]"),
myname);
fprintf(stderr, gettext("\n\tspecial mount_point\n"));
fprintf(stderr, gettext(
"%s -a [-F FSType ] [-V] [current_options] [-o specific_options]\n"),
myname);
fprintf(stderr, gettext("\t[mount_point ...]\n"));
exit(1);
}
void
elide_dev(char *mntopts)
{
char *dev, *other;
if (mntopts != NULL) {
dev = strstr(mntopts, "dev=");
if (dev != NULL) {
other = strpbrk(dev, ",");
if (other == NULL) {
if (dev != mntopts) {
*--dev = '\0';
} else {
*dev = '\0';
}
} else {
memmove(dev, other+1, strlen(other+1)+1);
}
}
}
}
void
print_mnttab(int vflg, int pflg)
{
FILE *fd;
FILE *rfp;
int ret;
char time_buf[TIME_MAX];
struct extmnttab mget;
time_t ltime;
if ((fd = fopen(mnttab, "r")) == NULL) {
fprintf(stderr, gettext("%s: Cannot open mnttab\n"), myname);
exit(1);
}
rfp = fopen(REMOTE, "r");
while ((ret = getextmntent(fd, &mget, sizeof (struct extmnttab)))
== 0) {
if (ignore(mget.mnt_mntopts))
continue;
if (mget.mnt_special && mget.mnt_mountp &&
mget.mnt_fstype && mget.mnt_time) {
ltime = atol(mget.mnt_time);
cftime(time_buf, FORMAT, <ime);
if (pflg) {
elide_dev(mget.mnt_mntopts);
printf("%s - %s %s - no %s\n",
mget.mnt_special,
mget.mnt_mountp,
mget.mnt_fstype,
mget.mnt_mntopts != NULL ?
mget.mnt_mntopts : "-");
} else if (vflg) {
printf("%s on %s type %s %s%s on %s",
mget.mnt_special,
mget.mnt_mountp,
mget.mnt_fstype,
remote(mget.mnt_fstype, rfp),
flags(mget.mnt_mntopts, NEW),
time_buf);
} else
printf("%s on %s %s%s on %s",
mget.mnt_mountp,
mget.mnt_special,
remote(mget.mnt_fstype, rfp),
flags(mget.mnt_mntopts, OLD),
time_buf);
}
}
if (ret > 0)
mnterror(ret);
}
char *
flags(char *mntopts, int flag)
{
char opts[sizeof (mntflags)];
char *value;
int rdwr = 1;
int suid = 1;
int devices = 1;
int setuid = 1;
if (mntopts == NULL || *mntopts == '\0')
return ("read/write/setuid/devices");
strcpy(opts, "");
while (*mntopts != '\0') {
switch (getsubopt(&mntopts, myopts, &value)) {
case READONLY:
rdwr = 0;
break;
case READWRITE:
rdwr = 1;
break;
case SUID:
suid = 1;
break;
case NOSUID:
suid = 0;
break;
case SETUID:
setuid = 1;
break;
case NOSETUID:
setuid = 0;
break;
case DEVICES:
devices = 1;
break;
case NODEVICES:
devices = 0;
break;
default:
if (*opts != '\0' && value != NULL)
strcat(opts, "/");
strcat(opts, value);
break;
}
}
strcpy(mntflags, "");
if (rdwr)
strcat(mntflags, "read/write");
else if (flag == OLD)
strcat(mntflags, "read only");
else
strcat(mntflags, "read-only");
if (suid) {
if (setuid)
strcat(mntflags, "/setuid");
else
strcat(mntflags, "/nosetuid");
if (devices)
strcat(mntflags, "/devices");
else
strcat(mntflags, "/nodevices");
} else {
strcat(mntflags, "/nosetuid/nodevices");
}
if (*opts != '\0') {
strcat(mntflags, "/");
strcat(mntflags, opts);
}
return (mntflags);
}
char *
remote(char *fstype, FILE *rfp)
{
char buf[BUFSIZ];
char *fs;
extern char *strtok();
if (rfp == NULL || fstype == NULL ||
strlen(fstype) > (size_t)FSTYPE_MAX)
return ("");
rewind(rfp);
while (fgets(buf, sizeof (buf), rfp) != NULL) {
fs = strtok(buf, " \t\n");
if (strcmp(fstype, fs) == 0)
return ("remote/");
}
return ("");
}
void
vfserror(int flag, char *special)
{
if (special == NULL)
special = "<null>";
switch (flag) {
case VFS_TOOLONG:
fprintf(stderr,
gettext("%s: Warning: Line in vfstab for \"%s\" exceeds %d characters\n"),
myname, special, VFS_LINE_MAX-1);
break;
case VFS_TOOFEW:
fprintf(stderr,
gettext("%s: Warning: Line for \"%s\" in vfstab has too few entries\n"),
myname, special);
break;
case VFS_TOOMANY:
fprintf(stderr,
gettext("%s: Warning: Line for \"%s\" in vfstab has too many entries\n"),
myname, special);
break;
default:
fprintf(stderr, gettext(
"%s: Warning: Error in line for \"%s\" in vfstab\n"),
myname, special);
}
}
void
mnterror(int flag)
{
switch (flag) {
case MNT_TOOLONG:
fprintf(stderr,
gettext("%s: Line in mnttab exceeds %d characters\n"),
myname, MNT_LINE_MAX-2);
break;
case MNT_TOOFEW:
fprintf(stderr,
gettext("%s: Line in mnttab has too few entries\n"),
myname);
break;
case MNT_TOOMANY:
fprintf(stderr,
gettext("%s: Line in mnttab has too many entries\n"),
myname);
break;
}
exit(1);
}
void
doexec(char *fstype, char *newargv[])
{
char full_path[PATH_MAX];
char alter_path[PATH_MAX];
char *vfs_path = VFS_PATH;
char *alt_path = ALT_PATH;
int i;
sprintf(full_path, "%s/%s/%s", vfs_path, fstype, myname);
sprintf(alter_path, "%s/%s/%s", alt_path, fstype, myname);
newargv[1] = myname;
if (Vflg) {
printf("%s -F %s", newargv[1], fstype);
for (i = 2; newargv[i]; i++)
printf(" %s", newargv[i]);
printf("\n");
fflush(stdout);
exit(0);
}
if (strcmp(fstype, "smbfs") == 0 &&
setpflags(PRIV_PFEXEC, 1) != 0) {
(void) fprintf(stderr,
gettext("mount: unable to set PFEXEC flag: %s\n"),
strerror(errno));
exit(1);
}
if (access(full_path, 0) == 0) {
execv(full_path, &newargv[1]);
if (errno == EACCES) {
fprintf(stderr,
gettext("%s: Cannot execute %s - permission denied\n"),
myname, full_path);
}
if (errno == ENOEXEC) {
newargv[0] = "sh";
newargv[1] = full_path;
execv("/sbin/sh", &newargv[0]);
}
}
execv(alter_path, &newargv[1]);
if (errno == EACCES) {
fprintf(stderr, gettext(
"%s: Cannot execute %s - permission denied\n"),
myname, alter_path);
exit(1);
}
if (errno == ENOEXEC) {
newargv[0] = "sh";
newargv[1] = alter_path;
execv("/sbin/sh", &newargv[0]);
}
fprintf(stderr,
gettext("%s: Operation not applicable to FSType %s\n"),
myname, fstype);
exit(1);
}
char *mntopts[] = { MNTOPT_IGNORE, NULL };
#define IGNORE 0
int
ignore(char *opts)
{
char *value;
char *saveptr, *my_opts;
int rval = 0;
if (opts == NULL || *opts == '\0')
return (0);
if ((saveptr = my_opts = strdup(opts)) == NULL)
nomem();
while (*my_opts != '\0') {
if (getsubopt(&my_opts, mntopts, &value) == IGNORE)
rval = 1;
}
free(saveptr);
return (rval);
}
int
parmount(char **mntlist, int count, char *fstype)
{
int maxfd = OPEN_MAX;
struct rlimit rl;
vfsent_t **vl, *vp;
if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1)
maxrun = 4;
else
maxrun = maxrun * 2 + 1;
if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
rl.rlim_cur = rl.rlim_max;
if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
maxfd = (int)rl.rlim_cur;
}
(void) enable_extended_FILE_stdio(-1, -1);
maxfd = (maxfd / 2) - 6;
if (maxfd < maxrun)
maxrun = maxfd;
if (maxrun < 4)
maxrun = 4;
if (count == 0)
mntlist = NULL;
else
fstype = NULL;
vfsll = getvfsall(fstype, mntlist == NULL);
if (vfsll == NULL ||
(vfsarray = make_vfsarray(mntlist, count)) == NULL) {
if (mntlist == NULL)
return (0);
fprintf(stderr, gettext("%s: No valid entries found in %s\n"),
myname, vfstab);
return (1);
}
if (!lofscnt)
qsort((void *)vfsarray, vfsarraysize, sizeof (vfsent_t *),
mlevelcmp);
vfsll = vfsarray[0];
for (vl = vfsarray; vp = *vl; )
vp->next = *++vl;
sigset(SIGHUP, cleanup);
sigset(SIGQUIT, cleanup);
sigset(SIGINT, cleanup);
do_mounts();
if (failcnt > 0 && failcnt == lofsfail)
return (ALL_LOFS_FAILURES);
return (exitcode);
}
vfsent_t *
getvfsall(char *fstype, int takeall)
{
vfsent_t *vhead, *vtail;
struct vfstab vget;
FILE *fp;
int cnt = 0, ret;
if ((fp = fopen(vfstab, "r")) == NULL) {
fprintf(stderr, gettext("%s: Cannot open %s\n"),
myname, vfstab);
exit(1);
}
vhead = vtail = NULL;
while ((ret = getvfsent(fp, &vget)) != -1) {
vfsent_t *vp;
if (ret > 0) {
vfserror(ret, vget.vfs_mountp);
continue;
}
if (takeall &&
(vget.vfs_automnt == NULL ||
strcmp(vget.vfs_automnt, "yes")))
continue;
if (fstype && vget.vfs_fstype &&
strcmp(fstype, vget.vfs_fstype))
continue;
if (vget.vfs_mountp == NULL ||
(vget.vfs_fstype && (strcmp(vget.vfs_fstype, "swap") == 0)))
continue;
if (check_fields(vget.vfs_fstype, vget.vfs_mountp)) {
exitcode = 1;
continue;
}
vp = new_vfsent(&vget, cnt);
if (vhead == NULL)
vhead = vp;
else
vtail->next = vp;
vtail = vp;
cnt++;
}
fclose(fp);
if (vtail == NULL) {
vfsarraysize = 0;
vfslltail = NULL;
return (NULL);
}
vtail->next = NULL;
vfslltail = vtail;
vfsarraysize = cnt;
return (vhead);
}
vfsent_t **
make_vfsarray(char **mntlist, int count)
{
vfsent_t *vp, *vmark, *vpprev, **vpp;
int ndx, found;
if (vfsll == NULL)
return (NULL);
if (count > 0)
vfsarraysize = count;
vpp = (vfsent_t **)malloc(sizeof (*vpp) * (vfsarraysize + 1));
if (vpp == NULL)
nomem();
if (mntlist == NULL) {
for (ndx = 0, vp = vfsll; vp; vp = vp->next) {
(void) setrpath(vp);
if (vp->v.vfs_fstype &&
(strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0))
lofscnt++;
vpp[ndx++] = vp;
}
vpp[ndx] = NULL;
return (vpp);
}
vpprev = vfslltail;
vpprev->next = vfsll;
vmark = vp = vfsll;
for (ndx = 0; *mntlist; mntlist++) {
found = 0;
while (vp) {
if (strcmp(*mntlist, vp->v.vfs_mountp) == 0) {
vpp[ndx++] = vp;
(void) setrpath(vp);
if (vp->v.vfs_fstype &&
(strcmp(vp->v.vfs_fstype,
MNTTYPE_LOFS) == 0))
lofscnt++;
if (vp == vpprev) {
vp = NULL;
found++;
break;
}
vp = vp->next;
vpprev->next->next = NULL;
vpprev->next = vp;
vmark = vp;
found++;
break;
}
vpprev = vp;
vp = vp->next;
if (vp == vmark)
break;
}
if (!found) {
fprintf(stderr, gettext(
"%s: Warning: %s not found in %s\n"),
myname, *mntlist, vfstab);
exitcode = 1;
}
}
if (ndx == 0)
return (NULL);
vpp[ndx] = NULL;
vfsarraysize = ndx;
return (vpp);
}
void
do_mounts(void)
{
int i, isave, cnt;
vfsent_t *vp, *vpprev, **vl;
char *newargv[ARGV_MAX];
pid_t child;
i = 2;
if (cflg)
newargv[i++] = "-c";
if (gflg)
newargv[i++] = "-g";
if (mflg)
newargv[i++] = "-m";
if (Oflg)
newargv[i++] = "-O";
if (qflg)
newargv[i++] = "-q";
if (rflg)
newargv[i++] = "-r";
if (dashflg)
newargv[i++] = "--";
if (oflg) {
newargv[i++] = "-o";
newargv[i++] = specific_opts;
}
isave = i;
vl = vfsarray;
cnt = vfsarraysize;
for (vpprev = *vl; vp = *vl; vpprev = vp, vl++, cnt--) {
if (vp->mlevel > vpprev->mlevel || lofscnt > 0) {
vfsent_t **vlp;
while (nrun > 0 && (dowait() != -1))
;
for (vlp = vl; *vlp; vlp++)
(void) setrpath(*vlp);
if (lofscnt == 0) {
qsort((void *)vl, cnt, sizeof (vfsent_t *),
mlevelcmp);
vp = *vl;
}
}
if (vp->flag & VRPFAILED) {
fprintf(stderr, gettext(
"%s: Nonexistent mount point: %s\n"),
myname, vp->v.vfs_mountp);
vp->flag |= VNOTMOUNTED;
exitcode = 1;
continue;
}
i = isave;
if (!oflg && vp->v.vfs_mntopts) {
newargv[i++] = "-o";
newargv[i++] = vp->v.vfs_mntopts;
}
newargv[i++] = vp->v.vfs_special;
newargv[i++] = vp->rpath;
newargv[i] = NULL;
while (setup_iopipe(vp) == -1 && (dowait() != -1))
;
while (nrun >= maxrun && (dowait() != -1))
;
if ((child = fork()) == -1) {
perror("fork");
cleanup(-1);
}
if (child == 0) {
signal(SIGHUP, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
signal(SIGINT, SIG_IGN);
setup_output(vp);
doexec(vp->v.vfs_fstype, newargv);
perror("exec");
exit(1);
}
(void) close(vp->sopipe[WRPIPE]);
(void) close(vp->sepipe[WRPIPE]);
vp->pid = child;
nrun++;
}
cleanup(0);
}
int
setup_iopipe(vfsent_t *mp)
{
if (pipe(mp->sopipe) == -1)
return (-1);
if (pipe(mp->sepipe) == -1) {
(void) close(mp->sopipe[RDPIPE]);
(void) close(mp->sopipe[WRPIPE]);
return (-1);
}
(void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
(void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
(void) fcntl(mp->sopipe[RDPIPE], F_SETFD, FD_CLOEXEC);
(void) fcntl(mp->sepipe[RDPIPE], F_SETFD, FD_CLOEXEC);
return (0);
}
void
setup_output(vfsent_t *vp)
{
(void) close(fileno(stdout));
(void) dup(vp->sopipe[WRPIPE]);
(void) close(vp->sopipe[WRPIPE]);
(void) close(fileno(stderr));
(void) dup(vp->sepipe[WRPIPE]);
(void) close(vp->sepipe[WRPIPE]);
}
static void
doio(vfsent_t *vp)
{
int bytes;
char ibuf[BUFSIZ];
while ((bytes = read(vp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
write(fileno(stderr), ibuf, bytes);
while ((bytes = read(vp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
write(fileno(stdout), ibuf, bytes);
(void) close(vp->sopipe[RDPIPE]);
(void) close(vp->sepipe[RDPIPE]);
}
int
dowait(void)
{
int child, wstat;
if ((child = wait(&wstat)) == -1)
return (-1);
nrun--;
return (cleanupkid(child, wstat) != 0);
}
int
cleanupkid(pid_t pid, int wstat)
{
vfsent_t *vp, *prevp;
int ret;
if (WIFEXITED(wstat))
ret = WEXITSTATUS(wstat);
else
ret = 1;
if (ret) {
exitcode = 1;
failcnt++;
}
for (prevp = NULL, vp = vfsll; vp; vp = vp->next) {
if (vp->pid != pid) {
prevp = vp;
continue;
}
if (prevp) {
prevp->next = vp->next;
vp->next = NULL;
}
break;
}
if (vp == NULL) {
fprintf(stderr, gettext(
"%s: Unknown child %d\n"), myname, pid);
exitcode = 1;
return (ret);
}
doio(vp);
if (vp->v.vfs_fstype &&
(strcmp(vp->v.vfs_fstype, MNTTYPE_LOFS) == 0)) {
lofscnt--;
if (ret)
lofsfail++;
}
vp->exitcode = ret;
return (ret);
}
static vfsent_t zvmount = { 0 };
vfsent_t *
new_vfsent(struct vfstab *vin, int order)
{
vfsent_t *new;
new = (vfsent_t *)malloc(sizeof (*new));
if (new == NULL)
nomem();
*new = zvmount;
if (vin->vfs_special &&
(new->v.vfs_special = strdup(vin->vfs_special)) == NULL)
nomem();
if (vin->vfs_mountp &&
(new->v.vfs_mountp = strdup(vin->vfs_mountp)) == NULL)
nomem();
if (vin->vfs_fstype &&
(new->v.vfs_fstype = strdup(vin->vfs_fstype)) == NULL)
nomem();
if (oflg) {
if ((new->v.vfs_mntopts = strdup(specific_opts)) == NULL)
nomem();
} else if (vin->vfs_mntopts &&
(new->v.vfs_mntopts = strdup(vin->vfs_mntopts)) == NULL)
nomem();
new->order = order;
return (new);
}
char *
setrpath(vfsent_t *vp)
{
char *rp;
if ((rp = realpath(vp->v.vfs_mountp, realdir)) == NULL)
vp->flag |= VRPFAILED;
else
vp->flag &= ~VRPFAILED;
if (vp->rpath)
free(vp->rpath);
if ((vp->rpath = strdup(realdir)) == NULL)
nomem();
vp->mlevel = fsgetmlevel(vp->rpath);
return (rp);
}
int
mlevelcmp(const void *a, const void *b)
{
vfsent_t *a1, *b1;
int lcmp;
a1 = *(vfsent_t **)a;
b1 = *(vfsent_t **)b;
lcmp = a1->mlevel - b1->mlevel;
if (lcmp == 0)
lcmp = a1->order - b1->order;
return (lcmp);
}
static int
mordercmp(const void *a, const void *b)
{
vfsent_t *a1, *b1;
a1 = *(vfsent_t **)a;
b1 = *(vfsent_t **)b;
return (a1->order - b1->order);
}
void
cleanup(int asig)
{
while (nrun > 0 && (dowait() != -1))
;
if (asig != 0)
exit(1);
}
int
check_fields(char *fstype, char *mountp)
{
struct stat64 stbuf;
if (fstype == NULL) {
fprintf(stderr,
gettext("%s: FSType cannot be determined\n"),
myname);
return (1);
}
if (strlen(fstype) > (size_t)FSTYPE_MAX) {
fprintf(stderr,
gettext("%s: FSType %s exceeds %d characters\n"),
myname, fstype, FSTYPE_MAX);
return (1);
}
if (mountp == NULL) {
fprintf(stderr,
gettext("%s: Mount point cannot be determined\n"),
myname);
return (1);
}
if (*mountp != '/') {
fprintf(stderr, gettext(
"%s: Mount point %s is not an absolute pathname.\n"),
myname, mountp);
return (1);
}
if (!aflg && stat64(mountp, &stbuf) < 0) {
if (errno == ENOENT || errno == ENOTDIR)
fprintf(stderr,
gettext("%s: Mount point %s does not exist.\n"),
myname, mountp);
else {
fprintf(stderr,
gettext("%s: Cannot stat mount point %s.\n"),
myname, mountp);
perror(myname);
}
return (1);
}
return (0);
}
void
nomem(void)
{
fprintf(stderr, gettext("%s: Out of memory\n"), myname);
while (nrun > 0 && (dowait() != -1))
;
exit(1);
}