]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - mount/umount.c
2 * A umount(8) for Linux 0.99.
3 * umount.c,v 1.1.1.1 1993/11/18 08:40:51 jrs Exp
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.
9 * Tue Sep 26 16:33:09 1995: Added patches from Greg Page (greg@caldera.com)
10 * so that NetWare filesystems can be unmounted.
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.
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
35 #include <sys/mount.h>
36 #include "mount_constants.h"
38 #include "getusername.h"
45 #include <sys/socket.h>
49 #include <rpc/pmap_clnt.h>
50 #include <rpc/pmap_prot.h>
52 #include <arpa/inet.h>
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 */
60 /* Does the present kernel source know about umount2? */
61 #include <linux/unistd.h>
64 static int umount2(const char *path
, int flags
);
66 _syscall2(int, umount2
, const char *, path
, int, flags
);
68 #else /* __NR_umount2 */
71 umount2(const char *path
, int flags
) {
72 fprintf(stderr
, _("umount: compiled without support for -f\n"));
76 #endif /* __NR_umount2 */
78 #if !defined(MNT_FORCE)
79 /* dare not try to include <linux/mount.h> -- lots of errors */
83 #endif /* MNT_FORCE */
85 /* Nonzero for force umount (-f). There is kernel support since 2.1.116. */
88 /* When umount fails, attempt a read-only remount (-r). */
91 /* Don't write a entry in /etc/mtab (-n). */
94 /* Call losetup -d for each unmounted loop device. */
97 /* Nonzero for chatty (-v). */
100 /* True if ruid != euid. */
104 static int xdr_dir(XDR
*xdrsp
, char *dirp
)
106 return (xdr_string(xdrsp
, &dirp
, MNTPATHLEN
));
110 nfs_umount_rpc_call(const char *spec
, const char *opts
)
112 register CLIENT
*clp
;
113 struct sockaddr_in saddr
;
114 struct timeval pertry
, try;
115 enum clnt_stat clnt_stat
;
117 int so
= RPC_ANYSOCK
;
118 struct hostent
*hostp
;
123 if (spec
== NULL
|| (p
= strchr(spec
,':')) == NULL
)
125 hostname
= xstrndup(spec
, p
-spec
);
126 dirname
= xstrdup(p
+1);
128 printf(_("host: %s, directory: %s\n"), hostname
, dirname
);
131 if (opts
&& (p
= strstr(opts
, "addr="))) {
137 while (*q
&& *q
!= ',') q
++;
138 hostname
= xstrndup(p
,q
-p
);
141 if (opts
&& (p
= strstr(opts
, "mountport=")) && isdigit(*(p
+10)))
144 if (hostname
[0] >= '0' && hostname
[0] <= '9')
145 saddr
.sin_addr
.s_addr
= inet_addr(hostname
);
147 if ((hostp
= gethostbyname(hostname
)) == NULL
) {
148 fprintf(stderr
, _("umount: can't get address for %s\n"),
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
);
156 memcpy(&saddr
.sin_addr
, hostp
->h_addr
, hostp
->h_length
);
159 saddr
.sin_family
= AF_INET
;
160 saddr
.sin_port
= htons(port
);
163 if ((clp
= clntudp_create(&saddr
, MOUNTPROG
, MOUNTVERS
,
164 pertry
, &so
)) == NULL
) {
165 clnt_pcreateerror("Cannot MOUNTPROG RPC");
168 clp
->cl_auth
= authunix_create_default();
171 clnt_stat
= clnt_call(clp
, MOUNTPROC_UMNT
,
172 (xdrproc_t
) xdr_dir
, dirname
,
173 (xdrproc_t
) xdr_void
, (caddr_t
) 0,
176 if (clnt_stat
!= RPC_SUCCESS
) {
177 clnt_perror(clp
, "Bad UMNT RPC");
180 auth_destroy(clp
->cl_auth
);
185 #endif /* HAVE_NFS */
187 /* complain about a failed umount */
188 static void complain(int err
, const char *dev
) {
191 error (_("umount: %s: invalid block device"), dev
); break;
193 error (_("umount: %s: not mounted"), dev
); break;
195 error (_("umount: %s: can't write superblock"), dev
); break;
197 /* Let us hope fstab has a line "proc /proc ..."
198 and not "none /proc ..."*/
199 error (_("umount: %s: device is busy"), dev
); break;
201 error (_("umount: %s: not found"), dev
); break;
203 error (_("umount: %s: must be superuser to umount"), dev
); break;
205 error (_("umount: %s: block devices not permitted on fs"), dev
); break;
207 error (_("umount: %s: %s"), dev
, strerror (err
)); break;
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. */
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
;
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"));
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
);
240 umnt_err
= umnt_err2
= 0;
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
;
247 res
= umount2 (node
, flags
);
250 if (errno
== ENOSYS
) {
252 printf(_("no umount2, trying umount...\n"));
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
265 /* if (umnt_err == ENOENT || umnt_err == EINVAL) */
266 if (umnt_err
!= EBUSY
&& strcmp(node
, spec
)) {
268 printf (_("could not umount %s - trying %s instead\n"),
273 /* Do not complain about remote NFS mount points */
274 if (errno
== ENOENT
&& index(spec
, ':'))
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
);
286 _("umount: %s busy - remounted read-only\n"),
288 remnt
.mnt_type
= remnt
.mnt_fsname
= NULL
;
289 remnt
.mnt_dir
= xstrdup(node
);
290 remnt
.mnt_opts
= "ro";
291 update_mtab(node
, &remnt
);
293 } else if (errno
!= EBUSY
) { /* hmm ... */
296 _("umount: could not remount %s read-only\n"),
303 /* Umount succeeded */
305 printf (_("%s umounted\n"), spec
);
307 /* Free any loop devices that we allocated ourselves */
311 /* old style mtab line? */
312 if (streq(mc
->m
.mnt_type
, "loop")) {
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)) {
328 * If option "-o loop=spec" occurs in mtab,
329 * note the mount point, and delete mtab line.
331 if ((mc
= getmntoptfile (spec
)) != NULL
)
332 node
= mc
->m
.mnt_dir
;
335 /* Also free loop devices when -d flag is given */
336 if (delloop
&& is_loop_device(spec
))
343 if (!nomtab
&& mtab_is_writable() &&
344 (umnt_err
== 0 || umnt_err
== EINVAL
|| umnt_err
== ENOENT
)) {
345 update_mtab (node
, NULL
);
352 complain(umnt_err2
, spec
);
353 if (umnt_err
&& umnt_err
!= umnt_err2
)
354 complain(umnt_err
, node
);
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.
369 umount_one_bw (const char *file
, struct mntentchn
*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
);
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. */
386 umount_all (string_list types
) {
387 struct mntentchn
*mc
, *hd
;
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
);
404 extern char version
[];
405 static struct option longopts
[] =
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' },
419 usage (FILE *fp
, int n
)
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"));
430 main (int argc
, char *argv
[])
434 string_list types
= NULL
;
436 struct mntentchn
*mc
, *fs
;
440 setlocale(LC_ALL
, "");
441 bindtextdomain(PACKAGE
, LOCALEDIR
);
444 while ((c
= getopt_long (argc
, argv
, "afhnrt:vV",
445 longopts
, NULL
)) != EOF
)
447 case 'a': /* umount everything */
451 case 'd': /* do losetup -d for unmounted loop devices */
454 case 'f': /* force umount */
460 case 'n': /* do not write in /etc/mtab */
463 case 'r': /* remount read-only if umount fails */
466 case 'v': /* make noise */
469 case 'V': /* version */
470 printf ("umount: %s\n", version
);
472 case 't': /* specify file system type */
473 types
= parse_list (optarg
);
482 if (getuid () != geteuid ())
485 if (all
|| types
|| nomtab
|| force
)
486 die (2, _("umount: only root can do that"));
494 types
= parse_list("noproc");
495 result
= umount_all (types
);
496 } else if (argc
< 1) {
498 } else while (argc
--) {
499 file
= canonicalize (*argv
); /* mtab paths are canonicalized */
501 printf(_("Trying to umount %s\n"), file
);
503 mc
= getmntfilesbackward (file
, NULL
);
505 printf(_("Could not find %s in mtab\n"), file
);
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
);
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
);
521 if (!getfsspec (file
) && !getfsfile (file
))
523 _("umount: %s is not in the fstab (and you are not root)"),
526 die (2, _("umount: %s mount disagrees with the fstab"), file
);
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
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
);
540 if (streq (car (options
), "user") ||
541 streq (car (options
), "users") ||
542 streq (car (options
), "owner"))
544 options
= cdr (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();
553 options
= parse_list (mc
->m
.mnt_opts
);
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
);
562 options
= cdr (options
);
568 result
= umount_one_bw (file
, mc
);
570 result
= umount_one (*argv
, *argv
, *argv
, *argv
, NULL
);