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