]> git.ipfire.org Git - thirdparty/util-linux.git/blame - mount/umount.c
Imported from util-linux-2.12o tarball.
[thirdparty/util-linux.git] / mount / umount.c
CommitLineData
6dbe3af9 1/*
d162fcb5 2 * umount(8) for Linux 0.99 - jrs, 1993
6dbe3af9
KZ
3 */
4
66ee8158 5#include <stdio.h>
fd6b7a7f
KZ
6#include <unistd.h>
7#include <getopt.h>
8#include <string.h>
9#include <errno.h>
66ee8158 10#include <ctype.h>
fd6b7a7f 11#include <sys/stat.h>
d162fcb5 12#include <sys/wait.h>
fd6b7a7f
KZ
13#include <sys/mount.h>
14#include "mount_constants.h"
6dbe3af9 15#include "sundries.h"
5c36a0eb 16#include "getusername.h"
fd6b7a7f
KZ
17#include "lomount.h"
18#include "loop.h"
19#include "fstab.h"
364cda48 20#include "env.h"
7eda085c 21#include "nls.h"
6dbe3af9
KZ
22
23#ifdef HAVE_NFS
24#include <sys/socket.h>
25#include <sys/time.h>
26#include <netdb.h>
27#include <rpc/rpc.h>
28#include <rpc/pmap_clnt.h>
29#include <rpc/pmap_prot.h>
fd6b7a7f 30#include "nfsmount.h"
6dbe3af9
KZ
31#include <arpa/inet.h>
32#endif
33
364cda48 34#if defined(MNT_FORCE) && !defined(__sparc__) && !defined(__arm__)
5c36a0eb
KZ
35/* Interesting ... it seems libc knows about MNT_FORCE and presumably
36 about umount2 as well -- need not do anything */
37#else /* MNT_FORCE */
38
39/* Does the present kernel source know about umount2? */
40#include <linux/unistd.h>
41#ifdef __NR_umount2
eb63b9b8
KZ
42
43static int umount2(const char *path, int flags);
44
5c36a0eb 45_syscall2(int, umount2, const char *, path, int, flags);
eb63b9b8 46
5c36a0eb 47#else /* __NR_umount2 */
eb63b9b8 48
5c36a0eb
KZ
49static int
50umount2(const char *path, int flags) {
7eda085c 51 fprintf(stderr, _("umount: compiled without support for -f\n"));
5c36a0eb
KZ
52 errno = ENOSYS;
53 return -1;
54}
55#endif /* __NR_umount2 */
56
eb63b9b8 57#if !defined(MNT_FORCE)
5c36a0eb
KZ
58/* dare not try to include <linux/mount.h> -- lots of errors */
59#define MNT_FORCE 1
eb63b9b8 60#endif
5c36a0eb
KZ
61
62#endif /* MNT_FORCE */
63
e8f26419
KZ
64#if !defined(MNT_DETACH)
65#define MNT_DETACH 2
66#endif
67
d162fcb5
KZ
68
69/* True if we are allowed to call /sbin/umount.${FSTYPE} */
70int external_allowed = 1;
71
5c36a0eb 72/* Nonzero for force umount (-f). There is kernel support since 2.1.116. */
6dbe3af9 73int force = 0;
6dbe3af9 74
e8f26419
KZ
75/* Nonzero for lazy umount (-l). There is kernel support since 2.4.11. */
76int lazy = 0;
77
fd6b7a7f
KZ
78/* When umount fails, attempt a read-only remount (-r). */
79int remount = 0;
80
81/* Don't write a entry in /etc/mtab (-n). */
82int nomtab = 0;
83
66ee8158
KZ
84/* Call losetup -d for each unmounted loop device. */
85int delloop = 0;
86
87/* Nonzero for chatty (-v). */
6dbe3af9
KZ
88int verbose = 0;
89
90/* True if ruid != euid. */
91int suid = 0;
92
d162fcb5
KZ
93/*
94 * check_special_umountprog()
95 * If there is a special umount program for this type, exec it.
96 * returns: 0: no exec was done, 1: exec was done, status has result
97 */
364cda48 98static int
d162fcb5
KZ
99check_special_umountprog(const char *spec, const char *node,
100 const char *type, int *status) {
101 char umountprog[120];
102 struct stat statbuf;
103 int res;
104
105 if (!external_allowed)
106 return 0;
107
108 if (type && strlen(type) < 100) {
109 sprintf(umountprog, "/sbin/umount.%s", type);
110 if (stat(umountprog, &statbuf) == 0) {
111 res = fork();
112 if (res == 0) {
113 char *umountargs[8];
114 int i = 0;
115
116 setuid(getuid());
117 setgid(getgid());
118 umountargs[i++] = umountprog;
119 umountargs[i++] = xstrdup(node);
120 if (nomtab)
121 umountargs[i++] = "-n";
122 if (lazy)
123 umountargs[i++] = "-l";
124 if (force)
125 umountargs[i++] = "-f";
126 if (verbose)
127 umountargs[i++] = "-v";
128 if (remount)
129 umountargs[i++] = "-r";
130 umountargs[i] = NULL;
131 execv(umountprog, umountargs);
132 exit(1); /* exec failed */
133 } else if (res != -1) {
134 int st;
135 wait(&st);
136 *status = (WIFEXITED(st) ? WEXITSTATUS(st)
137 : EX_SYSERR);
138 return 1;
139 } else {
140 int errsv = errno;
141 error(_("umount: cannot fork: %s"),
142 strerror(errsv));
143 }
144 }
145 }
146 return 0;
364cda48 147}
364cda48 148
6dbe3af9
KZ
149#ifdef HAVE_NFS
150static int xdr_dir(XDR *xdrsp, char *dirp)
151{
152 return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
153}
6dbe3af9 154
6dbe3af9 155static int
fd6b7a7f 156nfs_umount_rpc_call(const char *spec, const char *opts)
6dbe3af9 157{
6dbe3af9
KZ
158 register CLIENT *clp;
159 struct sockaddr_in saddr;
160 struct timeval pertry, try;
161 enum clnt_stat clnt_stat;
66ee8158 162 int port = 0;
6dbe3af9 163 int so = RPC_ANYSOCK;
6dbe3af9 164 struct hostent *hostp;
fd6b7a7f
KZ
165 char *hostname;
166 char *dirname;
167 char *p;
168
169 if (spec == NULL || (p = strchr(spec,':')) == NULL)
170 return 0;
171 hostname = xstrndup(spec, p-spec);
172 dirname = xstrdup(p+1);
173#ifdef DEBUG
7eda085c 174 printf(_("host: %s, directory: %s\n"), hostname, dirname);
fd6b7a7f
KZ
175#endif
176
177 if (opts && (p = strstr(opts, "addr="))) {
178 char *q;
179
180 free(hostname);
181 p += 5;
182 q = p;
183 while (*q && *q != ',') q++;
184 hostname = xstrndup(p,q-p);
185 }
186
66ee8158
KZ
187 if (opts && (p = strstr(opts, "mountport=")) && isdigit(*(p+10)))
188 port = atoi(p+10);
189
fd6b7a7f
KZ
190 if (hostname[0] >= '0' && hostname[0] <= '9')
191 saddr.sin_addr.s_addr = inet_addr(hostname);
2b6fc908 192 else {
fd6b7a7f 193 if ((hostp = gethostbyname(hostname)) == NULL) {
7eda085c 194 fprintf(stderr, _("umount: can't get address for %s\n"),
fd6b7a7f
KZ
195 hostname);
196 return 1;
2b6fc908
KZ
197 }
198 if (hostp->h_length > sizeof(struct in_addr)) {
7eda085c 199 fprintf(stderr, _("umount: got bad hostp->h_length\n"));
2b6fc908
KZ
200 hostp->h_length = sizeof(struct in_addr);
201 }
202 memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length);
203 }
fd6b7a7f
KZ
204
205 saddr.sin_family = AF_INET;
66ee8158 206 saddr.sin_port = htons(port);
fd6b7a7f
KZ
207 pertry.tv_sec = 3;
208 pertry.tv_usec = 0;
e8f26419
KZ
209 if (opts && (p = strstr(opts, "tcp"))) {
210 /* possibly: make sure option is not "notcp"
211 possibly: try udp if tcp fails */
212 if ((clp = clnttcp_create(&saddr, MOUNTPROG, MOUNTVERS,
213 &so, 0, 0)) == NULL) {
214 clnt_pcreateerror("Cannot MOUNTPROG RPC (tcp)");
215 return 1;
216 }
217 } else {
218 if ((clp = clntudp_create(&saddr, MOUNTPROG, MOUNTVERS,
219 pertry, &so)) == NULL) {
220 clnt_pcreateerror("Cannot MOUNTPROG RPC");
221 return 1;
222 }
fd6b7a7f
KZ
223 }
224 clp->cl_auth = authunix_create_default();
225 try.tv_sec = 20;
226 try.tv_usec = 0;
227 clnt_stat = clnt_call(clp, MOUNTPROC_UMNT,
228 (xdrproc_t) xdr_dir, dirname,
229 (xdrproc_t) xdr_void, (caddr_t) 0,
230 try);
231
232 if (clnt_stat != RPC_SUCCESS) {
233 clnt_perror(clp, "Bad UMNT RPC");
e8f26419 234 return 1;
fd6b7a7f
KZ
235 }
236 auth_destroy(clp->cl_auth);
237 clnt_destroy(clp);
238
e8f26419 239 return 0;
fd6b7a7f 240}
6dbe3af9 241#endif /* HAVE_NFS */
fd6b7a7f
KZ
242
243/* complain about a failed umount */
244static void complain(int err, const char *dev) {
245 switch (err) {
246 case ENXIO:
7eda085c 247 error (_("umount: %s: invalid block device"), dev); break;
fd6b7a7f 248 case EINVAL:
7eda085c 249 error (_("umount: %s: not mounted"), dev); break;
fd6b7a7f 250 case EIO:
7eda085c 251 error (_("umount: %s: can't write superblock"), dev); break;
fd6b7a7f
KZ
252 case EBUSY:
253 /* Let us hope fstab has a line "proc /proc ..."
254 and not "none /proc ..."*/
7eda085c 255 error (_("umount: %s: device is busy"), dev); break;
fd6b7a7f 256 case ENOENT:
7eda085c 257 error (_("umount: %s: not found"), dev); break;
fd6b7a7f 258 case EPERM:
7eda085c 259 error (_("umount: %s: must be superuser to umount"), dev); break;
fd6b7a7f 260 case EACCES:
7eda085c 261 error (_("umount: %s: block devices not permitted on fs"), dev); break;
fd6b7a7f 262 default:
7eda085c 263 error (_("umount: %s: %s"), dev, strerror (err)); break;
fd6b7a7f
KZ
264 }
265}
266
267/* Umount a single device. Return a status code, so don't exit
268 on a non-fatal error. We lock/unlock around each umount. */
269static int
270umount_one (const char *spec, const char *node, const char *type,
66ee8158
KZ
271 const char *opts, struct mntentchn *mc) {
272 int umnt_err, umnt_err2;
273 int isroot;
274 int res;
d162fcb5 275 int status;
66ee8158
KZ
276 const char *loopdev;
277
278 /* Special case for root. As of 0.99pl10 we can (almost) unmount root;
279 the kernel will remount it readonly so that we can carry on running
280 afterwards. The readonly remount is illegal if any files are opened
281 for writing at the time, so we can't update mtab for an unmount of
282 root. As it is only really a remount, this doesn't matter too
283 much. [sct May 29, 1993] */
284 isroot = (streq (node, "/") || streq (node, "root")
285 || streq (node, "rootfs"));
286 if (isroot)
287 nomtab++;
d162fcb5
KZ
288
289 /*
290 * Call umount.TYPE for types that require a separate umount program.
291 * All such special things must occur isolated in the types string.
292 */
293 if (check_special_umountprog(spec, node, type, &status))
294 return status;
6dbe3af9
KZ
295
296#ifdef HAVE_NFS
66ee8158
KZ
297 /* Ignore any RPC errors, so that you can umount the filesystem
298 if the server is down. */
299 if (strcasecmp(type, "nfs") == 0)
300 nfs_umount_rpc_call(spec, opts);
6dbe3af9 301#endif
6dbe3af9 302
66ee8158 303 umnt_err = umnt_err2 = 0;
e8f26419
KZ
304 if (lazy) {
305 res = umount2 (node, MNT_DETACH);
1d4ad1de
KZ
306 if (res < 0)
307 umnt_err = errno;
308 goto writemtab;
e8f26419 309 }
1d4ad1de 310
e8f26419
KZ
311 if (force) { /* only supported for NFS */
312 res = umount2 (node, MNT_FORCE);
66ee8158 313 if (res == -1) {
d03dd608 314 int errsv = errno;
66ee8158 315 perror("umount2");
d03dd608 316 errno = errsv;
66ee8158
KZ
317 if (errno == ENOSYS) {
318 if (verbose)
319 printf(_("no umount2, trying umount...\n"));
320 res = umount (node);
321 }
322 }
323 } else
324 res = umount (node);
325
326 if (res < 0) {
327 umnt_err = errno;
328 /* A device might have been mounted on a node that has since
329 been deleted or renamed, so if node fails, also try spec. */
330 /* Note that this is incorrect in case spec was mounted
331 several times. */
332 /* if (umnt_err == ENOENT || umnt_err == EINVAL) */
333 if (umnt_err != EBUSY && strcmp(node, spec)) {
334 if (verbose)
335 printf (_("could not umount %s - trying %s instead\n"),
336 node, spec);
337 res = umount (spec);
338 if (res < 0)
339 umnt_err2 = errno;
340 /* Do not complain about remote NFS mount points */
341 if (errno == ENOENT && index(spec, ':'))
342 umnt_err2 = 0;
343 }
344 }
345
346 if (res < 0 && remount && (umnt_err == EBUSY || umnt_err2 == EBUSY)) {
347 /* Umount failed - let us try a remount */
348 res = mount(spec, node, NULL,
349 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
350 if (res == 0) {
d26aa358 351 struct my_mntent remnt;
66ee8158
KZ
352 fprintf(stderr,
353 _("umount: %s busy - remounted read-only\n"),
354 spec);
355 remnt.mnt_type = remnt.mnt_fsname = NULL;
356 remnt.mnt_dir = xstrdup(node);
d162fcb5 357 remnt.mnt_opts = xstrdup("ro");
66ee8158
KZ
358 update_mtab(node, &remnt);
359 return 0;
360 } else if (errno != EBUSY) { /* hmm ... */
361 perror("remount");
362 fprintf(stderr,
363 _("umount: could not remount %s read-only\n"),
364 spec);
365 }
366 }
367
368 loopdev = 0;
369 if (res >= 0) {
370 /* Umount succeeded */
371 if (verbose)
372 printf (_("%s umounted\n"), spec);
373
374 /* Free any loop devices that we allocated ourselves */
375 if (mc) {
376 char *optl;
377
378 /* old style mtab line? */
379 if (streq(mc->m.mnt_type, "loop")) {
380 loopdev = spec;
381 goto gotloop;
382 }
383
384 /* new style mtab line? */
385 optl = mc->m.mnt_opts ? xstrdup(mc->m.mnt_opts) : "";
386 for (optl = strtok (optl, ","); optl;
387 optl = strtok (NULL, ",")) {
388 if (!strncmp(optl, "loop=", 5)) {
389 loopdev = optl+5;
390 goto gotloop;
391 }
392 }
393 } else {
394 /*
395 * If option "-o loop=spec" occurs in mtab,
396 * note the mount point, and delete mtab line.
397 */
398 if ((mc = getmntoptfile (spec)) != NULL)
399 node = mc->m.mnt_dir;
400 }
401
402 /* Also free loop devices when -d flag is given */
403 if (delloop && is_loop_device(spec))
404 loopdev = spec;
405 }
406 gotloop:
407 if (loopdev)
408 del_loop(loopdev);
409
1d4ad1de 410 writemtab:
66ee8158
KZ
411 if (!nomtab && mtab_is_writable() &&
412 (umnt_err == 0 || umnt_err == EINVAL || umnt_err == ENOENT)) {
413 update_mtab (node, NULL);
414 }
415
416 if (res >= 0)
417 return 0;
6dbe3af9 418
66ee8158
KZ
419 if (umnt_err2)
420 complain(umnt_err2, spec);
421 if (umnt_err && umnt_err != umnt_err2)
422 complain(umnt_err, node);
423 return 1;
6dbe3af9
KZ
424}
425
5c36a0eb 426/*
d26aa358
KZ
427 * umount_one_bw: unmount FILE that has last occurrence MC0
428 *
5c36a0eb
KZ
429 * Why this loop?
430 * 1. People who boot a system with a bad fstab root entry
431 * will get an incorrect "/dev/foo on /" in mtab.
432 * If later /dev/foo is actually mounted elsewhere,
433 * it will occur twice in mtab.
434 * 2. With overmounting one can get the situation that
435 * the same filename is used as mount point twice.
436 * In both cases, it is best to try the last occurrence first.
437 */
438static int
d03dd608
KZ
439umount_one_bw (const char *file, struct mntentchn *mc0) {
440 struct mntentchn *mc;
441 int res = 1;
442
443 mc = mc0;
444 while (res && mc) {
445 res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
446 mc->m.mnt_type, mc->m.mnt_opts, mc);
447 mc = getmntdirbackward(file, mc);
448 }
449 mc = mc0;
450 while (res && mc) {
451 res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
452 mc->m.mnt_type, mc->m.mnt_opts, mc);
453 mc = getmntdevbackward(file, mc);
454 }
455 return res;
5c36a0eb
KZ
456}
457
6dbe3af9 458/* Unmount all filesystems of type VFSTYPES found in mtab. Since we are
c07ebfa1 459 concurrently updating mtab after every successful umount, we have to
6dbe3af9
KZ
460 slurp in the entire file before we start. This isn't too bad, because
461 in any case it's important to umount mtab entries in reverse order
fd6b7a7f 462 to mount, e.g. /usr/spool before /usr. */
6dbe3af9 463static int
95f1bdee 464umount_all (char *types, char *test_opts) {
fd6b7a7f
KZ
465 struct mntentchn *mc, *hd;
466 int errors = 0;
467
468 hd = mtab_head();
469 if (!hd->prev)
7eda085c 470 die (2, _("umount: cannot find list of filesystems to unmount"));
fd6b7a7f 471 for (mc = hd->prev; mc != hd; mc = mc->prev) {
95f1bdee
KZ
472 if (matching_type (mc->m.mnt_type, types)
473 && matching_opts (mc->m.mnt_opts, test_opts)) {
66ee8158
KZ
474 errors |= umount_one (mc->m.mnt_fsname, mc->m.mnt_dir,
475 mc->m.mnt_type, mc->m.mnt_opts, mc);
fd6b7a7f
KZ
476 }
477 }
6dbe3af9 478
fd6b7a7f
KZ
479 sync ();
480 return errors;
6dbe3af9
KZ
481}
482
483extern char version[];
484static struct option longopts[] =
485{
486 { "all", 0, 0, 'a' },
487 { "force", 0, 0, 'f' },
488 { "help", 0, 0, 'h' },
fd6b7a7f 489 { "no-mtab", 0, 0, 'n' },
95f1bdee 490 { "test-opts", 1, 0, 'O' },
6dbe3af9
KZ
491 { "verbose", 0, 0, 'v' },
492 { "version", 0, 0, 'V' },
fd6b7a7f 493 { "read-only", 0, 0, 'r' },
6dbe3af9
KZ
494 { "types", 1, 0, 't' },
495 { NULL, 0, 0, 0 }
496};
497
6dbe3af9
KZ
498static void
499usage (FILE *fp, int n)
500{
7eda085c 501 fprintf (fp, _("Usage: umount [-hV]\n"
95f1bdee 502 " umount -a [-f] [-r] [-n] [-v] [-t vfstypes] [-O opts]\n"
7eda085c 503 " umount [-f] [-r] [-n] [-v] special | node...\n"));
6dbe3af9
KZ
504 exit (n);
505}
506
726f69e2
KZ
507int mount_quiet = 0;
508
d26aa358
KZ
509/*
510 * Look for an option in a comma-separated list
511 */
ffc43748 512static int
d26aa358
KZ
513contains(const char *list, const char *s) {
514 int n = strlen(s);
515
516 while (*list) {
517 if (strncmp(list, s, n) == 0 &&
518 (list[n] == 0 || list[n] == ','))
ffc43748 519 return 1;
d26aa358 520 while (*list && *list++ != ',') ;
ffc43748
KZ
521 }
522 return 0;
523}
524
525/*
526 * If list contains "user=peter" and we ask for "user=", return "peter"
527 */
528static char *
d26aa358
KZ
529get_value(const char *list, const char *s) {
530 const char *t;
ffc43748 531 int n = strlen(s);
d26aa358
KZ
532
533 while (*list) {
534 if (strncmp(list, s, n) == 0) {
535 s = t = list+n;
536 while (*s && *s != ',')
537 s++;
538 return xstrndup(t, s-t);
539 }
540 while (*list && *list++ != ',') ;
ffc43748
KZ
541 }
542 return 0;
543}
364cda48
KZ
544
545static int
546umount_file (char *arg) {
547 struct mntentchn *mc, *fs;
d26aa358 548 const char *file, *options;
d162fcb5
KZ
549 int fstab_has_user, fstab_has_users, fstab_has_owner, fstab_has_group;
550 int ok;
364cda48 551
5213517f
KZ
552 if (!*arg) { /* "" would be expanded to `pwd` */
553 die(2, _("Cannot umount \"\"\n"));
554 return 0;
555 }
556
d03dd608 557 file = canonicalize(arg); /* mtab paths are canonicalized */
364cda48
KZ
558 if (verbose > 1)
559 printf(_("Trying to umount %s\n"), file);
560
d03dd608
KZ
561 mc = getmntdirbackward(file, NULL);
562 if (!mc)
563 mc = getmntdevbackward(file, NULL);
364cda48
KZ
564 if (!mc && verbose)
565 printf(_("Could not find %s in mtab\n"), file);
566
567 if (suid) {
d03dd608
KZ
568 char *mtab_user = NULL;
569
364cda48 570 if (!mc)
d03dd608
KZ
571 die(2,
572 _("umount: %s is not mounted (according to mtab)"),
573 file);
756bfd01
KZ
574 /* The 2.4 kernel will generally refuse to mount the same
575 filesystem on the same mount point, but will accept NFS.
576 So, unmounting must be possible. */
577 if (!is_mounted_once(file) && strcmp(mc->m.mnt_type,"nfs"))
d03dd608
KZ
578 die(2,
579 _("umount: it seems %s is mounted multiple times"),
580 file);
364cda48
KZ
581
582 /* If fstab contains the two lines
583 /dev/sda1 /mnt/zip auto user,noauto 0 0
584 /dev/sda4 /mnt/zip auto user,noauto 0 0
585 then "mount /dev/sda4" followed by "umount /mnt/zip"
586 used to fail. So, we must not look for file, but for
587 the pair (spec,file) in fstab. */
588 fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir);
589 if (!fs) {
590 if (!getfsspec (file) && !getfsfile (file))
591 die (2,
d03dd608
KZ
592 _("umount: %s is not in the fstab "
593 "(and you are not root)"),
364cda48
KZ
594 file);
595 else
d03dd608
KZ
596 die (2, _("umount: %s mount disagrees with "
597 "the fstab"), file);
364cda48
KZ
598 }
599
d162fcb5
KZ
600 /*
601 * User mounting and unmounting is allowed only
602 * if fstab contains one of the options `user',
603 * `users' or `owner' or `group'.
604 *
605 * The option `users' allows arbitrary users to mount
606 * and unmount - this may be a security risk.
607 *
608 * The options `user', `owner' and `group' only allow
609 * unmounting by the user that mounted (visible in mtab).
610 */
ffc43748 611
d26aa358
KZ
612 options = fs->m.mnt_opts;
613 if (!options)
614 options = "";
ffc43748
KZ
615 fstab_has_user = contains(options, "user");
616 fstab_has_users = contains(options, "users");
617 fstab_has_owner = contains(options, "owner");
d162fcb5 618 fstab_has_group = contains(options, "group");
ffc43748
KZ
619 ok = 0;
620
621 if (fstab_has_users)
622 ok = 1;
623
d162fcb5
KZ
624 if (!ok && (fstab_has_user || fstab_has_owner ||
625 fstab_has_group)) {
364cda48
KZ
626 char *user = getusername();
627
d26aa358
KZ
628 options = mc->m.mnt_opts;
629 if (!options)
630 options = "";
ffc43748
KZ
631 mtab_user = get_value(options, "user=");
632
633 if (user && mtab_user && streq (user, mtab_user))
634 ok = 1;
364cda48 635 }
ffc43748 636 if (!ok)
d03dd608
KZ
637 die (2, _("umount: only %s can unmount %s from %s"),
638 mtab_user ? mtab_user : "root",
ffc43748 639 fs->m.mnt_fsname, fs->m.mnt_dir);
364cda48
KZ
640 }
641
642 if (mc)
643 return umount_one_bw (file, mc);
644 else
645 return umount_one (arg, arg, arg, arg, NULL);
6dbe3af9 646}
fd6b7a7f 647
d162fcb5
KZ
648char *progname;
649
364cda48
KZ
650int
651main (int argc, char *argv[]) {
652 int c;
653 int all = 0;
d162fcb5 654 char *types = NULL, *test_opts = NULL, *p;
364cda48
KZ
655 int result = 0;
656
657 sanitize_env();
658 setlocale(LC_ALL, "");
659 bindtextdomain(PACKAGE, LOCALEDIR);
660 textdomain(PACKAGE);
661
d162fcb5
KZ
662 progname = argv[0];
663 if ((p = strrchr(progname, '/')) != NULL)
664 progname = p+1;
665
b22550fa 666 umask(022);
0e6f4a20 667
d162fcb5 668 while ((c = getopt_long (argc, argv, "adfhlnrit:O:vV",
ffc43748 669 longopts, NULL)) != -1)
364cda48
KZ
670 switch (c) {
671 case 'a': /* umount everything */
672 ++all;
673 break;
674 /* fall through? */
675 case 'd': /* do losetup -d for unmounted loop devices */
676 ++delloop;
677 break;
678 case 'f': /* force umount */
679 ++force;
680 break;
681 case 'h': /* help */
682 usage (stdout, 0);
683 break;
e8f26419
KZ
684 case 'l': /* lazy umount */
685 ++lazy;
686 break;
364cda48
KZ
687 case 'n': /* do not write in /etc/mtab */
688 ++nomtab;
689 break;
95f1bdee
KZ
690 case 'O': /* specify file system options */
691 test_opts = optarg;
692 break;
364cda48
KZ
693 case 'r': /* remount read-only if umount fails */
694 ++remount;
695 break;
696 case 'v': /* make noise */
697 ++verbose;
698 break;
699 case 'V': /* version */
700 printf ("umount: %s\n", version);
701 exit (0);
702 case 't': /* specify file system type */
703 types = optarg;
704 break;
d162fcb5
KZ
705 case 'i':
706 external_allowed = 0;
707 break;
364cda48
KZ
708 case 0:
709 break;
710 case '?':
711 default:
712 usage (stderr, 1);
713 }
714
715 if (getuid () != geteuid ()) {
716 suid = 1;
717 if (all || types || nomtab || force)
718 die (2, _("umount: only root can do that"));
719 }
720
721 argc -= optind;
722 argv += optind;
723
724 if (all) {
d03dd608 725 /* nodev stuff: sysfs, usbfs, oprofilefs, ... */
364cda48 726 if (types == NULL)
d03dd608 727 types = "noproc,nodevfs,nodevpts";
95f1bdee 728 result = umount_all (types, test_opts);
364cda48
KZ
729 } else if (argc < 1) {
730 usage (stderr, 2);
731 } else while (argc--) {
732 result += umount_file(*argv++);
733 }
734 exit (result); /* nonzero on at least one failure */
735}