]> git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/umount.c
Imported from util-linux-2.10s tarball.
[thirdparty/util-linux.git] / mount / umount.c
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.
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.
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
19 * 970307: aeb - canonicalise names from fstab
20 * 970726: aeb - remount read-only in cases where umount fails
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
25 * 001202: aeb - remove at most one line from /etc/mtab
26 */
27
28 #include <stdio.h>
29 #include <unistd.h>
30 #include <getopt.h>
31 #include <string.h>
32 #include <errno.h>
33 #include <ctype.h>
34 #include <sys/stat.h>
35 #include <sys/mount.h>
36 #include "mount_constants.h"
37 #include "sundries.h"
38 #include "getusername.h"
39 #include "lomount.h"
40 #include "loop.h"
41 #include "fstab.h"
42 #include "nls.h"
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>
51 #include "nfsmount.h"
52 #include <arpa/inet.h>
53 #endif
54
55 #if defined(MNT_FORCE) && !defined(__sparc__) && !defined(__arm__)
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
63
64 static int umount2(const char *path, int flags);
65
66 _syscall2(int, umount2, const char *, path, int, flags);
67
68 #else /* __NR_umount2 */
69
70 static int
71 umount2(const char *path, int flags) {
72 fprintf(stderr, _("umount: compiled without support for -f\n"));
73 errno = ENOSYS;
74 return -1;
75 }
76 #endif /* __NR_umount2 */
77
78 #if !defined(MNT_FORCE)
79 /* dare not try to include <linux/mount.h> -- lots of errors */
80 #define MNT_FORCE 1
81 #endif
82
83 #endif /* MNT_FORCE */
84
85 /* Nonzero for force umount (-f). There is kernel support since 2.1.116. */
86 int force = 0;
87
88 /* When umount fails, attempt a read-only remount (-r). */
89 int remount = 0;
90
91 /* Don't write a entry in /etc/mtab (-n). */
92 int nomtab = 0;
93
94 /* Call losetup -d for each unmounted loop device. */
95 int delloop = 0;
96
97 /* Nonzero for chatty (-v). */
98 int verbose = 0;
99
100 /* True if ruid != euid. */
101 int suid = 0;
102
103 #ifdef HAVE_NFS
104 static int xdr_dir(XDR *xdrsp, char *dirp)
105 {
106 return (xdr_string(xdrsp, &dirp, MNTPATHLEN));
107 }
108
109 static int
110 nfs_umount_rpc_call(const char *spec, const char *opts)
111 {
112 register CLIENT *clp;
113 struct sockaddr_in saddr;
114 struct timeval pertry, try;
115 enum clnt_stat clnt_stat;
116 int port = 0;
117 int so = RPC_ANYSOCK;
118 struct hostent *hostp;
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
128 printf(_("host: %s, directory: %s\n"), hostname, dirname);
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
141 if (opts && (p = strstr(opts, "mountport=")) && isdigit(*(p+10)))
142 port = atoi(p+10);
143
144 if (hostname[0] >= '0' && hostname[0] <= '9')
145 saddr.sin_addr.s_addr = inet_addr(hostname);
146 else {
147 if ((hostp = gethostbyname(hostname)) == NULL) {
148 fprintf(stderr, _("umount: can't get address for %s\n"),
149 hostname);
150 return 1;
151 }
152 if (hostp->h_length > sizeof(struct in_addr)) {
153 fprintf(stderr, _("umount: got bad hostp->h_length\n"));
154 hostp->h_length = sizeof(struct in_addr);
155 }
156 memcpy(&saddr.sin_addr, hostp->h_addr, hostp->h_length);
157 }
158
159 saddr.sin_family = AF_INET;
160 saddr.sin_port = htons(port);
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 }
185 #endif /* HAVE_NFS */
186
187 /* complain about a failed umount */
188 static void complain(int err, const char *dev) {
189 switch (err) {
190 case ENXIO:
191 error (_("umount: %s: invalid block device"), dev); break;
192 case EINVAL:
193 error (_("umount: %s: not mounted"), dev); break;
194 case EIO:
195 error (_("umount: %s: can't write superblock"), dev); break;
196 case EBUSY:
197 /* Let us hope fstab has a line "proc /proc ..."
198 and not "none /proc ..."*/
199 error (_("umount: %s: device is busy"), dev); break;
200 case ENOENT:
201 error (_("umount: %s: not found"), dev); break;
202 case EPERM:
203 error (_("umount: %s: must be superuser to umount"), dev); break;
204 case EACCES:
205 error (_("umount: %s: block devices not permitted on fs"), dev); break;
206 default:
207 error (_("umount: %s: %s"), dev, strerror (err)); break;
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. */
213 static int
214 umount_one (const char *spec, const char *node, const char *type,
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++;
231
232 #ifdef HAVE_NFS
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);
237 #endif
238
239
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;
350
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;
356 }
357
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 */
368 static int
369 umount_one_bw (const char *file, struct mntentchn *mc) {
370 int res = 1;
371
372 while (res && mc) {
373 res = umount_one(mc->m.mnt_fsname, mc->m.mnt_dir,
374 mc->m.mnt_type, mc->m.mnt_opts, mc);
375 mc = getmntfilesbackward (file, mc);
376 }
377 return res;
378 }
379
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
384 to mount, e.g. /usr/spool before /usr. */
385 static int
386 umount_all (string_list types) {
387 struct mntentchn *mc, *hd;
388 int errors = 0;
389
390 hd = mtab_head();
391 if (!hd->prev)
392 die (2, _("umount: cannot find list of filesystems to unmount"));
393 for (mc = hd->prev; mc != hd; mc = mc->prev) {
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);
397 }
398 }
399
400 sync ();
401 return errors;
402 }
403
404 extern char version[];
405 static struct option longopts[] =
406 {
407 { "all", 0, 0, 'a' },
408 { "force", 0, 0, 'f' },
409 { "help", 0, 0, 'h' },
410 { "no-mtab", 0, 0, 'n' },
411 { "verbose", 0, 0, 'v' },
412 { "version", 0, 0, 'V' },
413 { "read-only", 0, 0, 'r' },
414 { "types", 1, 0, 't' },
415 { NULL, 0, 0, 0 }
416 };
417
418 static void
419 usage (FILE *fp, int n)
420 {
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"));
424 exit (n);
425 }
426
427 int mount_quiet = 0;
428
429 int
430 main (int argc, char *argv[])
431 {
432 int c;
433 int all = 0;
434 string_list types = NULL;
435 string_list options;
436 struct mntentchn *mc, *fs;
437 char *file;
438 int result = 0;
439
440 setlocale(LC_ALL, "");
441 bindtextdomain(PACKAGE, LOCALEDIR);
442 textdomain(PACKAGE);
443
444 while ((c = getopt_long (argc, argv, "afhnrt:vV",
445 longopts, NULL)) != EOF)
446 switch (c) {
447 case 'a': /* umount everything */
448 ++all;
449 break;
450 /* fall through? */
451 case 'd': /* do losetup -d for unmounted loop devices */
452 ++delloop;
453 break;
454 case 'f': /* force umount */
455 ++force;
456 break;
457 case 'h': /* help */
458 usage (stdout, 0);
459 break;
460 case 'n': /* do not write in /etc/mtab */
461 ++nomtab;
462 break;
463 case 'r': /* remount read-only if umount fails */
464 ++remount;
465 break;
466 case 'v': /* make noise */
467 ++verbose;
468 break;
469 case 'V': /* version */
470 printf ("umount: %s\n", version);
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);
480 }
481
482 if (getuid () != geteuid ())
483 {
484 suid = 1;
485 if (all || types || nomtab || force)
486 die (2, _("umount: only root can do that"));
487 }
488
489 argc -= optind;
490 argv += optind;
491
492 if (all) {
493 if (types == NULL)
494 types = parse_list("noproc");
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)
501 printf(_("Trying to umount %s\n"), file);
502
503 mc = getmntfilesbackward (file, NULL);
504 if (!mc && verbose)
505 printf(_("Could not find %s in mtab\n"), file);
506
507 if (suid) {
508 if (!mc)
509 die (2, _("umount: %s is not mounted (according to mtab)"), file);
510 if (getmntfilesbackward (file, mc))
511 die (2, _("umount: it seems %s is mounted multiple times"), file);
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. */
519 fs = getfsspecfile(mc->m.mnt_fsname, mc->m.mnt_dir);
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)"),
524 file);
525 else
526 die (2, _("umount: %s mount disagrees with the fstab"), file);
527 }
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. */
535 /* The option `owner' only allows (un)mounting by the owner. */
536 /* A convenient side effect is that the user who mounted
537 is visible in mtab. */
538 options = parse_list (fs->m.mnt_opts);
539 while (options) {
540 if (streq (car (options), "user") ||
541 streq (car (options), "users") ||
542 streq (car (options), "owner"))
543 break;
544 options = cdr (options);
545 }
546 if (!options)
547 die (2, _("umount: only root can unmount %s from %s"),
548 fs->m.mnt_fsname, fs->m.mnt_dir);
549 if (streq (car (options), "user") ||
550 streq (car (options), "owner")) {
551 char *user = getusername();
552
553 options = parse_list (mc->m.mnt_opts);
554 while (options) {
555 char *co = car (options);
556 if (!strncmp(co, "user=", 5)) {
557 if (!user || !streq(co+5,user))
558 die(2, _("umount: only %s can unmount %s from %s"),
559 co+5, fs->m.mnt_fsname, fs->m.mnt_dir);
560 break;
561 }
562 options = cdr (options);
563 }
564 }
565 }
566
567 if (mc)
568 result = umount_one_bw (file, mc);
569 else
570 result = umount_one (*argv, *argv, *argv, *argv, NULL);
571
572 argv++;
573
574 }
575 exit (result);
576 }
577