]> git.ipfire.org Git - thirdparty/util-linux.git/blame - mount/umount.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / mount / umount.c
CommitLineData
6dbe3af9
KZ
1/*
2 * A umount(8) for Linux 0.99.
3 * umount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
4 *
5 * Wed Sep 14 22:43:54 1994: Sebastian Lederer
6 * (lederer@next-pc.informatik.uni-bonn.de) added support for sending an
7 * unmount RPC call to the server when an NFS-filesystem is unmounted.
726f69e2
KZ
8 *
9 * Tue Sep 26 16:33:09 1995: Added patches from Greg Page (greg@caldera.com)
10 * so that NetWare filesystems can be unmounted.
fd6b7a7f
KZ
11 *
12 * 951213: Marek Michalkiewicz <marekm@i17linuxb.ists.pwr.wroc.pl>:
13 * Ignore any RPC errors, so that you can umount an nfs mounted filesystem
14 * if the server is down.
15 *
16 * 960223: aeb - several minor changes
17 * 960324: aeb - added some changes from Rob Leslie <rob@mars.org>
18 * 960823: aeb - also try umount(spec) when umount(node) fails
66ee8158 19 * 970307: aeb - canonicalise names from fstab
fd6b7a7f 20 * 970726: aeb - remount read-only in cases where umount fails
5c36a0eb
KZ
21 * 980810: aeb - umount2 support
22 * 981222: aeb - If mount point or special file occurs several times
23 * in mtab, try them all, with last one tried first
24 * - Differentiate "user" and "users" key words in fstab
66ee8158 25 * 001202: aeb - remove at most one line from /etc/mtab
6dbe3af9
KZ
26 */
27
66ee8158 28#include <stdio.h>
fd6b7a7f
KZ
29#include <unistd.h>
30#include <getopt.h>
31#include <string.h>
32#include <errno.h>
66ee8158 33#include <ctype.h>
fd6b7a7f
KZ
34#include <sys/stat.h>
35#include <sys/mount.h>
36#include "mount_constants.h"
6dbe3af9 37#include "sundries.h"
5c36a0eb 38#include "getusername.h"
fd6b7a7f
KZ
39#include "lomount.h"
40#include "loop.h"
41#include "fstab.h"
7eda085c 42#include "nls.h"
6dbe3af9
KZ
43
44#ifdef HAVE_NFS
45#include <sys/socket.h>
46#include <sys/time.h>
47#include <netdb.h>
48#include <rpc/rpc.h>
49#include <rpc/pmap_clnt.h>
50#include <rpc/pmap_prot.h>
fd6b7a7f 51#include "nfsmount.h"
6dbe3af9
KZ
52#include <arpa/inet.h>
53#endif
54
eb63b9b8 55#if defined(MNT_FORCE) && !defined(__sparc__) && !defined(__arm__)
5c36a0eb
KZ
56/* Interesting ... it seems libc knows about MNT_FORCE and presumably
57 about umount2 as well -- need not do anything */
58#else /* MNT_FORCE */
59
60/* Does the present kernel source know about umount2? */
61#include <linux/unistd.h>
62#ifdef __NR_umount2
eb63b9b8
KZ
63
64static int umount2(const char *path, int flags);
65
5c36a0eb 66_syscall2(int, umount2, const char *, path, int, flags);
eb63b9b8 67
5c36a0eb 68#else /* __NR_umount2 */
eb63b9b8 69
5c36a0eb
KZ
70static int
71umount2(const char *path, int flags) {
7eda085c 72 fprintf(stderr, _("umount: compiled without support for -f\n"));
5c36a0eb
KZ
73 errno = ENOSYS;
74 return -1;
75}
76#endif /* __NR_umount2 */
77
eb63b9b8 78#if !defined(MNT_FORCE)
5c36a0eb
KZ
79/* dare not try to include <linux/mount.h> -- lots of errors */
80#define MNT_FORCE 1
eb63b9b8 81#endif
5c36a0eb
KZ
82
83#endif /* MNT_FORCE */
84
85/* Nonzero for force umount (-f). There is kernel support since 2.1.116. */
6dbe3af9 86int force = 0;
6dbe3af9 87
fd6b7a7f
KZ
88/* When umount fails, attempt a read-only remount (-r). */
89int remount = 0;
90
91/* Don't write a entry in /etc/mtab (-n). */
92int nomtab = 0;
93
66ee8158
KZ
94/* Call losetup -d for each unmounted loop device. */
95int delloop = 0;
96
97/* Nonzero for chatty (-v). */
6dbe3af9
KZ
98int verbose = 0;
99
100/* True if ruid != euid. */
101int suid = 0;
102
103#ifdef HAVE_NFS
104static int xdr_dir(XDR *xdrsp, char *dirp)
105{
106 return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
107}
6dbe3af9 108
6dbe3af9 109static int
fd6b7a7f 110nfs_umount_rpc_call(const char *spec, const char *opts)
6dbe3af9 111{
6dbe3af9
KZ
112 register CLIENT *clp;
113 struct sockaddr_in saddr;
114 struct timeval pertry, try;
115 enum clnt_stat clnt_stat;
66ee8158 116 int port = 0;
6dbe3af9 117 int so = RPC_ANYSOCK;
6dbe3af9 118 struct hostent *hostp;
fd6b7a7f
KZ
119 char *hostname;
120 char *dirname;
121 char *p;
122
123 if (spec == NULL || (p = strchr(spec,':')) == NULL)
124 return 0;
125 hostname = xstrndup(spec, p-spec);
126 dirname = xstrdup(p+1);
127#ifdef DEBUG
7eda085c 128 printf(_("host: %s, directory: %s\n"), hostname, dirname);
fd6b7a7f
KZ
129#endif
130
131 if (opts && (p = strstr(opts, "addr="))) {
132 char *q;
133
134 free(hostname);
135 p += 5;
136 q = p;
137 while (*q && *q != ',') q++;
138 hostname = xstrndup(p,q-p);
139 }
140
66ee8158
KZ
141 if (opts && (p = strstr(opts, "mountport=")) && isdigit(*(p+10)))
142 port = atoi(p+10);
143
fd6b7a7f
KZ
144 if (hostname[0] >= '0' && hostname[0] <= '9')
145 saddr.sin_addr.s_addr = inet_addr(hostname);
2b6fc908 146 else {
fd6b7a7f 147 if ((hostp = gethostbyname(hostname)) == NULL) {
7eda085c 148 fprintf(stderr, _("umount: can't get address for %s\n"),
fd6b7a7f
KZ
149 hostname);
150 return 1;
2b6fc908
KZ
151 }
152 if (hostp->h_length > sizeof(struct in_addr)) {
7eda085c 153 fprintf(stderr, _("umount: got bad hostp->h_length\n"));
2b6fc908
KZ
154 hostp->h_length = sizeof(struct in_addr);
155 }
156 memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length);
157 }
fd6b7a7f
KZ
158
159 saddr.sin_family = AF_INET;
66ee8158 160 saddr.sin_port = htons(port);
fd6b7a7f
KZ
161 pertry.tv_sec = 3;
162 pertry.tv_usec = 0;
163 if ((clp = clntudp_create(&saddr, MOUNTPROG, MOUNTVERS,
164 pertry, &so)) == NULL) {
165 clnt_pcreateerror("Cannot MOUNTPROG RPC");
166 return (1);
167 }
168 clp->cl_auth = authunix_create_default();
169 try.tv_sec = 20;
170 try.tv_usec = 0;
171 clnt_stat = clnt_call(clp, MOUNTPROC_UMNT,
172 (xdrproc_t) xdr_dir, dirname,
173 (xdrproc_t) xdr_void, (caddr_t) 0,
174 try);
175
176 if (clnt_stat != RPC_SUCCESS) {
177 clnt_perror(clp, "Bad UMNT RPC");
178 return (1);
179 }
180 auth_destroy(clp->cl_auth);
181 clnt_destroy(clp);
182
183 return (0);
184}
6dbe3af9 185#endif /* HAVE_NFS */
fd6b7a7f
KZ
186
187/* complain about a failed umount */
188static void complain(int err, const char *dev) {
189 switch (err) {
190 case ENXIO:
7eda085c 191 error (_("umount: %s: invalid block device"), dev); break;
fd6b7a7f 192 case EINVAL:
7eda085c 193 error (_("umount: %s: not mounted"), dev); break;
fd6b7a7f 194 case EIO:
7eda085c 195 error (_("umount: %s: can't write superblock"), dev); break;
fd6b7a7f
KZ
196 case EBUSY:
197 /* Let us hope fstab has a line "proc /proc ..."
198 and not "none /proc ..."*/
7eda085c 199 error (_("umount: %s: device is busy"), dev); break;
fd6b7a7f 200 case ENOENT:
7eda085c 201 error (_("umount: %s: not found"), dev); break;
fd6b7a7f 202 case EPERM:
7eda085c 203 error (_("umount: %s: must be superuser to umount"), dev); break;
fd6b7a7f 204 case EACCES:
7eda085c 205 error (_("umount: %s: block devices not permitted on fs"), dev); break;
fd6b7a7f 206 default:
7eda085c 207 error (_("umount: %s: %s"), dev, strerror (err)); break;
fd6b7a7f
KZ
208 }
209}
210
211/* Umount a single device. Return a status code, so don't exit
212 on a non-fatal error. We lock/unlock around each umount. */
213static int
214umount_one (const char *spec, const char *node, const char *type,
66ee8158
KZ
215 const char *opts, struct mntentchn *mc) {
216 int umnt_err, umnt_err2;
217 int isroot;
218 int res;
219 const char *loopdev;
220
221 /* Special case for root. As of 0.99pl10 we can (almost) unmount root;
222 the kernel will remount it readonly so that we can carry on running
223 afterwards. The readonly remount is illegal if any files are opened
224 for writing at the time, so we can't update mtab for an unmount of
225 root. As it is only really a remount, this doesn't matter too
226 much. [sct May 29, 1993] */
227 isroot = (streq (node, "/") || streq (node, "root")
228 || streq (node, "rootfs"));
229 if (isroot)
230 nomtab++;
6dbe3af9
KZ
231
232#ifdef HAVE_NFS
66ee8158
KZ
233 /* Ignore any RPC errors, so that you can umount the filesystem
234 if the server is down. */
235 if (strcasecmp(type, "nfs") == 0)
236 nfs_umount_rpc_call(spec, opts);
6dbe3af9 237#endif
6dbe3af9 238
6dbe3af9 239
66ee8158
KZ
240 umnt_err = umnt_err2 = 0;
241 if (force) {
242 /* completely untested;
243 2.1.116 only has some support in nfs case */
244 /* probably this won't work */
245 int flags = MNT_FORCE;
246
247 res = umount2 (node, flags);
248 if (res == -1) {
249 perror("umount2");
250 if (errno == ENOSYS) {
251 if (verbose)
252 printf(_("no umount2, trying umount...\n"));
253 res = umount (node);
254 }
255 }
256 } else
257 res = umount (node);
258
259 if (res < 0) {
260 umnt_err = errno;
261 /* A device might have been mounted on a node that has since
262 been deleted or renamed, so if node fails, also try spec. */
263 /* Note that this is incorrect in case spec was mounted
264 several times. */
265 /* if (umnt_err == ENOENT || umnt_err == EINVAL) */
266 if (umnt_err != EBUSY && strcmp(node, spec)) {
267 if (verbose)
268 printf (_("could not umount %s - trying %s instead\n"),
269 node, spec);
270 res = umount (spec);
271 if (res < 0)
272 umnt_err2 = errno;
273 /* Do not complain about remote NFS mount points */
274 if (errno == ENOENT && index(spec, ':'))
275 umnt_err2 = 0;
276 }
277 }
278
279 if (res < 0 && remount && (umnt_err == EBUSY || umnt_err2 == EBUSY)) {
280 /* Umount failed - let us try a remount */
281 res = mount(spec, node, NULL,
282 MS_MGC_VAL | MS_REMOUNT | MS_RDONLY, NULL);
283 if (res == 0) {
284 struct mntent remnt;
285 fprintf(stderr,
286 _("umount: %s busy - remounted read-only\n"),
287 spec);
288 remnt.mnt_type = remnt.mnt_fsname = NULL;
289 remnt.mnt_dir = xstrdup(node);
290 remnt.mnt_opts = "ro";
291 update_mtab(node, &remnt);
292 return 0;
293 } else if (errno != EBUSY) { /* hmm ... */
294 perror("remount");
295 fprintf(stderr,
296 _("umount: could not remount %s read-only\n"),
297 spec);
298 }
299 }
300
301 loopdev = 0;
302 if (res >= 0) {
303 /* Umount succeeded */
304 if (verbose)
305 printf (_("%s umounted\n"), spec);
306
307 /* Free any loop devices that we allocated ourselves */
308 if (mc) {
309 char *optl;
310
311 /* old style mtab line? */
312 if (streq(mc->m.mnt_type, "loop")) {
313 loopdev = spec;
314 goto gotloop;
315 }
316
317 /* new style mtab line? */
318 optl = mc->m.mnt_opts ? xstrdup(mc->m.mnt_opts) : "";
319 for (optl = strtok (optl, ","); optl;
320 optl = strtok (NULL, ",")) {
321 if (!strncmp(optl, "loop=", 5)) {
322 loopdev = optl+5;
323 goto gotloop;
324 }
325 }
326 } else {
327 /*
328 * If option "-o loop=spec" occurs in mtab,
329 * note the mount point, and delete mtab line.
330 */
331 if ((mc = getmntoptfile (spec)) != NULL)
332 node = mc->m.mnt_dir;
333 }
334
335 /* Also free loop devices when -d flag is given */
336 if (delloop && is_loop_device(spec))
337 loopdev = spec;
338 }
339 gotloop:
340 if (loopdev)
341 del_loop(loopdev);
342
343 if (!nomtab && mtab_is_writable() &&
344 (umnt_err == 0 || umnt_err == EINVAL || umnt_err == ENOENT)) {
345 update_mtab (node, NULL);
346 }
347
348 if (res >= 0)
349 return 0;
6dbe3af9 350
66ee8158
KZ
351 if (umnt_err2)
352 complain(umnt_err2, spec);
353 if (umnt_err && umnt_err != umnt_err2)
354 complain(umnt_err, node);
355 return 1;
6dbe3af9
KZ
356}
357
5c36a0eb
KZ
358/*
359 * Why this loop?
360 * 1. People who boot a system with a bad fstab root entry
361 * will get an incorrect "/dev/foo on /" in mtab.
362 * If later /dev/foo is actually mounted elsewhere,
363 * it will occur twice in mtab.
364 * 2. With overmounting one can get the situation that
365 * the same filename is used as mount point twice.
366 * In both cases, it is best to try the last occurrence first.
367 */
368static int
369umount_one_bw (const char *file, struct mntentchn *mc) {
370 int res = 1;
371
372 while (res && mc) {
66ee8158
KZ
373 res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
374 mc->m.mnt_type, mc->m.mnt_opts, mc);
5c36a0eb
KZ
375 mc = getmntfilesbackward (file, mc);
376 }
377 return res;
378}
379
6dbe3af9
KZ
380/* Unmount all filesystems of type VFSTYPES found in mtab. Since we are
381 concurrently updating mtab after every succesful umount, we have to
382 slurp in the entire file before we start. This isn't too bad, because
383 in any case it's important to umount mtab entries in reverse order
fd6b7a7f 384 to mount, e.g. /usr/spool before /usr. */
6dbe3af9 385static int
fd6b7a7f
KZ
386umount_all (string_list types) {
387 struct mntentchn *mc, *hd;
388 int errors = 0;
389
390 hd = mtab_head();
391 if (!hd->prev)
7eda085c 392 die (2, _("umount: cannot find list of filesystems to unmount"));
fd6b7a7f 393 for (mc = hd->prev; mc != hd; mc = mc->prev) {
66ee8158
KZ
394 if (matching_type (mc->m.mnt_type, types)) {
395 errors |= umount_one (mc->m.mnt_fsname, mc->m.mnt_dir,
396 mc->m.mnt_type, mc->m.mnt_opts, mc);
fd6b7a7f
KZ
397 }
398 }
6dbe3af9 399
fd6b7a7f
KZ
400 sync ();
401 return errors;
6dbe3af9
KZ
402}
403
404extern char version[];
405static struct option longopts[] =
406{
407 { "all", 0, 0, 'a' },
408 { "force", 0, 0, 'f' },
409 { "help", 0, 0, 'h' },
fd6b7a7f 410 { "no-mtab", 0, 0, 'n' },
6dbe3af9
KZ
411 { "verbose", 0, 0, 'v' },
412 { "version", 0, 0, 'V' },
fd6b7a7f 413 { "read-only", 0, 0, 'r' },
6dbe3af9
KZ
414 { "types", 1, 0, 't' },
415 { NULL, 0, 0, 0 }
416};
417
6dbe3af9
KZ
418static void
419usage (FILE *fp, int n)
420{
7eda085c
KZ
421 fprintf (fp, _("Usage: umount [-hV]\n"
422 " umount -a [-f] [-r] [-n] [-v] [-t vfstypes]\n"
423 " umount [-f] [-r] [-n] [-v] special | node...\n"));
6dbe3af9
KZ
424 exit (n);
425}
426
726f69e2
KZ
427int mount_quiet = 0;
428
6dbe3af9
KZ
429int
430main (int argc, char *argv[])
431{
432 int c;
433 int all = 0;
434 string_list types = NULL;
435 string_list options;
fd6b7a7f 436 struct mntentchn *mc, *fs;
6dbe3af9
KZ
437 char *file;
438 int result = 0;
439
7eda085c
KZ
440 setlocale(LC_ALL, "");
441 bindtextdomain(PACKAGE, LOCALEDIR);
442 textdomain(PACKAGE);
443
5c36a0eb
KZ
444 while ((c = getopt_long (argc, argv, "afhnrt:vV",
445 longopts, NULL)) != EOF)
fd6b7a7f 446 switch (c) {
6dbe3af9
KZ
447 case 'a': /* umount everything */
448 ++all;
449 break;
66ee8158
KZ
450 /* fall through? */
451 case 'd': /* do losetup -d for unmounted loop devices */
452 ++delloop;
453 break;
5c36a0eb 454 case 'f': /* force umount */
6dbe3af9 455 ++force;
6dbe3af9
KZ
456 break;
457 case 'h': /* help */
458 usage (stdout, 0);
459 break;
5c36a0eb 460 case 'n': /* do not write in /etc/mtab */
fd6b7a7f
KZ
461 ++nomtab;
462 break;
463 case 'r': /* remount read-only if umount fails */
464 ++remount;
465 break;
6dbe3af9
KZ
466 case 'v': /* make noise */
467 ++verbose;
468 break;
469 case 'V': /* version */
726f69e2 470 printf ("umount: %s\n", version);
6dbe3af9
KZ
471 exit (0);
472 case 't': /* specify file system type */
473 types = parse_list (optarg);
474 break;
475 case 0:
476 break;
477 case '?':
478 default:
479 usage (stderr, 1);
fd6b7a7f 480 }
6dbe3af9
KZ
481
482 if (getuid () != geteuid ())
483 {
484 suid = 1;
5c36a0eb 485 if (all || types || nomtab || force)
7eda085c 486 die (2, _("umount: only root can do that"));
6dbe3af9
KZ
487 }
488
489 argc -= optind;
490 argv += optind;
491
fd6b7a7f
KZ
492 if (all) {
493 if (types == NULL)
7eda085c 494 types = parse_list("noproc");
fd6b7a7f
KZ
495 result = umount_all (types);
496 } else if (argc < 1) {
497 usage (stderr, 2);
498 } else while (argc--) {
499 file = canonicalize (*argv); /* mtab paths are canonicalized */
500 if (verbose > 1)
7eda085c 501 printf(_("Trying to umount %s\n"), file);
fd6b7a7f 502
5c36a0eb 503 mc = getmntfilesbackward (file, NULL);
fd6b7a7f 504 if (!mc && verbose)
7eda085c 505 printf(_("Could not find %s in mtab\n"), file);
fd6b7a7f
KZ
506
507 if (suid) {
508 if (!mc)
7eda085c 509 die (2, _("umount: %s is not mounted (according to mtab)"), file);
5c36a0eb 510 if (getmntfilesbackward (file, mc))
7eda085c 511 die (2, _("umount: it seems %s is mounted multiple times"), file);
eb63b9b8
KZ
512
513 /* If fstab contains the two lines
514 /dev/sda1 /mnt/zip auto user,noauto 0 0
515 /dev/sda4 /mnt/zip auto user,noauto 0 0
516 then "mount /dev/sda4" followed by "umount /mnt/zip"
517 used to fail. So, we must not look for file, but for
518 the pair (spec,file) in fstab. */
66ee8158 519 fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir);
eb63b9b8
KZ
520 if (!fs) {
521 if (!getfsspec (file) && !getfsfile (file))
522 die (2,
523 _("umount: %s is not in the fstab (and you are not root)"),
fd6b7a7f 524 file);
eb63b9b8
KZ
525 else
526 die (2, _("umount: %s mount disagrees with the fstab"), file);
fd6b7a7f 527 }
5c36a0eb
KZ
528
529 /* User mounting and unmounting is allowed only
530 if fstab contains the option `user' or `users' */
531 /* The option `users' allows arbitrary users to mount
532 and unmount - this may be a security risk. */
533 /* The option `user' only allows unmounting by the user
534 that mounted. */
eb63b9b8 535 /* The option `owner' only allows (un)mounting by the owner. */
5c36a0eb
KZ
536 /* A convenient side effect is that the user who mounted
537 is visible in mtab. */
66ee8158 538 options = parse_list (fs->m.mnt_opts);
fd6b7a7f 539 while (options) {
5c36a0eb 540 if (streq (car (options), "user") ||
eb63b9b8
KZ
541 streq (car (options), "users") ||
542 streq (car (options), "owner"))
6dbe3af9
KZ
543 break;
544 options = cdr (options);
fd6b7a7f 545 }
6dbe3af9 546 if (!options)
7eda085c 547 die (2, _("umount: only root can unmount %s from %s"),
66ee8158 548 fs->m.mnt_fsname, fs->m.mnt_dir);
eb63b9b8
KZ
549 if (streq (car (options), "user") ||
550 streq (car (options), "owner")) {
5c36a0eb
KZ
551 char *user = getusername();
552
66ee8158 553 options = parse_list (mc->m.mnt_opts);
5c36a0eb
KZ
554 while (options) {
555 char *co = car (options);
556 if (!strncmp(co, "user=", 5)) {
557 if (!user || !streq(co+5,user))
7eda085c 558 die(2, _("umount: only %s can unmount %s from %s"),
66ee8158 559 co+5, fs->m.mnt_fsname, fs->m.mnt_dir);
5c36a0eb
KZ
560 break;
561 }
562 options = cdr (options);
563 }
564 }
fd6b7a7f 565 }
6dbe3af9 566
fd6b7a7f 567 if (mc)
5c36a0eb 568 result = umount_one_bw (file, mc);
fd6b7a7f 569 else
5c36a0eb 570 result = umount_one (*argv, *argv, *argv, *argv, NULL);
726f69e2 571
fd6b7a7f
KZ
572 argv++;
573
574 }
6dbe3af9
KZ
575 exit (result);
576}
fd6b7a7f 577