6253 F_GETLK doesn't always return lock owner
[illumos-gate.git] / usr / src / cmd / fs.d / umount.c
blobda08a82432de462df4aed348285dd310fc82ebbb
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 /* All Rights Reserved */
30 #include <stdio.h>
31 #include <stdio_ext.h>
32 #include <limits.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/signal.h>
37 #include <sys/mnttab.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 #include <sys/stat.h>
41 #include <sys/param.h>
42 #include <sys/wait.h>
43 #include <sys/vfstab.h>
44 #include <sys/fcntl.h>
45 #include <sys/resource.h>
46 #include <sys/mntent.h>
47 #include <sys/ctfs.h>
48 #include <locale.h>
49 #include <stdarg.h>
50 #include <sys/mount.h>
51 #include <sys/objfs.h>
52 #include "fslib.h"
53 #include <sharefs/share.h>
55 #define FS_PATH "/usr/lib/fs"
56 #define ALT_PATH "/etc/fs"
57 #define FULLPATH_MAX 32
58 #define FSTYPE_MAX 8
59 #define ARGV_MAX 16
61 int aflg, oflg, Vflg, dashflg, dflg, fflg;
63 extern void rpterr(), usage(), mnterror();
65 extern char *optarg; /* used by getopt */
66 extern int optind, opterr;
68 static char *myname;
69 char fs_path[] = FS_PATH;
70 char alt_path[] = ALT_PATH;
71 char mnttab[MAXPATHLEN + 1];
72 char *oarg, *farg;
73 int maxrun, nrun;
74 int no_mnttab;
75 int lofscnt; /* presence of lofs prohibits parallel */
76 /* umounting */
77 int exitcode;
78 char resolve[MAXPATHLEN];
79 static char ibuf[BUFSIZ];
82 * Currently, mounting cachefs's simultaneous uncovers various problems.
83 * For the short term, we serialize cachefs activity while we fix
84 * these cachefs bugs.
86 #define CACHEFS_BUG
87 #ifdef CACHEFS_BUG
88 #include <sys/fs/cachefs_fs.h> /* for BACKMNT_NAME */
89 int cachefs_running; /* parallel cachefs not supported yet */
90 #endif
93 * The basic mount struct that describes an mnttab entry.
94 * It is used both in an array and as a linked list elem.
97 typedef struct mountent {
98 struct mnttab ment; /* the mnttab data */
99 int mlevel; /* mount level of the mount pt */
100 pid_t pid; /* the pid of this mount process */
101 #define RDPIPE 0
102 #define WRPIPE 1
103 int sopipe[2]; /* pipe attached to child's stdout */
104 int sepipe[2]; /* pipe attached to child's stderr */
105 struct mountent *link; /* used when in linked list */
106 } mountent_t;
108 static mountent_t *mntll; /* head of global linked list of */
109 /* mountents */
110 int listlength; /* # of elems in this list */
113 * If the automatic flag (-a) is given and mount points are not specified
114 * on the command line, then do not attempt to umount these. These
115 * generally need to be kept mounted until system shutdown.
117 static const char *keeplist[] = {
118 "/",
119 "/dev",
120 "/dev/fd",
121 "/devices",
122 "/etc/mnttab",
123 "/etc/svc/volatile",
124 "/lib",
125 "/proc",
126 "/sbin",
127 CTFS_ROOT,
128 OBJFS_ROOT,
129 "/tmp",
130 "/usr",
131 "/var",
132 "/var/adm",
133 "/var/run",
134 SHARETAB,
135 NULL
138 static void nomem();
139 static void doexec(struct mnttab *);
140 static int setup_iopipe(mountent_t *);
141 static void setup_output(mountent_t *);
142 static void doio(mountent_t *);
143 static void do_umounts(mountent_t **);
144 static int dowait();
145 static int parumount();
146 static int mcompar(const void *, const void *);
147 static void cleanup(int);
149 static mountent_t **make_mntarray(char **, int);
150 static mountent_t *getmntall();
151 static mountent_t *new_mountent(struct mnttab *);
152 static mountent_t *getmntlast(mountent_t *, char *, char *);
155 main(int argc, char **argv)
157 int cc;
158 struct mnttab mget;
159 char *mname, *is_special;
160 int fscnt;
161 mountent_t *mp;
163 (void) setlocale(LC_ALL, "");
165 #if !defined(TEXT_DOMAIN)
166 #define TEXT_DOMAIN "SYS_TEST"
167 #endif
168 (void) textdomain(TEXT_DOMAIN);
170 myname = strrchr(argv[0], '/');
171 if (myname)
172 myname++;
173 else
174 myname = argv[0];
177 * Process the args.
178 * "-d" for compatibility
180 while ((cc = getopt(argc, argv, "ado:Vf?")) != -1)
181 switch (cc) {
182 case 'a':
183 aflg++;
184 break;
185 #ifdef DEBUG
186 case 'd':
187 dflg++;
188 break;
189 #endif
191 case '?':
192 usage();
193 break;
194 case 'o':
195 if (oflg)
196 usage();
197 else {
198 oflg++;
199 oarg = optarg;
201 break;
202 case 'f':
203 fflg++;
204 break;
205 case 'V':
206 if (Vflg)
207 usage();
208 else
209 Vflg++;
210 break;
211 default:
212 usage();
213 break;
216 fscnt = argc - optind;
217 if (!aflg && fscnt != 1)
218 usage();
220 /* copy '--' to specific */
221 if (strcmp(argv[optind-1], "--") == 0)
222 dashflg++;
225 * mnttab may be a symlink to a file in another file system.
226 * This happens during install when / is mounted read-only
227 * and /etc/mnttab is symlinked to a file in /tmp.
228 * If this is the case, we need to follow the symlink to the
229 * read-write file itself so that the subsequent mnttab.temp
230 * open and rename will work.
232 if (realpath(MNTTAB, mnttab) == NULL) {
233 strcpy(mnttab, MNTTAB);
237 * bugid 1205242
238 * call the realpath() here, so that if the user is
239 * trying to umount an autofs directory, the directory
240 * is forced to mount.
243 mname = argv[optind];
244 is_special = realpath(mname, resolve);
247 * Read the whole mnttab into memory.
249 mntll = getmntall();
251 if (aflg && fscnt != 1)
252 exit(parumount(argv + optind, fscnt));
254 aflg = 0;
256 mntnull(&mget);
257 if (listlength == 0) {
258 fprintf(stderr, gettext(
259 "%s: warning: no entries found in %s\n"),
260 myname, mnttab);
261 mget.mnt_mountp = mname; /* assume mount point */
262 no_mnttab++;
263 doexec(&mget);
264 exit(0);
267 mp = NULL;
270 * if realpath fails, it can't be a mount point, so we'll
271 * go straight to the code that treats the arg as a special.
272 * if realpath succeeds, it could be a special or a mount point;
273 * we'll start by assuming it's a mount point, and if it's not,
274 * try to treat it as a special.
276 if (is_special != NULL) {
278 * if this succeeds,
279 * we'll have the appropriate record; if it fails
280 * we'll assume the arg is a special of some sort
282 mp = getmntlast(mntll, NULL, resolve);
285 * Since stackable mount is allowed (RFE 2001535),
286 * we will un-mount the last entry in the MNTTAB that matches.
288 if (mp == NULL) {
290 * Perhaps there is a bogus mnttab entry that
291 * can't be resolved:
293 if ((mp = getmntlast(mntll, NULL, mname)) == NULL)
295 * assume it's a device (special) now
297 mp = getmntlast(mntll, mname, NULL);
298 if (mp) {
300 * Found it.
301 * This is a device. Now we want to know if
302 * it stackmounted on by something else.
303 * The original fix for bug 1103850 has a
304 * problem with lockfs (bug 1119731). This
305 * is a revised method.
307 mountent_t *lmp;
308 lmp = getmntlast(mntll, NULL, mp->ment.mnt_mountp);
310 if (lmp && strcmp(lmp->ment.mnt_special,
311 mp->ment.mnt_special)) {
312 errno = EBUSY;
313 rpterr(mname);
314 exit(1);
316 } else {
317 fprintf(stderr, gettext(
318 "%s: warning: %s not in mnttab\n"),
319 myname, mname);
320 if (Vflg)
321 exit(1);
323 * same error as mount -V
324 * would give for unknown
325 * mount point
327 mget.mnt_special = mget.mnt_mountp = mname;
331 if (mp)
332 doexec(&mp->ment);
333 else
334 doexec(&mget);
336 return (0);
339 void
340 doexec(struct mnttab *ment)
342 int ret;
344 #ifdef DEBUG
345 if (dflg)
346 fprintf(stderr, "%d: umounting %s\n",
347 getpid(), ment->mnt_mountp);
348 #endif
350 /* try to exec the dependent portion */
351 if ((ment->mnt_fstype != NULL) || Vflg) {
352 char full_path[FULLPATH_MAX];
353 char alter_path[FULLPATH_MAX];
354 char *newargv[ARGV_MAX];
355 int ii;
357 if (strlen(ment->mnt_fstype) > (size_t)FSTYPE_MAX) {
358 fprintf(stderr, gettext(
359 "%s: FSType %s exceeds %d characters\n"),
360 myname, ment->mnt_fstype, FSTYPE_MAX);
361 exit(1);
364 /* build the full pathname of the fstype dependent command. */
365 sprintf(full_path, "%s/%s/%s", fs_path, ment->mnt_fstype,
366 myname);
367 sprintf(alter_path, "%s/%s/%s", alt_path, ment->mnt_fstype,
368 myname);
371 * create the new arg list, and end the list with a
372 * null pointer
374 ii = 2;
375 if (oflg) {
376 newargv[ii++] = "-o";
377 newargv[ii++] = oarg;
379 if (dashflg) {
380 newargv[ii++] = "--";
382 if (fflg) {
383 newargv[ii++] = "-f";
385 newargv[ii++] = (ment->mnt_mountp)
386 ? ment->mnt_mountp : ment->mnt_special;
387 newargv[ii] = NULL;
389 /* set the new argv[0] to the filename */
390 newargv[1] = myname;
392 if (Vflg) {
393 printf("%s", myname);
394 for (ii = 2; newargv[ii]; ii++)
395 printf(" %s", newargv[ii]);
396 printf("\n");
397 fflush(stdout);
398 exit(0);
401 /* Try to exec the fstype dependent umount. */
402 execv(full_path, &newargv[1]);
403 if (errno == ENOEXEC) {
404 newargv[0] = "sh";
405 newargv[1] = full_path;
406 execv("/sbin/sh", &newargv[0]);
408 newargv[1] = myname;
409 execv(alter_path, &newargv[1]);
410 if (errno == ENOEXEC) {
411 newargv[0] = "sh";
412 newargv[1] = alter_path;
413 execv("/sbin/sh", &newargv[0]);
415 /* exec failed */
416 if (errno != ENOENT) {
417 fprintf(stderr, gettext("umount: cannot execute %s\n"),
418 full_path);
419 exit(1);
423 * No fstype independent executable then. We'll go generic
424 * from here.
427 /* don't use -o with generic */
428 if (oflg) {
429 fprintf(stderr, gettext(
430 "%s: %s specific umount does not exist;"
431 " -o suboption ignored\n"),
432 myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>");
435 signal(SIGHUP, SIG_IGN);
436 signal(SIGQUIT, SIG_IGN);
437 signal(SIGINT, SIG_IGN);
439 * Try to umount the mountpoint.
440 * If that fails, try the corresponding special.
441 * (This ordering is necessary for nfs umounts.)
442 * (for remote resources: if the first umount returns EBUSY
443 * don't call umount again - umount() with a resource name
444 * will return a misleading error to the user
446 if (fflg) {
447 if (((ret = umount2(ment->mnt_mountp, MS_FORCE)) < 0) &&
448 (errno != EBUSY && errno != ENOTSUP &&
449 errno != EPERM))
450 ret = umount2(ment->mnt_special, MS_FORCE);
451 } else {
452 if (((ret = umount2(ment->mnt_mountp, 0)) < 0) &&
453 (errno != EBUSY) && (errno != EPERM))
454 ret = umount2(ment->mnt_special, 0);
457 if (ret < 0) {
458 rpterr(ment->mnt_mountp);
459 if (errno != EINVAL && errno != EFAULT)
460 exit(1);
462 exitcode = 1;
465 exit(exitcode);
468 void
469 rpterr(char *sp)
471 switch (errno) {
472 case EPERM:
473 fprintf(stderr, gettext("%s: permission denied\n"), myname);
474 break;
475 case ENXIO:
476 fprintf(stderr, gettext("%s: %s no device\n"), myname, sp);
477 break;
478 case ENOENT:
479 fprintf(stderr,
480 gettext("%s: %s no such file or directory\n"),
481 myname, sp);
482 break;
483 case EINVAL:
484 fprintf(stderr, gettext("%s: %s not mounted\n"), myname, sp);
485 break;
486 case EBUSY:
487 fprintf(stderr, gettext("%s: %s busy\n"), myname, sp);
488 break;
489 case ENOTBLK:
490 fprintf(stderr,
491 gettext("%s: %s block device required\n"), myname, sp);
492 break;
493 case ECOMM:
494 fprintf(stderr,
495 gettext("%s: warning: broken link detected\n"), myname);
496 break;
497 default:
498 perror(myname);
499 fprintf(stderr, gettext("%s: cannot unmount %s\n"), myname, sp);
503 void
504 usage(void)
506 fprintf(stderr, gettext(
507 "Usage:\n%s [-f] [-V] [-o specific_options] {special | mount-point}\n"),
508 myname);
509 fprintf(stderr, gettext(
510 "%s -a [-f] [-V] [-o specific_options] [mount_point ...]\n"), myname);
511 exit(1);
514 void
515 mnterror(int flag)
517 switch (flag) {
518 case MNT_TOOLONG:
519 fprintf(stderr,
520 gettext("%s: line in mnttab exceeds %d characters\n"),
521 myname, MNT_LINE_MAX-2);
522 break;
523 case MNT_TOOFEW:
524 fprintf(stderr,
525 gettext("%s: line in mnttab has too few entries\n"),
526 myname);
527 break;
528 default:
529 break;
534 * Search the mlist linked list for the
535 * first match of specp or mntp. The list is expected to be in reverse
536 * order of /etc/mnttab.
537 * If both are specified, then both have to match.
538 * Returns the (mountent_t *) of the match, otherwise returns NULL.
540 mountent_t *
541 getmntlast(mountent_t *mlist, char *specp, char *mntp)
543 int mfound, sfound;
545 for (/* */; mlist; mlist = mlist->link) {
546 mfound = sfound = 0;
547 if (mntp && (strcmp(mlist->ment.mnt_mountp, mntp) == 0)) {
548 if (specp == NULL)
549 return (mlist);
550 mfound++;
552 if (specp && (strcmp(mlist->ment.mnt_special, specp) == 0)) {
553 if (mntp == NULL)
554 return (mlist);
555 sfound++;
557 if (mfound && sfound)
558 return (mlist);
560 return (NULL);
566 * Perform the parallel version of umount. Returns 0 if no errors occurred,
567 * non zero otherwise.
570 parumount(char **mntlist, int count)
572 int maxfd = OPEN_MAX;
573 struct rlimit rl;
574 mountent_t **mntarray, **ml, *mp;
577 * If no mount points are specified and none were found in mnttab,
578 * then end it all here.
580 if (count == 0 && mntll == NULL)
581 return (0);
584 * This is the process scaling section. After running a series
585 * of tests based on the number of simultaneous processes and
586 * processors available, optimum performance was achieved near or
587 * at (PROCN * 2).
589 if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1)
590 maxrun = 4;
591 else
592 maxrun = maxrun * 2 + 1;
594 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
595 rl.rlim_cur = rl.rlim_max;
596 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
597 maxfd = (int)rl.rlim_cur;
598 (void) enable_extended_FILE_stdio(-1, -1);
602 * The parent needs to maintain 3 of its own fd's, plus 2 for
603 * each child (the stdout and stderr pipes).
605 maxfd = (maxfd / 2) - 6; /* 6 takes care of temporary */
606 /* periods of open fds */
607 if (maxfd < maxrun)
608 maxrun = maxfd;
609 if (maxrun < 4)
610 maxrun = 4; /* sanity check */
612 mntarray = make_mntarray(mntlist, count);
614 if (listlength == 0) {
615 if (count == 0) /* not an error, just none found */
616 return (0);
617 fprintf(stderr, gettext("%s: no valid entries found in %s\n"),
618 myname, mnttab);
619 return (1);
623 * Sort the entries based on their mount level only if lofs's are
624 * not present.
626 if (lofscnt == 0) {
627 qsort((void *)mntarray, listlength, sizeof (mountent_t *),
628 mcompar);
630 * If we do not detect a lofs by now, we never will.
632 lofscnt = -1;
635 * Now link them up so that a given pid is easier to find when
636 * we go to clean up after they are done.
638 mntll = mntarray[0];
639 for (ml = mntarray; mp = *ml; /* */)
640 mp->link = *++ml;
643 * Try to handle interrupts in a reasonable way.
645 sigset(SIGHUP, cleanup);
646 sigset(SIGQUIT, cleanup);
647 sigset(SIGINT, cleanup);
649 do_umounts(mntarray); /* do the umounts */
650 return (exitcode);
654 * Returns a mountent_t array based on mntlist. If mntlist is NULL, then
655 * it returns all mnttab entries with a few exceptions. Sets the global
656 * variable listlength to the number of entries in the array.
658 mountent_t **
659 make_mntarray(char **mntlist, int count)
661 mountent_t *mp, **mpp;
662 int ndx;
663 char *cp;
665 if (count > 0)
666 listlength = count;
668 mpp = (mountent_t **)malloc(sizeof (*mp) * (listlength + 1));
669 if (mpp == NULL)
670 nomem();
672 if (count == 0) {
673 if (mntll == NULL) { /* no entries? */
674 listlength = 0;
675 return (NULL);
678 * No mount list specified: take all mnttab mount points
679 * except for a few cases.
681 for (ndx = 0, mp = mntll; mp; mp = mp->link) {
682 if (fsstrinlist(mp->ment.mnt_mountp, keeplist))
683 continue;
684 mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp);
685 if (mp->ment.mnt_fstype &&
686 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
687 lofscnt++;
689 mpp[ndx++] = mp;
691 mpp[ndx] = NULL;
692 listlength = ndx;
693 return (mpp);
697 * A list of mount points was specified on the command line.
698 * Build an array out of these.
700 for (ndx = 0; count--; ) {
701 cp = *mntlist++;
702 if (realpath(cp, resolve) == NULL) {
703 fprintf(stderr,
704 gettext("%s: warning: can't resolve %s\n"),
705 myname, cp);
706 exitcode = 1;
707 mp = getmntlast(mntll, NULL, cp); /* try anyways */
708 } else
709 mp = getmntlast(mntll, NULL, resolve);
710 if (mp == NULL) {
711 struct mnttab mnew;
713 * Then we've reached the end without finding
714 * what we are looking for, but we still have to
715 * try to umount it: append it to mntarray.
717 fprintf(stderr, gettext(
718 "%s: warning: %s not found in %s\n"),
719 myname, resolve, mnttab);
720 exitcode = 1;
721 mntnull(&mnew);
722 mnew.mnt_special = mnew.mnt_mountp = strdup(resolve);
723 if (mnew.mnt_special == NULL)
724 nomem();
725 mp = new_mountent(&mnew);
727 if (mp->ment.mnt_fstype &&
728 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
729 lofscnt++;
731 mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp);
732 mpp[ndx++] = mp;
734 mpp[ndx] = NULL;
735 listlength = ndx;
736 return (mpp);
740 * Returns the tail of a linked list of all mnttab entries. I.e, it's faster
741 * to return the mnttab in reverse order.
742 * Sets listlength to the number of entries in the list.
743 * Returns NULL if none are found.
745 mountent_t *
746 getmntall(void)
748 FILE *fp;
749 mountent_t *mtail;
750 int cnt = 0, ret;
751 struct mnttab mget;
753 if ((fp = fopen(mnttab, "r")) == NULL) {
754 fprintf(stderr, gettext("%s: warning cannot open %s\n"),
755 myname, mnttab);
756 return (0);
758 mtail = NULL;
760 while ((ret = getmntent(fp, &mget)) != -1) {
761 mountent_t *mp;
763 if (ret > 0) {
764 mnterror(ret);
765 continue;
768 mp = new_mountent(&mget);
769 mp->link = mtail;
770 mtail = mp;
771 cnt++;
773 fclose(fp);
774 if (mtail == NULL) {
775 listlength = 0;
776 return (NULL);
778 listlength = cnt;
779 return (mtail);
782 void
783 do_umounts(mountent_t **mntarray)
785 mountent_t *mp, *mpprev, **ml = mntarray;
786 int cnt = listlength;
789 * Main loop for the forked children:
791 for (mpprev = *ml; mp = *ml; mpprev = mp, ml++, cnt--) {
792 pid_t pid;
795 * Check to see if we cross a mount level: e.g.,
796 * /a/b/c -> /a/b. If so, we need to wait for all current
797 * umounts to finish before umounting the rest.
799 * Also, we unmount serially as long as there are lofs's
800 * to mount to avoid improper umount ordering.
802 if (mp->mlevel < mpprev->mlevel || lofscnt > 0)
803 while (nrun > 0 && (dowait() != -1))
806 if (lofscnt == 0) {
808 * We can now go to parallel umounting.
810 qsort((void *)ml, cnt, sizeof (mountent_t *), mcompar);
811 mp = *ml; /* possible first entry */
812 lofscnt--; /* so we don't do this again */
815 while (setup_iopipe(mp) == -1 && (dowait() != -1))
818 while (nrun >= maxrun && (dowait() != -1)) /* throttle */
821 #ifdef CACHEFS_BUG
823 * If this is the back file system, then let cachefs/umount
824 * unmount it.
826 if (strstr(mp->ment.mnt_mountp, BACKMNT_NAME))
827 continue;
830 if (mp->ment.mnt_fstype &&
831 (strcmp(mp->ment.mnt_fstype, "cachefs") == 0)) {
832 while (cachefs_running && (dowait() != -1))
834 cachefs_running = 1;
836 #endif
838 if ((pid = fork()) == -1) {
839 perror("fork");
840 cleanup(-1);
841 /* not reached */
843 #ifdef DEBUG
844 if (dflg && pid > 0) {
845 fprintf(stderr, "parent %d: umounting %d %s\n",
846 getpid(), pid, mp->ment.mnt_mountp);
848 #endif
849 if (pid == 0) { /* child */
850 signal(SIGHUP, SIG_IGN);
851 signal(SIGQUIT, SIG_IGN);
852 signal(SIGINT, SIG_IGN);
853 setup_output(mp);
854 doexec(&mp->ment);
855 perror("exec");
856 exit(1);
859 /* parent */
860 (void) close(mp->sopipe[WRPIPE]);
861 (void) close(mp->sepipe[WRPIPE]);
862 mp->pid = pid;
863 nrun++;
865 cleanup(0);
869 * cleanup the existing children and exit with an error
870 * if asig != 0.
872 void
873 cleanup(int asig)
876 * Let the stragglers finish.
878 while (nrun > 0 && (dowait() != -1))
880 if (asig != 0)
881 exit(1);
886 * Waits for 1 child to die.
888 * Returns -1 if no children are left to wait for.
889 * Returns 0 if a child died without an error.
890 * Returns 1 if a child died with an error.
891 * Sets the global exitcode if an error occurred.
894 dowait(void)
896 int wstat, child, ret;
897 mountent_t *mp, *prevp;
899 if ((child = wait(&wstat)) == -1)
900 return (-1);
902 if (WIFEXITED(wstat)) /* this should always be true */
903 ret = WEXITSTATUS(wstat);
904 else
905 ret = 1; /* assume some kind of error */
906 nrun--;
907 if (ret)
908 exitcode = 1;
911 * Find our child so we can process its std output, if any.
912 * This search gets smaller and smaller as children are cleaned
913 * up.
915 for (prevp = NULL, mp = mntll; mp; mp = mp->link) {
916 if (mp->pid != child) {
917 prevp = mp;
918 continue;
921 * Found: let's remove it from this list.
923 if (prevp) {
924 prevp->link = mp->link;
925 mp->link = NULL;
927 break;
930 if (mp == NULL) {
932 * This should never happen.
934 #ifdef DEBUG
935 fprintf(stderr, gettext(
936 "%s: unknown child %d\n"), myname, child);
937 #endif
938 exitcode = 1;
939 return (1);
941 doio(mp); /* Any output? */
943 if (mp->ment.mnt_fstype &&
944 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
945 lofscnt--;
947 #ifdef CACHEFS_BUG
948 if (mp->ment.mnt_fstype &&
949 (strcmp(mp->ment.mnt_fstype, "cachefs") == 0))
950 cachefs_running = 0;
951 #endif
953 return (ret);
956 static const mountent_t zmount = { 0 };
958 mountent_t *
959 new_mountent(struct mnttab *ment)
961 mountent_t *new;
963 new = (mountent_t *)malloc(sizeof (*new));
964 if (new == NULL)
965 nomem();
967 *new = zmount;
968 if (ment->mnt_special &&
969 (new->ment.mnt_special = strdup(ment->mnt_special)) == NULL)
970 nomem();
971 if (ment->mnt_mountp &&
972 (new->ment.mnt_mountp = strdup(ment->mnt_mountp)) == NULL)
973 nomem();
974 if (ment->mnt_fstype &&
975 (new->ment.mnt_fstype = strdup(ment->mnt_fstype)) == NULL)
976 nomem();
977 return (new);
982 * Sort in descending order of "mount level". For example, /a/b/c is
983 * placed before /a/b .
986 mcompar(const void *a, const void *b)
988 mountent_t *a1, *b1;
990 a1 = *(mountent_t **)a;
991 b1 = *(mountent_t **)b;
992 return (b1->mlevel - a1->mlevel);
996 * The purpose of this routine is to form stdout and stderr
997 * pipes for the children's output. The parent then reads and writes it
998 * out it serially in order to ensure that the output is
999 * not garbled.
1003 setup_iopipe(mountent_t *mp)
1006 * Make a stdout and stderr pipe. This should never fail.
1008 if (pipe(mp->sopipe) == -1)
1009 return (-1);
1010 if (pipe(mp->sepipe) == -1) {
1011 (void) close(mp->sopipe[RDPIPE]);
1012 (void) close(mp->sopipe[WRPIPE]);
1013 return (-1);
1016 * Don't block on an empty pipe.
1018 (void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1019 (void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1020 return (0);
1024 * Called by a child to attach its stdout and stderr to the write side of
1025 * the pipes.
1027 void
1028 setup_output(mountent_t *mp)
1030 (void) close(fileno(stdout));
1031 (void) dup(mp->sopipe[WRPIPE]);
1032 (void) close(mp->sopipe[WRPIPE]);
1034 (void) close(fileno(stderr));
1035 (void) dup(mp->sepipe[WRPIPE]);
1036 (void) close(mp->sepipe[WRPIPE]);
1040 * Parent uses this to print any stdout or stderr output issued by
1041 * the child.
1043 static void
1044 doio(mountent_t *mp)
1046 int bytes;
1048 while ((bytes = read(mp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1049 write(fileno(stderr), ibuf, bytes);
1050 while ((bytes = read(mp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1051 write(fileno(stdout), ibuf, bytes);
1053 (void) close(mp->sopipe[RDPIPE]);
1054 (void) close(mp->sepipe[RDPIPE]);
1057 void
1058 nomem(void)
1060 fprintf(stderr, gettext("%s: out of memory\n"), myname);
1062 * Let the stragglers finish.
1064 while (nrun > 0 && (dowait() != -1))
1066 exit(1);