Print this page
6198 Let's EOL cachefs
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/fs.d/umount.c
+++ new/usr/src/cmd/fs.d/umount.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License (the "License").
6 6 * You may not use this file except in compliance with the License.
7 7 *
8 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 9 * or http://www.opensolaris.org/os/licensing.
10 10 * See the License for the specific language governing permissions
11 11 * and limitations under the License.
12 12 *
13 13 * When distributing Covered Code, include this CDDL HEADER in each
↓ open down ↓ |
13 lines elided |
↑ open up ↑ |
14 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 15 * If applicable, add the following below this CDDL HEADER, with the
16 16 * fields enclosed by brackets "[]" replaced with your own identifying
17 17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 18 *
19 19 * CDDL HEADER END
20 20 */
21 21 /*
22 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
23 23 * Use is subject to license terms.
24 + * Copyright 2015 Nexenta Systems, Inc. All rights reserved.
24 25 */
25 26
26 27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 28 /* All Rights Reserved */
28 29
29 30
30 31 #include <stdio.h>
31 32 #include <stdio_ext.h>
32 33 #include <limits.h>
33 34 #include <unistd.h>
34 35 #include <stdlib.h>
35 36 #include <string.h>
36 37 #include <sys/signal.h>
37 38 #include <sys/mnttab.h>
38 39 #include <errno.h>
39 40 #include <sys/types.h>
40 41 #include <sys/stat.h>
41 42 #include <sys/param.h>
42 43 #include <sys/wait.h>
43 44 #include <sys/vfstab.h>
44 45 #include <sys/fcntl.h>
45 46 #include <sys/resource.h>
46 47 #include <sys/mntent.h>
47 48 #include <sys/ctfs.h>
48 49 #include <locale.h>
49 50 #include <stdarg.h>
50 51 #include <sys/mount.h>
51 52 #include <sys/objfs.h>
52 53 #include "fslib.h"
53 54 #include <sharefs/share.h>
54 55
55 56 #define FS_PATH "/usr/lib/fs"
56 57 #define ALT_PATH "/etc/fs"
57 58 #define FULLPATH_MAX 32
58 59 #define FSTYPE_MAX 8
59 60 #define ARGV_MAX 16
60 61
61 62 int aflg, oflg, Vflg, dashflg, dflg, fflg;
62 63
63 64 extern void rpterr(), usage(), mnterror();
64 65
65 66 extern char *optarg; /* used by getopt */
66 67 extern int optind, opterr;
67 68
68 69 static char *myname;
69 70 char fs_path[] = FS_PATH;
70 71 char alt_path[] = ALT_PATH;
71 72 char mnttab[MAXPATHLEN + 1];
↓ open down ↓ |
38 lines elided |
↑ open up ↑ |
72 73 char *oarg, *farg;
73 74 int maxrun, nrun;
74 75 int no_mnttab;
75 76 int lofscnt; /* presence of lofs prohibits parallel */
76 77 /* umounting */
77 78 int exitcode;
78 79 char resolve[MAXPATHLEN];
79 80 static char ibuf[BUFSIZ];
80 81
81 82 /*
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.
85 - */
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
91 -
92 -/*
93 83 * The basic mount struct that describes an mnttab entry.
94 84 * It is used both in an array and as a linked list elem.
95 85 */
96 86
97 87 typedef struct mountent {
98 88 struct mnttab ment; /* the mnttab data */
99 89 int mlevel; /* mount level of the mount pt */
100 90 pid_t pid; /* the pid of this mount process */
101 91 #define RDPIPE 0
102 92 #define WRPIPE 1
103 93 int sopipe[2]; /* pipe attached to child's stdout */
104 94 int sepipe[2]; /* pipe attached to child's stderr */
105 95 struct mountent *link; /* used when in linked list */
106 96 } mountent_t;
107 97
108 98 static mountent_t *mntll; /* head of global linked list of */
109 99 /* mountents */
110 100 int listlength; /* # of elems in this list */
111 101
112 102 /*
113 103 * If the automatic flag (-a) is given and mount points are not specified
114 104 * on the command line, then do not attempt to umount these. These
115 105 * generally need to be kept mounted until system shutdown.
116 106 */
117 107 static const char *keeplist[] = {
118 108 "/",
119 109 "/dev",
120 110 "/dev/fd",
121 111 "/devices",
122 112 "/etc/mnttab",
123 113 "/etc/svc/volatile",
124 114 "/lib",
125 115 "/proc",
126 116 "/sbin",
127 117 CTFS_ROOT,
128 118 OBJFS_ROOT,
129 119 "/tmp",
130 120 "/usr",
131 121 "/var",
132 122 "/var/adm",
133 123 "/var/run",
134 124 SHARETAB,
135 125 NULL
136 126 };
137 127
138 128 static void nomem();
139 129 static void doexec(struct mnttab *);
140 130 static int setup_iopipe(mountent_t *);
141 131 static void setup_output(mountent_t *);
142 132 static void doio(mountent_t *);
143 133 static void do_umounts(mountent_t **);
144 134 static int dowait();
145 135 static int parumount();
146 136 static int mcompar(const void *, const void *);
147 137 static void cleanup(int);
148 138
149 139 static mountent_t **make_mntarray(char **, int);
150 140 static mountent_t *getmntall();
151 141 static mountent_t *new_mountent(struct mnttab *);
152 142 static mountent_t *getmntlast(mountent_t *, char *, char *);
153 143
154 144 int
155 145 main(int argc, char **argv)
156 146 {
157 147 int cc;
158 148 struct mnttab mget;
159 149 char *mname, *is_special;
160 150 int fscnt;
161 151 mountent_t *mp;
162 152
163 153 (void) setlocale(LC_ALL, "");
164 154
165 155 #if !defined(TEXT_DOMAIN)
166 156 #define TEXT_DOMAIN "SYS_TEST"
167 157 #endif
168 158 (void) textdomain(TEXT_DOMAIN);
169 159
170 160 myname = strrchr(argv[0], '/');
171 161 if (myname)
172 162 myname++;
173 163 else
174 164 myname = argv[0];
175 165
176 166 /*
177 167 * Process the args.
178 168 * "-d" for compatibility
179 169 */
180 170 while ((cc = getopt(argc, argv, "ado:Vf?")) != -1)
181 171 switch (cc) {
182 172 case 'a':
183 173 aflg++;
184 174 break;
185 175 #ifdef DEBUG
186 176 case 'd':
187 177 dflg++;
188 178 break;
189 179 #endif
190 180
191 181 case '?':
192 182 usage();
193 183 break;
194 184 case 'o':
195 185 if (oflg)
196 186 usage();
197 187 else {
198 188 oflg++;
199 189 oarg = optarg;
200 190 }
201 191 break;
202 192 case 'f':
203 193 fflg++;
204 194 break;
205 195 case 'V':
206 196 if (Vflg)
207 197 usage();
208 198 else
209 199 Vflg++;
210 200 break;
211 201 default:
212 202 usage();
213 203 break;
214 204 }
215 205
216 206 fscnt = argc - optind;
217 207 if (!aflg && fscnt != 1)
218 208 usage();
219 209
220 210 /* copy '--' to specific */
221 211 if (strcmp(argv[optind-1], "--") == 0)
222 212 dashflg++;
223 213
224 214 /*
225 215 * mnttab may be a symlink to a file in another file system.
226 216 * This happens during install when / is mounted read-only
227 217 * and /etc/mnttab is symlinked to a file in /tmp.
228 218 * If this is the case, we need to follow the symlink to the
229 219 * read-write file itself so that the subsequent mnttab.temp
230 220 * open and rename will work.
231 221 */
232 222 if (realpath(MNTTAB, mnttab) == NULL) {
233 223 strcpy(mnttab, MNTTAB);
234 224 }
235 225
236 226 /*
237 227 * bugid 1205242
238 228 * call the realpath() here, so that if the user is
239 229 * trying to umount an autofs directory, the directory
240 230 * is forced to mount.
241 231 */
242 232
243 233 mname = argv[optind];
244 234 is_special = realpath(mname, resolve);
245 235
246 236 /*
247 237 * Read the whole mnttab into memory.
248 238 */
249 239 mntll = getmntall();
250 240
251 241 if (aflg && fscnt != 1)
252 242 exit(parumount(argv + optind, fscnt));
253 243
254 244 aflg = 0;
255 245
256 246 mntnull(&mget);
257 247 if (listlength == 0) {
258 248 fprintf(stderr, gettext(
259 249 "%s: warning: no entries found in %s\n"),
260 250 myname, mnttab);
261 251 mget.mnt_mountp = mname; /* assume mount point */
262 252 no_mnttab++;
263 253 doexec(&mget);
264 254 exit(0);
265 255 }
266 256
267 257 mp = NULL;
268 258
269 259 /*
270 260 * if realpath fails, it can't be a mount point, so we'll
271 261 * go straight to the code that treats the arg as a special.
272 262 * if realpath succeeds, it could be a special or a mount point;
273 263 * we'll start by assuming it's a mount point, and if it's not,
274 264 * try to treat it as a special.
275 265 */
276 266 if (is_special != NULL) {
277 267 /*
278 268 * if this succeeds,
279 269 * we'll have the appropriate record; if it fails
280 270 * we'll assume the arg is a special of some sort
281 271 */
282 272 mp = getmntlast(mntll, NULL, resolve);
283 273 }
284 274 /*
285 275 * Since stackable mount is allowed (RFE 2001535),
286 276 * we will un-mount the last entry in the MNTTAB that matches.
287 277 */
288 278 if (mp == NULL) {
289 279 /*
290 280 * Perhaps there is a bogus mnttab entry that
291 281 * can't be resolved:
292 282 */
293 283 if ((mp = getmntlast(mntll, NULL, mname)) == NULL)
294 284 /*
295 285 * assume it's a device (special) now
296 286 */
297 287 mp = getmntlast(mntll, mname, NULL);
298 288 if (mp) {
299 289 /*
300 290 * Found it.
301 291 * This is a device. Now we want to know if
302 292 * it stackmounted on by something else.
303 293 * The original fix for bug 1103850 has a
304 294 * problem with lockfs (bug 1119731). This
305 295 * is a revised method.
306 296 */
307 297 mountent_t *lmp;
308 298 lmp = getmntlast(mntll, NULL, mp->ment.mnt_mountp);
309 299
310 300 if (lmp && strcmp(lmp->ment.mnt_special,
311 301 mp->ment.mnt_special)) {
312 302 errno = EBUSY;
313 303 rpterr(mname);
314 304 exit(1);
315 305 }
316 306 } else {
317 307 fprintf(stderr, gettext(
318 308 "%s: warning: %s not in mnttab\n"),
319 309 myname, mname);
320 310 if (Vflg)
321 311 exit(1);
322 312 /*
323 313 * same error as mount -V
324 314 * would give for unknown
325 315 * mount point
326 316 */
327 317 mget.mnt_special = mget.mnt_mountp = mname;
328 318 }
329 319 }
330 320
331 321 if (mp)
332 322 doexec(&mp->ment);
333 323 else
334 324 doexec(&mget);
335 325
336 326 return (0);
337 327 }
338 328
339 329 void
340 330 doexec(struct mnttab *ment)
341 331 {
342 332 int ret;
343 333
344 334 #ifdef DEBUG
345 335 if (dflg)
346 336 fprintf(stderr, "%d: umounting %s\n",
347 337 getpid(), ment->mnt_mountp);
348 338 #endif
349 339
350 340 /* try to exec the dependent portion */
351 341 if ((ment->mnt_fstype != NULL) || Vflg) {
352 342 char full_path[FULLPATH_MAX];
353 343 char alter_path[FULLPATH_MAX];
354 344 char *newargv[ARGV_MAX];
355 345 int ii;
356 346
357 347 if (strlen(ment->mnt_fstype) > (size_t)FSTYPE_MAX) {
358 348 fprintf(stderr, gettext(
359 349 "%s: FSType %s exceeds %d characters\n"),
360 350 myname, ment->mnt_fstype, FSTYPE_MAX);
361 351 exit(1);
362 352 }
363 353
364 354 /* build the full pathname of the fstype dependent command. */
365 355 sprintf(full_path, "%s/%s/%s", fs_path, ment->mnt_fstype,
366 356 myname);
367 357 sprintf(alter_path, "%s/%s/%s", alt_path, ment->mnt_fstype,
368 358 myname);
369 359
370 360 /*
371 361 * create the new arg list, and end the list with a
372 362 * null pointer
373 363 */
374 364 ii = 2;
375 365 if (oflg) {
376 366 newargv[ii++] = "-o";
377 367 newargv[ii++] = oarg;
378 368 }
379 369 if (dashflg) {
380 370 newargv[ii++] = "--";
381 371 }
382 372 if (fflg) {
383 373 newargv[ii++] = "-f";
384 374 }
385 375 newargv[ii++] = (ment->mnt_mountp)
386 376 ? ment->mnt_mountp : ment->mnt_special;
387 377 newargv[ii] = NULL;
388 378
389 379 /* set the new argv[0] to the filename */
390 380 newargv[1] = myname;
391 381
392 382 if (Vflg) {
393 383 printf("%s", myname);
394 384 for (ii = 2; newargv[ii]; ii++)
395 385 printf(" %s", newargv[ii]);
396 386 printf("\n");
397 387 fflush(stdout);
398 388 exit(0);
399 389 }
400 390
401 391 /* Try to exec the fstype dependent umount. */
402 392 execv(full_path, &newargv[1]);
403 393 if (errno == ENOEXEC) {
404 394 newargv[0] = "sh";
405 395 newargv[1] = full_path;
406 396 execv("/sbin/sh", &newargv[0]);
407 397 }
408 398 newargv[1] = myname;
409 399 execv(alter_path, &newargv[1]);
410 400 if (errno == ENOEXEC) {
411 401 newargv[0] = "sh";
412 402 newargv[1] = alter_path;
413 403 execv("/sbin/sh", &newargv[0]);
414 404 }
415 405 /* exec failed */
416 406 if (errno != ENOENT) {
417 407 fprintf(stderr, gettext("umount: cannot execute %s\n"),
418 408 full_path);
419 409 exit(1);
420 410 }
421 411 }
422 412 /*
423 413 * No fstype independent executable then. We'll go generic
424 414 * from here.
425 415 */
426 416
427 417 /* don't use -o with generic */
428 418 if (oflg) {
429 419 fprintf(stderr, gettext(
430 420 "%s: %s specific umount does not exist;"
431 421 " -o suboption ignored\n"),
432 422 myname, ment->mnt_fstype ? ment->mnt_fstype : "<null>");
433 423 }
434 424
435 425 signal(SIGHUP, SIG_IGN);
436 426 signal(SIGQUIT, SIG_IGN);
437 427 signal(SIGINT, SIG_IGN);
438 428 /*
439 429 * Try to umount the mountpoint.
440 430 * If that fails, try the corresponding special.
441 431 * (This ordering is necessary for nfs umounts.)
442 432 * (for remote resources: if the first umount returns EBUSY
443 433 * don't call umount again - umount() with a resource name
444 434 * will return a misleading error to the user
445 435 */
446 436 if (fflg) {
447 437 if (((ret = umount2(ment->mnt_mountp, MS_FORCE)) < 0) &&
448 438 (errno != EBUSY && errno != ENOTSUP &&
449 439 errno != EPERM))
450 440 ret = umount2(ment->mnt_special, MS_FORCE);
451 441 } else {
452 442 if (((ret = umount2(ment->mnt_mountp, 0)) < 0) &&
453 443 (errno != EBUSY) && (errno != EPERM))
454 444 ret = umount2(ment->mnt_special, 0);
455 445 }
456 446
457 447 if (ret < 0) {
458 448 rpterr(ment->mnt_mountp);
459 449 if (errno != EINVAL && errno != EFAULT)
460 450 exit(1);
461 451
462 452 exitcode = 1;
463 453 }
464 454
465 455 exit(exitcode);
466 456 }
467 457
468 458 void
469 459 rpterr(char *sp)
470 460 {
471 461 switch (errno) {
472 462 case EPERM:
473 463 fprintf(stderr, gettext("%s: permission denied\n"), myname);
474 464 break;
475 465 case ENXIO:
476 466 fprintf(stderr, gettext("%s: %s no device\n"), myname, sp);
477 467 break;
478 468 case ENOENT:
479 469 fprintf(stderr,
480 470 gettext("%s: %s no such file or directory\n"),
481 471 myname, sp);
482 472 break;
483 473 case EINVAL:
484 474 fprintf(stderr, gettext("%s: %s not mounted\n"), myname, sp);
485 475 break;
486 476 case EBUSY:
487 477 fprintf(stderr, gettext("%s: %s busy\n"), myname, sp);
488 478 break;
489 479 case ENOTBLK:
490 480 fprintf(stderr,
491 481 gettext("%s: %s block device required\n"), myname, sp);
492 482 break;
493 483 case ECOMM:
494 484 fprintf(stderr,
495 485 gettext("%s: warning: broken link detected\n"), myname);
496 486 break;
497 487 default:
498 488 perror(myname);
499 489 fprintf(stderr, gettext("%s: cannot unmount %s\n"), myname, sp);
500 490 }
501 491 }
502 492
503 493 void
504 494 usage(void)
505 495 {
506 496 fprintf(stderr, gettext(
507 497 "Usage:\n%s [-f] [-V] [-o specific_options] {special | mount-point}\n"),
508 498 myname);
509 499 fprintf(stderr, gettext(
510 500 "%s -a [-f] [-V] [-o specific_options] [mount_point ...]\n"), myname);
511 501 exit(1);
512 502 }
513 503
514 504 void
515 505 mnterror(int flag)
516 506 {
517 507 switch (flag) {
518 508 case MNT_TOOLONG:
519 509 fprintf(stderr,
520 510 gettext("%s: line in mnttab exceeds %d characters\n"),
521 511 myname, MNT_LINE_MAX-2);
522 512 break;
523 513 case MNT_TOOFEW:
524 514 fprintf(stderr,
525 515 gettext("%s: line in mnttab has too few entries\n"),
526 516 myname);
527 517 break;
528 518 default:
529 519 break;
530 520 }
531 521 }
532 522
533 523 /*
534 524 * Search the mlist linked list for the
535 525 * first match of specp or mntp. The list is expected to be in reverse
536 526 * order of /etc/mnttab.
537 527 * If both are specified, then both have to match.
538 528 * Returns the (mountent_t *) of the match, otherwise returns NULL.
539 529 */
540 530 mountent_t *
541 531 getmntlast(mountent_t *mlist, char *specp, char *mntp)
542 532 {
543 533 int mfound, sfound;
544 534
545 535 for (/* */; mlist; mlist = mlist->link) {
546 536 mfound = sfound = 0;
547 537 if (mntp && (strcmp(mlist->ment.mnt_mountp, mntp) == 0)) {
548 538 if (specp == NULL)
549 539 return (mlist);
550 540 mfound++;
551 541 }
552 542 if (specp && (strcmp(mlist->ment.mnt_special, specp) == 0)) {
553 543 if (mntp == NULL)
554 544 return (mlist);
555 545 sfound++;
556 546 }
557 547 if (mfound && sfound)
558 548 return (mlist);
559 549 }
560 550 return (NULL);
561 551 }
562 552
563 553
564 554
565 555 /*
566 556 * Perform the parallel version of umount. Returns 0 if no errors occurred,
567 557 * non zero otherwise.
568 558 */
569 559 int
570 560 parumount(char **mntlist, int count)
571 561 {
572 562 int maxfd = OPEN_MAX;
573 563 struct rlimit rl;
574 564 mountent_t **mntarray, **ml, *mp;
575 565
576 566 /*
577 567 * If no mount points are specified and none were found in mnttab,
578 568 * then end it all here.
579 569 */
580 570 if (count == 0 && mntll == NULL)
581 571 return (0);
582 572
583 573 /*
584 574 * This is the process scaling section. After running a series
585 575 * of tests based on the number of simultaneous processes and
586 576 * processors available, optimum performance was achieved near or
587 577 * at (PROCN * 2).
588 578 */
589 579 if ((maxrun = sysconf(_SC_NPROCESSORS_ONLN)) == -1)
590 580 maxrun = 4;
591 581 else
592 582 maxrun = maxrun * 2 + 1;
593 583
594 584 if (getrlimit(RLIMIT_NOFILE, &rl) == 0) {
595 585 rl.rlim_cur = rl.rlim_max;
596 586 if (setrlimit(RLIMIT_NOFILE, &rl) == 0)
597 587 maxfd = (int)rl.rlim_cur;
598 588 (void) enable_extended_FILE_stdio(-1, -1);
599 589 }
600 590
601 591 /*
602 592 * The parent needs to maintain 3 of its own fd's, plus 2 for
603 593 * each child (the stdout and stderr pipes).
604 594 */
605 595 maxfd = (maxfd / 2) - 6; /* 6 takes care of temporary */
606 596 /* periods of open fds */
607 597 if (maxfd < maxrun)
608 598 maxrun = maxfd;
609 599 if (maxrun < 4)
610 600 maxrun = 4; /* sanity check */
611 601
612 602 mntarray = make_mntarray(mntlist, count);
613 603
614 604 if (listlength == 0) {
615 605 if (count == 0) /* not an error, just none found */
616 606 return (0);
617 607 fprintf(stderr, gettext("%s: no valid entries found in %s\n"),
618 608 myname, mnttab);
619 609 return (1);
620 610 }
621 611
622 612 /*
623 613 * Sort the entries based on their mount level only if lofs's are
624 614 * not present.
625 615 */
626 616 if (lofscnt == 0) {
627 617 qsort((void *)mntarray, listlength, sizeof (mountent_t *),
628 618 mcompar);
629 619 /*
630 620 * If we do not detect a lofs by now, we never will.
631 621 */
632 622 lofscnt = -1;
633 623 }
634 624 /*
635 625 * Now link them up so that a given pid is easier to find when
636 626 * we go to clean up after they are done.
637 627 */
638 628 mntll = mntarray[0];
639 629 for (ml = mntarray; mp = *ml; /* */)
640 630 mp->link = *++ml;
641 631
642 632 /*
643 633 * Try to handle interrupts in a reasonable way.
644 634 */
645 635 sigset(SIGHUP, cleanup);
646 636 sigset(SIGQUIT, cleanup);
647 637 sigset(SIGINT, cleanup);
648 638
649 639 do_umounts(mntarray); /* do the umounts */
650 640 return (exitcode);
651 641 }
652 642
653 643 /*
654 644 * Returns a mountent_t array based on mntlist. If mntlist is NULL, then
655 645 * it returns all mnttab entries with a few exceptions. Sets the global
656 646 * variable listlength to the number of entries in the array.
657 647 */
658 648 mountent_t **
659 649 make_mntarray(char **mntlist, int count)
660 650 {
661 651 mountent_t *mp, **mpp;
662 652 int ndx;
663 653 char *cp;
664 654
665 655 if (count > 0)
666 656 listlength = count;
667 657
668 658 mpp = (mountent_t **)malloc(sizeof (*mp) * (listlength + 1));
669 659 if (mpp == NULL)
670 660 nomem();
671 661
672 662 if (count == 0) {
673 663 if (mntll == NULL) { /* no entries? */
674 664 listlength = 0;
675 665 return (NULL);
676 666 }
677 667 /*
678 668 * No mount list specified: take all mnttab mount points
679 669 * except for a few cases.
680 670 */
681 671 for (ndx = 0, mp = mntll; mp; mp = mp->link) {
682 672 if (fsstrinlist(mp->ment.mnt_mountp, keeplist))
683 673 continue;
684 674 mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp);
685 675 if (mp->ment.mnt_fstype &&
686 676 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
687 677 lofscnt++;
688 678
689 679 mpp[ndx++] = mp;
690 680 }
691 681 mpp[ndx] = NULL;
692 682 listlength = ndx;
693 683 return (mpp);
694 684 }
695 685
696 686 /*
697 687 * A list of mount points was specified on the command line.
698 688 * Build an array out of these.
699 689 */
700 690 for (ndx = 0; count--; ) {
701 691 cp = *mntlist++;
702 692 if (realpath(cp, resolve) == NULL) {
703 693 fprintf(stderr,
704 694 gettext("%s: warning: can't resolve %s\n"),
705 695 myname, cp);
706 696 exitcode = 1;
707 697 mp = getmntlast(mntll, NULL, cp); /* try anyways */
708 698 } else
709 699 mp = getmntlast(mntll, NULL, resolve);
710 700 if (mp == NULL) {
711 701 struct mnttab mnew;
712 702 /*
713 703 * Then we've reached the end without finding
714 704 * what we are looking for, but we still have to
715 705 * try to umount it: append it to mntarray.
716 706 */
717 707 fprintf(stderr, gettext(
718 708 "%s: warning: %s not found in %s\n"),
719 709 myname, resolve, mnttab);
720 710 exitcode = 1;
721 711 mntnull(&mnew);
722 712 mnew.mnt_special = mnew.mnt_mountp = strdup(resolve);
723 713 if (mnew.mnt_special == NULL)
724 714 nomem();
725 715 mp = new_mountent(&mnew);
726 716 }
727 717 if (mp->ment.mnt_fstype &&
728 718 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
729 719 lofscnt++;
730 720
731 721 mp->mlevel = fsgetmlevel(mp->ment.mnt_mountp);
732 722 mpp[ndx++] = mp;
733 723 }
734 724 mpp[ndx] = NULL;
735 725 listlength = ndx;
736 726 return (mpp);
737 727 }
738 728
739 729 /*
740 730 * Returns the tail of a linked list of all mnttab entries. I.e, it's faster
741 731 * to return the mnttab in reverse order.
742 732 * Sets listlength to the number of entries in the list.
743 733 * Returns NULL if none are found.
744 734 */
745 735 mountent_t *
746 736 getmntall(void)
747 737 {
748 738 FILE *fp;
749 739 mountent_t *mtail;
750 740 int cnt = 0, ret;
751 741 struct mnttab mget;
752 742
753 743 if ((fp = fopen(mnttab, "r")) == NULL) {
754 744 fprintf(stderr, gettext("%s: warning cannot open %s\n"),
755 745 myname, mnttab);
756 746 return (0);
757 747 }
758 748 mtail = NULL;
759 749
760 750 while ((ret = getmntent(fp, &mget)) != -1) {
761 751 mountent_t *mp;
762 752
763 753 if (ret > 0) {
764 754 mnterror(ret);
765 755 continue;
766 756 }
767 757
768 758 mp = new_mountent(&mget);
769 759 mp->link = mtail;
770 760 mtail = mp;
771 761 cnt++;
772 762 }
773 763 fclose(fp);
774 764 if (mtail == NULL) {
775 765 listlength = 0;
776 766 return (NULL);
777 767 }
778 768 listlength = cnt;
779 769 return (mtail);
780 770 }
781 771
782 772 void
783 773 do_umounts(mountent_t **mntarray)
784 774 {
785 775 mountent_t *mp, *mpprev, **ml = mntarray;
786 776 int cnt = listlength;
787 777
788 778 /*
789 779 * Main loop for the forked children:
790 780 */
791 781 for (mpprev = *ml; mp = *ml; mpprev = mp, ml++, cnt--) {
792 782 pid_t pid;
793 783
794 784 /*
795 785 * Check to see if we cross a mount level: e.g.,
796 786 * /a/b/c -> /a/b. If so, we need to wait for all current
797 787 * umounts to finish before umounting the rest.
798 788 *
799 789 * Also, we unmount serially as long as there are lofs's
800 790 * to mount to avoid improper umount ordering.
801 791 */
802 792 if (mp->mlevel < mpprev->mlevel || lofscnt > 0)
803 793 while (nrun > 0 && (dowait() != -1))
804 794 ;
805 795
806 796 if (lofscnt == 0) {
807 797 /*
808 798 * We can now go to parallel umounting.
809 799 */
810 800 qsort((void *)ml, cnt, sizeof (mountent_t *), mcompar);
↓ open down ↓ |
708 lines elided |
↑ open up ↑ |
811 801 mp = *ml; /* possible first entry */
812 802 lofscnt--; /* so we don't do this again */
813 803 }
814 804
815 805 while (setup_iopipe(mp) == -1 && (dowait() != -1))
816 806 ;
817 807
818 808 while (nrun >= maxrun && (dowait() != -1)) /* throttle */
819 809 ;
820 810
821 -#ifdef CACHEFS_BUG
822 - /*
823 - * If this is the back file system, then let cachefs/umount
824 - * unmount it.
825 - */
826 - if (strstr(mp->ment.mnt_mountp, BACKMNT_NAME))
827 - continue;
828 -
829 -
830 - if (mp->ment.mnt_fstype &&
831 - (strcmp(mp->ment.mnt_fstype, "cachefs") == 0)) {
832 - while (cachefs_running && (dowait() != -1))
833 - ;
834 - cachefs_running = 1;
835 - }
836 -#endif
837 -
838 811 if ((pid = fork()) == -1) {
839 812 perror("fork");
840 813 cleanup(-1);
841 814 /* not reached */
842 815 }
843 816 #ifdef DEBUG
844 817 if (dflg && pid > 0) {
845 818 fprintf(stderr, "parent %d: umounting %d %s\n",
846 819 getpid(), pid, mp->ment.mnt_mountp);
847 820 }
848 821 #endif
849 822 if (pid == 0) { /* child */
850 823 signal(SIGHUP, SIG_IGN);
851 824 signal(SIGQUIT, SIG_IGN);
852 825 signal(SIGINT, SIG_IGN);
853 826 setup_output(mp);
854 827 doexec(&mp->ment);
855 828 perror("exec");
856 829 exit(1);
857 830 }
858 831
859 832 /* parent */
860 833 (void) close(mp->sopipe[WRPIPE]);
861 834 (void) close(mp->sepipe[WRPIPE]);
862 835 mp->pid = pid;
863 836 nrun++;
864 837 }
865 838 cleanup(0);
866 839 }
867 840
868 841 /*
869 842 * cleanup the existing children and exit with an error
870 843 * if asig != 0.
871 844 */
872 845 void
873 846 cleanup(int asig)
874 847 {
875 848 /*
876 849 * Let the stragglers finish.
877 850 */
878 851 while (nrun > 0 && (dowait() != -1))
879 852 ;
880 853 if (asig != 0)
881 854 exit(1);
882 855 }
883 856
884 857
885 858 /*
886 859 * Waits for 1 child to die.
887 860 *
888 861 * Returns -1 if no children are left to wait for.
889 862 * Returns 0 if a child died without an error.
890 863 * Returns 1 if a child died with an error.
891 864 * Sets the global exitcode if an error occurred.
892 865 */
893 866 int
894 867 dowait(void)
895 868 {
896 869 int wstat, child, ret;
897 870 mountent_t *mp, *prevp;
898 871
899 872 if ((child = wait(&wstat)) == -1)
900 873 return (-1);
901 874
902 875 if (WIFEXITED(wstat)) /* this should always be true */
903 876 ret = WEXITSTATUS(wstat);
904 877 else
905 878 ret = 1; /* assume some kind of error */
906 879 nrun--;
907 880 if (ret)
908 881 exitcode = 1;
909 882
910 883 /*
911 884 * Find our child so we can process its std output, if any.
912 885 * This search gets smaller and smaller as children are cleaned
913 886 * up.
914 887 */
915 888 for (prevp = NULL, mp = mntll; mp; mp = mp->link) {
916 889 if (mp->pid != child) {
917 890 prevp = mp;
918 891 continue;
919 892 }
920 893 /*
921 894 * Found: let's remove it from this list.
922 895 */
923 896 if (prevp) {
924 897 prevp->link = mp->link;
925 898 mp->link = NULL;
926 899 }
927 900 break;
928 901 }
929 902
930 903 if (mp == NULL) {
931 904 /*
932 905 * This should never happen.
933 906 */
934 907 #ifdef DEBUG
935 908 fprintf(stderr, gettext(
936 909 "%s: unknown child %d\n"), myname, child);
↓ open down ↓ |
89 lines elided |
↑ open up ↑ |
937 910 #endif
938 911 exitcode = 1;
939 912 return (1);
940 913 }
941 914 doio(mp); /* Any output? */
942 915
943 916 if (mp->ment.mnt_fstype &&
944 917 (strcmp(mp->ment.mnt_fstype, MNTTYPE_LOFS) == 0))
945 918 lofscnt--;
946 919
947 -#ifdef CACHEFS_BUG
948 - if (mp->ment.mnt_fstype &&
949 - (strcmp(mp->ment.mnt_fstype, "cachefs") == 0))
950 - cachefs_running = 0;
951 -#endif
952 -
953 920 return (ret);
954 921 }
955 922
956 923 static const mountent_t zmount = { 0 };
957 924
958 925 mountent_t *
959 926 new_mountent(struct mnttab *ment)
960 927 {
961 928 mountent_t *new;
962 929
963 930 new = (mountent_t *)malloc(sizeof (*new));
964 931 if (new == NULL)
965 932 nomem();
966 933
967 934 *new = zmount;
968 935 if (ment->mnt_special &&
969 936 (new->ment.mnt_special = strdup(ment->mnt_special)) == NULL)
970 937 nomem();
971 938 if (ment->mnt_mountp &&
972 939 (new->ment.mnt_mountp = strdup(ment->mnt_mountp)) == NULL)
973 940 nomem();
974 941 if (ment->mnt_fstype &&
975 942 (new->ment.mnt_fstype = strdup(ment->mnt_fstype)) == NULL)
976 943 nomem();
977 944 return (new);
978 945 }
979 946
980 947
981 948 /*
982 949 * Sort in descending order of "mount level". For example, /a/b/c is
983 950 * placed before /a/b .
984 951 */
985 952 int
986 953 mcompar(const void *a, const void *b)
987 954 {
988 955 mountent_t *a1, *b1;
989 956
990 957 a1 = *(mountent_t **)a;
991 958 b1 = *(mountent_t **)b;
992 959 return (b1->mlevel - a1->mlevel);
993 960 }
994 961
995 962 /*
996 963 * The purpose of this routine is to form stdout and stderr
997 964 * pipes for the children's output. The parent then reads and writes it
998 965 * out it serially in order to ensure that the output is
999 966 * not garbled.
1000 967 */
1001 968
1002 969 int
1003 970 setup_iopipe(mountent_t *mp)
1004 971 {
1005 972 /*
1006 973 * Make a stdout and stderr pipe. This should never fail.
1007 974 */
1008 975 if (pipe(mp->sopipe) == -1)
1009 976 return (-1);
1010 977 if (pipe(mp->sepipe) == -1) {
1011 978 (void) close(mp->sopipe[RDPIPE]);
1012 979 (void) close(mp->sopipe[WRPIPE]);
1013 980 return (-1);
1014 981 }
1015 982 /*
1016 983 * Don't block on an empty pipe.
1017 984 */
1018 985 (void) fcntl(mp->sopipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1019 986 (void) fcntl(mp->sepipe[RDPIPE], F_SETFL, O_NDELAY|O_NONBLOCK);
1020 987 return (0);
1021 988 }
1022 989
1023 990 /*
1024 991 * Called by a child to attach its stdout and stderr to the write side of
1025 992 * the pipes.
1026 993 */
1027 994 void
1028 995 setup_output(mountent_t *mp)
1029 996 {
1030 997 (void) close(fileno(stdout));
1031 998 (void) dup(mp->sopipe[WRPIPE]);
1032 999 (void) close(mp->sopipe[WRPIPE]);
1033 1000
1034 1001 (void) close(fileno(stderr));
1035 1002 (void) dup(mp->sepipe[WRPIPE]);
1036 1003 (void) close(mp->sepipe[WRPIPE]);
1037 1004 }
1038 1005
1039 1006 /*
1040 1007 * Parent uses this to print any stdout or stderr output issued by
1041 1008 * the child.
1042 1009 */
1043 1010 static void
1044 1011 doio(mountent_t *mp)
1045 1012 {
1046 1013 int bytes;
1047 1014
1048 1015 while ((bytes = read(mp->sepipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1049 1016 write(fileno(stderr), ibuf, bytes);
1050 1017 while ((bytes = read(mp->sopipe[RDPIPE], ibuf, sizeof (ibuf))) > 0)
1051 1018 write(fileno(stdout), ibuf, bytes);
1052 1019
1053 1020 (void) close(mp->sopipe[RDPIPE]);
1054 1021 (void) close(mp->sepipe[RDPIPE]);
1055 1022 }
1056 1023
1057 1024 void
1058 1025 nomem(void)
1059 1026 {
1060 1027 fprintf(stderr, gettext("%s: out of memory\n"), myname);
1061 1028 /*
1062 1029 * Let the stragglers finish.
1063 1030 */
1064 1031 while (nrun > 0 && (dowait() != -1))
1065 1032 ;
1066 1033 exit(1);
1067 1034 }
↓ open down ↓ |
105 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX