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