2011-11-29 12:02:27 -06:00
|
|
|
/*
|
|
|
|
* umount(8) -- mount a filesystem
|
|
|
|
*
|
|
|
|
* Copyright (C) 2011 Red Hat, Inc. All rights reserved.
|
|
|
|
* Written by Karel Zak <kzak@redhat.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it would be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
2012-02-22 15:28:48 -06:00
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
2011-11-29 12:02:27 -06:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
|
|
|
#include <libmount.h>
|
|
|
|
|
|
|
|
#include "nls.h"
|
|
|
|
#include "c.h"
|
|
|
|
#include "env.h"
|
2012-04-04 12:49:40 -05:00
|
|
|
#include "closestream.h"
|
2012-11-07 12:02:28 -06:00
|
|
|
#include "pathnames.h"
|
2012-11-26 09:25:46 -06:00
|
|
|
#include "canonicalize.h"
|
2017-06-22 15:17:14 -05:00
|
|
|
|
|
|
|
#define XALLOC_EXIT_CODE MNT_EX_SYSERR
|
2013-02-26 07:50:26 -06:00
|
|
|
#include "xalloc.h"
|
2011-11-29 12:02:27 -06:00
|
|
|
|
2017-06-22 15:18:14 -05:00
|
|
|
#define OPTUTILS_EXIT_CODE MNT_EX_USAGE
|
|
|
|
#include "optutils.h"
|
|
|
|
|
2018-08-01 02:10:07 -05:00
|
|
|
static int quiet;
|
2020-08-25 03:48:29 -05:00
|
|
|
static struct ul_env_list *envs_removed;
|
2018-08-01 02:10:07 -05:00
|
|
|
|
2011-11-29 12:02:27 -06:00
|
|
|
static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
|
|
|
|
const char *filename, int line)
|
|
|
|
{
|
|
|
|
if (filename)
|
2016-03-16 03:55:53 -05:00
|
|
|
warnx(_("%s: parse error at line %d -- ignored"), filename, line);
|
2015-10-15 04:53:44 -05:00
|
|
|
return 1;
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
|
|
|
|
2012-01-23 05:28:05 -06:00
|
|
|
|
2019-04-16 06:47:17 -05:00
|
|
|
static void __attribute__((__noreturn__)) umount_print_version(void)
|
2011-11-29 12:02:27 -06:00
|
|
|
{
|
|
|
|
const char *ver = NULL;
|
2012-01-23 05:28:05 -06:00
|
|
|
const char **features = NULL, **p;
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
mnt_get_library_version(&ver);
|
2012-01-23 05:28:05 -06:00
|
|
|
mnt_get_library_features(&features);
|
2011-11-29 12:02:27 -06:00
|
|
|
|
2012-01-23 05:28:05 -06:00
|
|
|
printf(_("%s from %s (libmount %s"),
|
|
|
|
program_invocation_short_name,
|
|
|
|
PACKAGE_STRING,
|
|
|
|
ver);
|
|
|
|
p = features;
|
|
|
|
while (p && *p) {
|
|
|
|
fputs(p == features ? ": " : ", ", stdout);
|
|
|
|
fputs(*p++, stdout);
|
|
|
|
}
|
|
|
|
fputs(")\n", stdout);
|
2017-04-27 07:25:57 -05:00
|
|
|
exit(MNT_EX_SUCCESS);
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
2017-06-19 13:52:50 -05:00
|
|
|
static void __attribute__((__noreturn__)) usage(void)
|
2011-11-29 12:02:27 -06:00
|
|
|
{
|
2017-06-19 13:52:50 -05:00
|
|
|
FILE *out = stdout;
|
2011-11-29 12:02:27 -06:00
|
|
|
fputs(USAGE_HEADER, out);
|
|
|
|
fprintf(out, _(
|
|
|
|
" %1$s [-hV]\n"
|
|
|
|
" %1$s -a [options]\n"
|
|
|
|
" %1$s [options] <source> | <directory>\n"),
|
|
|
|
program_invocation_short_name);
|
|
|
|
|
2014-12-22 15:57:17 -06:00
|
|
|
fputs(USAGE_SEPARATOR, out);
|
|
|
|
fputs(_("Unmount filesystems.\n"), out);
|
|
|
|
|
2011-11-29 12:02:27 -06:00
|
|
|
fputs(USAGE_OPTIONS, out);
|
2013-02-26 07:50:26 -06:00
|
|
|
fputs(_(" -a, --all unmount all filesystems\n"), out);
|
2014-04-04 08:08:01 -05:00
|
|
|
fputs(_(" -A, --all-targets unmount all mountpoints for the given device in the\n"
|
2013-05-29 14:52:56 -05:00
|
|
|
" current namespace\n"), out);
|
2013-01-22 17:27:10 -06:00
|
|
|
fputs(_(" -c, --no-canonicalize don't canonicalize paths\n"), out);
|
|
|
|
fputs(_(" -d, --detach-loop if mounted loop device, also free this loop device\n"), out);
|
|
|
|
fputs(_(" --fake dry run; skip the umount(2) syscall\n"), out);
|
|
|
|
fputs(_(" -f, --force force unmount (in case of an unreachable NFS system)\n"), out);
|
|
|
|
fputs(_(" -i, --internal-only don't call the umount.<type> helpers\n"), out);
|
|
|
|
fputs(_(" -n, --no-mtab don't write to /etc/mtab\n"), out);
|
2013-05-29 14:52:56 -05:00
|
|
|
fputs(_(" -l, --lazy detach the filesystem now, clean up things later\n"), out);
|
2013-01-22 17:27:10 -06:00
|
|
|
fputs(_(" -O, --test-opts <list> limit the set of filesystems (use with -a)\n"), out);
|
|
|
|
fputs(_(" -R, --recursive recursively unmount a target with all its children\n"), out);
|
2013-05-29 14:52:56 -05:00
|
|
|
fputs(_(" -r, --read-only in case unmounting fails, try to remount read-only\n"), out);
|
2013-01-22 17:27:10 -06:00
|
|
|
fputs(_(" -t, --types <list> limit the set of filesystem types\n"), out);
|
|
|
|
fputs(_(" -v, --verbose say what is being done\n"), out);
|
2018-08-01 02:10:07 -05:00
|
|
|
fputs(_(" -q, --quiet suppress 'not mounted' error messages\n"), out);
|
2018-04-17 08:52:54 -05:00
|
|
|
fputs(_(" -N, --namespace <ns> perform umount in another namespace\n"), out);
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
fputs(USAGE_SEPARATOR, out);
|
2017-06-29 08:52:16 -05:00
|
|
|
printf(USAGE_HELP_OPTIONS(25));
|
|
|
|
printf(USAGE_MAN_TAIL("umount(8)"));
|
2011-11-29 12:02:27 -06:00
|
|
|
|
2017-06-19 13:52:50 -05:00
|
|
|
exit(MNT_EX_SUCCESS);
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
|
|
|
|
mount: no exit on EPERM, continue without suid
The current libmount assumes that mount(8) and umount(8) are suid
binaries. For this reason it implements internal rules which
restrict what is allowed for non-root users. Unfortunately, it's
out of reality for some use-cases where root permissions are no
required. Nice example are fuse filesystems.
So, the current situation is to call exit() always when mount, umount or
libmount are unsure with non-root user rights. This patch removes the
exit() call and replaces it with suid permissions drop, after that it
continues as usually. It means after suid-drop all depend on kernel
and no another security rule is used by libmount (simply because any
rule is no more necessary).
Example:
old version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
mount: only root can use "--types" option
new version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
kzak@192.168.111.1's password:
$ findmnt /home/kzak/mnt
TARGET SOURCE FSTYPE OPTIONS
/home/kzak/mnt kzak@192.168.111.1:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000
$ umount /home/kzak/mnt
$ echo $?
0
Note that fuse user umount is supported since v2.34 due to user_id= in
kernel mount table.
Signed-off-by: Karel Zak <kzak@redhat.com>
2019-11-19 07:58:20 -06:00
|
|
|
static void suid_drop(struct libmnt_context *cxt)
|
2011-11-29 12:02:27 -06:00
|
|
|
{
|
|
|
|
const uid_t ruid = getuid();
|
|
|
|
const uid_t euid = geteuid();
|
|
|
|
|
mount: no exit on EPERM, continue without suid
The current libmount assumes that mount(8) and umount(8) are suid
binaries. For this reason it implements internal rules which
restrict what is allowed for non-root users. Unfortunately, it's
out of reality for some use-cases where root permissions are no
required. Nice example are fuse filesystems.
So, the current situation is to call exit() always when mount, umount or
libmount are unsure with non-root user rights. This patch removes the
exit() call and replaces it with suid permissions drop, after that it
continues as usually. It means after suid-drop all depend on kernel
and no another security rule is used by libmount (simply because any
rule is no more necessary).
Example:
old version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
mount: only root can use "--types" option
new version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
kzak@192.168.111.1's password:
$ findmnt /home/kzak/mnt
TARGET SOURCE FSTYPE OPTIONS
/home/kzak/mnt kzak@192.168.111.1:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000
$ umount /home/kzak/mnt
$ echo $?
0
Note that fuse user umount is supported since v2.34 due to user_id= in
kernel mount table.
Signed-off-by: Karel Zak <kzak@redhat.com>
2019-11-19 07:58:20 -06:00
|
|
|
if (ruid != 0 && euid == 0) {
|
|
|
|
if (setgid(getgid()) < 0)
|
|
|
|
err(MNT_EX_FAIL, _("setgid() failed"));
|
|
|
|
|
|
|
|
if (setuid(getuid()) < 0)
|
|
|
|
err(MNT_EX_FAIL, _("setuid() failed"));
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
mount: no exit on EPERM, continue without suid
The current libmount assumes that mount(8) and umount(8) are suid
binaries. For this reason it implements internal rules which
restrict what is allowed for non-root users. Unfortunately, it's
out of reality for some use-cases where root permissions are no
required. Nice example are fuse filesystems.
So, the current situation is to call exit() always when mount, umount or
libmount are unsure with non-root user rights. This patch removes the
exit() call and replaces it with suid permissions drop, after that it
continues as usually. It means after suid-drop all depend on kernel
and no another security rule is used by libmount (simply because any
rule is no more necessary).
Example:
old version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
mount: only root can use "--types" option
new version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
kzak@192.168.111.1's password:
$ findmnt /home/kzak/mnt
TARGET SOURCE FSTYPE OPTIONS
/home/kzak/mnt kzak@192.168.111.1:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000
$ umount /home/kzak/mnt
$ echo $?
0
Note that fuse user umount is supported since v2.34 due to user_id= in
kernel mount table.
Signed-off-by: Karel Zak <kzak@redhat.com>
2019-11-19 07:58:20 -06:00
|
|
|
|
|
|
|
/* be paranoid and check it, setuid(0) has to fail */
|
|
|
|
if (ruid != 0 && setuid(0) == 0)
|
|
|
|
errx(MNT_EX_FAIL, _("drop permissions failed."));
|
|
|
|
|
|
|
|
mnt_context_force_unrestricted(cxt);
|
2020-08-25 03:48:29 -05:00
|
|
|
|
|
|
|
/* restore "bad" environment variables */
|
|
|
|
if (envs_removed) {
|
|
|
|
env_list_setenv(envs_removed);
|
|
|
|
env_list_free(envs_removed);
|
|
|
|
envs_removed = NULL;
|
|
|
|
}
|
2012-01-23 04:15:41 -06:00
|
|
|
}
|
|
|
|
|
2012-10-09 04:56:35 -05:00
|
|
|
static void success_message(struct libmnt_context *cxt)
|
|
|
|
{
|
|
|
|
const char *tgt, *src;
|
|
|
|
|
|
|
|
if (mnt_context_helper_executed(cxt)
|
|
|
|
|| mnt_context_get_status(cxt) != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
tgt = mnt_context_get_target(cxt);
|
|
|
|
if (!tgt)
|
|
|
|
return;
|
|
|
|
|
|
|
|
src = mnt_context_get_source(cxt);
|
|
|
|
if (src)
|
|
|
|
warnx(_("%s (%s) unmounted"), tgt, src);
|
|
|
|
else
|
|
|
|
warnx(_("%s unmounted"), tgt);
|
|
|
|
}
|
|
|
|
|
2012-01-23 04:15:41 -06:00
|
|
|
static int mk_exit_code(struct libmnt_context *cxt, int rc)
|
|
|
|
{
|
2017-04-27 07:11:50 -05:00
|
|
|
char buf[BUFSIZ] = { 0 };
|
|
|
|
|
|
|
|
rc = mnt_context_get_excode(cxt, rc, buf, sizeof(buf));
|
2018-08-01 02:10:07 -05:00
|
|
|
|
|
|
|
/* suppress "not mounted" error message */
|
|
|
|
if (quiet &&
|
|
|
|
rc == MNT_EX_FAIL &&
|
|
|
|
mnt_context_syscall_called(cxt) &&
|
|
|
|
mnt_context_get_syscall_errno(cxt) == EINVAL)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
/* print errors/warnings */
|
2017-04-27 07:11:50 -05:00
|
|
|
if (*buf) {
|
|
|
|
const char *spec = mnt_context_get_target(cxt);
|
|
|
|
if (!spec)
|
|
|
|
spec = mnt_context_get_source(cxt);
|
|
|
|
if (!spec)
|
|
|
|
spec = "???";
|
2018-05-10 15:18:53 -05:00
|
|
|
warnx("%s: %s.", spec, buf);
|
2012-01-23 04:15:41 -06:00
|
|
|
}
|
2017-04-27 07:11:50 -05:00
|
|
|
return rc;
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
|
|
|
|
2011-12-01 09:47:26 -06:00
|
|
|
static int umount_all(struct libmnt_context *cxt)
|
2011-11-29 12:02:27 -06:00
|
|
|
{
|
2011-12-01 09:47:26 -06:00
|
|
|
struct libmnt_iter *itr;
|
|
|
|
struct libmnt_fs *fs;
|
|
|
|
int mntrc, ignored, rc = 0;
|
|
|
|
|
|
|
|
itr = mnt_new_iter(MNT_ITER_BACKWARD);
|
|
|
|
if (!itr) {
|
|
|
|
warn(_("failed to initialize libmount iterator"));
|
2017-04-27 07:25:57 -05:00
|
|
|
return MNT_EX_SYSERR;
|
2011-12-01 09:47:26 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
while (mnt_context_next_umount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
|
|
|
|
|
|
|
|
const char *tgt = mnt_fs_get_target(fs);
|
|
|
|
|
|
|
|
if (ignored) {
|
|
|
|
if (mnt_context_is_verbose(cxt))
|
|
|
|
printf(_("%-25s: ignored\n"), tgt);
|
|
|
|
} else {
|
2014-04-07 04:59:30 -05:00
|
|
|
int xrc = mk_exit_code(cxt, mntrc);
|
2012-01-23 04:15:41 -06:00
|
|
|
|
2017-04-27 07:25:57 -05:00
|
|
|
if (xrc == MNT_EX_SUCCESS
|
2014-04-07 04:59:30 -05:00
|
|
|
&& mnt_context_is_verbose(cxt))
|
2013-05-29 14:52:56 -05:00
|
|
|
printf("%-25s: successfully unmounted\n", tgt);
|
2014-04-07 04:59:30 -05:00
|
|
|
rc |= xrc;
|
2011-12-01 09:47:26 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-30 16:49:00 -06:00
|
|
|
mnt_free_iter(itr);
|
2011-12-01 09:47:26 -06:00
|
|
|
return rc;
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
|
|
|
|
|
|
|
static int umount_one(struct libmnt_context *cxt, const char *spec)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (!spec)
|
2017-04-27 07:25:57 -05:00
|
|
|
return MNT_EX_SOFTWARE;
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
if (mnt_context_set_target(cxt, spec))
|
2017-04-27 07:25:57 -05:00
|
|
|
err(MNT_EX_SYSERR, _("failed to set umount target"));
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
rc = mnt_context_umount(cxt);
|
mount: no exit on EPERM, continue without suid
The current libmount assumes that mount(8) and umount(8) are suid
binaries. For this reason it implements internal rules which
restrict what is allowed for non-root users. Unfortunately, it's
out of reality for some use-cases where root permissions are no
required. Nice example are fuse filesystems.
So, the current situation is to call exit() always when mount, umount or
libmount are unsure with non-root user rights. This patch removes the
exit() call and replaces it with suid permissions drop, after that it
continues as usually. It means after suid-drop all depend on kernel
and no another security rule is used by libmount (simply because any
rule is no more necessary).
Example:
old version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
mount: only root can use "--types" option
new version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
kzak@192.168.111.1's password:
$ findmnt /home/kzak/mnt
TARGET SOURCE FSTYPE OPTIONS
/home/kzak/mnt kzak@192.168.111.1:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000
$ umount /home/kzak/mnt
$ echo $?
0
Note that fuse user umount is supported since v2.34 due to user_id= in
kernel mount table.
Signed-off-by: Karel Zak <kzak@redhat.com>
2019-11-19 07:58:20 -06:00
|
|
|
|
|
|
|
if (rc == -EPERM
|
|
|
|
&& mnt_context_is_restricted(cxt)
|
2020-02-24 06:02:09 -06:00
|
|
|
&& mnt_context_tab_applied(cxt)
|
mount: no exit on EPERM, continue without suid
The current libmount assumes that mount(8) and umount(8) are suid
binaries. For this reason it implements internal rules which
restrict what is allowed for non-root users. Unfortunately, it's
out of reality for some use-cases where root permissions are no
required. Nice example are fuse filesystems.
So, the current situation is to call exit() always when mount, umount or
libmount are unsure with non-root user rights. This patch removes the
exit() call and replaces it with suid permissions drop, after that it
continues as usually. It means after suid-drop all depend on kernel
and no another security rule is used by libmount (simply because any
rule is no more necessary).
Example:
old version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
mount: only root can use "--types" option
new version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
kzak@192.168.111.1's password:
$ findmnt /home/kzak/mnt
TARGET SOURCE FSTYPE OPTIONS
/home/kzak/mnt kzak@192.168.111.1:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000
$ umount /home/kzak/mnt
$ echo $?
0
Note that fuse user umount is supported since v2.34 due to user_id= in
kernel mount table.
Signed-off-by: Karel Zak <kzak@redhat.com>
2019-11-19 07:58:20 -06:00
|
|
|
&& !mnt_context_syscall_called(cxt)) {
|
2020-02-24 06:02:09 -06:00
|
|
|
/* Mountpoint exists, but failed something else in libmount,
|
|
|
|
* drop perms and try it again */
|
mount: no exit on EPERM, continue without suid
The current libmount assumes that mount(8) and umount(8) are suid
binaries. For this reason it implements internal rules which
restrict what is allowed for non-root users. Unfortunately, it's
out of reality for some use-cases where root permissions are no
required. Nice example are fuse filesystems.
So, the current situation is to call exit() always when mount, umount or
libmount are unsure with non-root user rights. This patch removes the
exit() call and replaces it with suid permissions drop, after that it
continues as usually. It means after suid-drop all depend on kernel
and no another security rule is used by libmount (simply because any
rule is no more necessary).
Example:
old version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
mount: only root can use "--types" option
new version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
kzak@192.168.111.1's password:
$ findmnt /home/kzak/mnt
TARGET SOURCE FSTYPE OPTIONS
/home/kzak/mnt kzak@192.168.111.1:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000
$ umount /home/kzak/mnt
$ echo $?
0
Note that fuse user umount is supported since v2.34 due to user_id= in
kernel mount table.
Signed-off-by: Karel Zak <kzak@redhat.com>
2019-11-19 07:58:20 -06:00
|
|
|
suid_drop(cxt);
|
|
|
|
rc = mnt_context_umount(cxt);
|
|
|
|
}
|
|
|
|
|
2012-01-23 04:15:41 -06:00
|
|
|
rc = mk_exit_code(cxt, rc);
|
2011-11-29 12:02:27 -06:00
|
|
|
|
2017-04-27 07:25:57 -05:00
|
|
|
if (rc == MNT_EX_SUCCESS && mnt_context_is_verbose(cxt))
|
2012-10-09 04:56:35 -05:00
|
|
|
success_message(cxt);
|
|
|
|
|
2011-11-29 12:02:27 -06:00
|
|
|
mnt_reset_context(cxt);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2013-02-26 07:50:26 -06:00
|
|
|
static struct libmnt_table *new_mountinfo(struct libmnt_context *cxt)
|
|
|
|
{
|
2018-04-24 11:05:04 -05:00
|
|
|
struct libmnt_table *tb;
|
|
|
|
struct libmnt_ns *ns_old = mnt_context_switch_target_ns(cxt);
|
|
|
|
|
|
|
|
if (!ns_old)
|
|
|
|
err(MNT_EX_SYSERR, _("failed to switch namespace"));
|
|
|
|
|
|
|
|
tb = mnt_new_table();
|
2013-02-26 07:50:26 -06:00
|
|
|
if (!tb)
|
2017-04-27 07:25:57 -05:00
|
|
|
err(MNT_EX_SYSERR, _("libmount table allocation failed"));
|
2013-02-26 07:50:26 -06:00
|
|
|
|
|
|
|
mnt_table_set_parser_errcb(tb, table_parser_errcb);
|
|
|
|
mnt_table_set_cache(tb, mnt_context_get_cache(cxt));
|
|
|
|
|
|
|
|
if (mnt_table_parse_file(tb, _PATH_PROC_MOUNTINFO)) {
|
|
|
|
warn(_("failed to parse %s"), _PATH_PROC_MOUNTINFO);
|
2013-08-21 09:07:51 -05:00
|
|
|
mnt_unref_table(tb);
|
2013-02-26 07:50:26 -06:00
|
|
|
tb = NULL;
|
|
|
|
}
|
|
|
|
|
2018-04-24 11:05:04 -05:00
|
|
|
if (!mnt_context_switch_ns(cxt, ns_old))
|
|
|
|
err(MNT_EX_SYSERR, _("failed to switch namespace"));
|
|
|
|
|
2013-02-26 07:50:26 -06:00
|
|
|
return tb;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* like umount_one() but does not return error is @spec not mounted
|
|
|
|
*/
|
|
|
|
static int umount_one_if_mounted(struct libmnt_context *cxt, const char *spec)
|
|
|
|
{
|
|
|
|
int rc;
|
|
|
|
struct libmnt_fs *fs;
|
|
|
|
|
|
|
|
rc = mnt_context_find_umount_fs(cxt, spec, &fs);
|
|
|
|
if (rc == 1) {
|
2017-04-27 07:25:57 -05:00
|
|
|
rc = MNT_EX_SUCCESS; /* already unmounted */
|
2013-02-26 07:50:26 -06:00
|
|
|
mnt_reset_context(cxt);
|
|
|
|
} else if (rc < 0) {
|
|
|
|
rc = mk_exit_code(cxt, rc); /* error */
|
|
|
|
mnt_reset_context(cxt);
|
|
|
|
} else
|
|
|
|
rc = umount_one(cxt, mnt_fs_get_target(fs));
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-11-07 12:02:28 -06:00
|
|
|
static int umount_do_recurse(struct libmnt_context *cxt,
|
2013-02-26 07:50:26 -06:00
|
|
|
struct libmnt_table *tb, struct libmnt_fs *fs)
|
2012-11-07 12:02:28 -06:00
|
|
|
{
|
2021-03-22 05:29:28 -05:00
|
|
|
struct libmnt_fs *child, *over = NULL;
|
2012-11-07 12:02:28 -06:00
|
|
|
struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_BACKWARD);
|
2013-02-26 07:50:26 -06:00
|
|
|
int rc;
|
2012-11-07 12:02:28 -06:00
|
|
|
|
|
|
|
if (!itr)
|
2017-04-27 07:25:57 -05:00
|
|
|
err(MNT_EX_SYSERR, _("libmount iterator allocation failed"));
|
2013-02-26 07:50:26 -06:00
|
|
|
|
2021-03-22 05:29:28 -05:00
|
|
|
/* first try overmount */
|
|
|
|
if (mnt_table_over_fs(tb, fs, &over) == 0 && over) {
|
|
|
|
rc = umount_do_recurse(cxt, tb, over);
|
|
|
|
if (rc != MNT_EX_SUCCESS)
|
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2016-05-29 16:11:53 -05:00
|
|
|
/* umount all children */
|
2012-11-07 12:02:28 -06:00
|
|
|
for (;;) {
|
2013-02-26 07:50:26 -06:00
|
|
|
rc = mnt_table_next_child_fs(tb, itr, fs, &child);
|
2012-11-07 12:02:28 -06:00
|
|
|
if (rc < 0) {
|
2013-02-26 07:50:26 -06:00
|
|
|
warnx(_("failed to get child fs of %s"),
|
|
|
|
mnt_fs_get_target(fs));
|
2017-04-27 07:25:57 -05:00
|
|
|
rc = MNT_EX_SOFTWARE;
|
2012-11-07 12:02:28 -06:00
|
|
|
goto done;
|
|
|
|
} else if (rc == 1)
|
|
|
|
break; /* no more children */
|
|
|
|
|
2021-03-22 05:29:28 -05:00
|
|
|
if (over && child == over)
|
|
|
|
continue;
|
|
|
|
|
2012-11-07 12:02:28 -06:00
|
|
|
rc = umount_do_recurse(cxt, tb, child);
|
2017-04-27 07:25:57 -05:00
|
|
|
if (rc != MNT_EX_SUCCESS)
|
2012-11-07 12:02:28 -06:00
|
|
|
goto done;
|
|
|
|
}
|
|
|
|
|
2013-02-26 07:50:26 -06:00
|
|
|
rc = umount_one_if_mounted(cxt, mnt_fs_get_target(fs));
|
2012-11-07 12:02:28 -06:00
|
|
|
done:
|
|
|
|
mnt_free_iter(itr);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int umount_recursive(struct libmnt_context *cxt, const char *spec)
|
|
|
|
{
|
|
|
|
struct libmnt_table *tb;
|
2013-02-26 07:50:26 -06:00
|
|
|
struct libmnt_fs *fs;
|
2012-11-07 12:02:28 -06:00
|
|
|
int rc;
|
|
|
|
|
2013-02-26 07:50:26 -06:00
|
|
|
tb = new_mountinfo(cxt);
|
|
|
|
if (!tb)
|
2017-04-27 07:25:57 -05:00
|
|
|
return MNT_EX_SOFTWARE;
|
2013-02-26 07:50:26 -06:00
|
|
|
|
2012-11-15 09:44:07 -06:00
|
|
|
/* it's always real mountpoint, don't assume that the target maybe a device */
|
|
|
|
mnt_context_disable_swapmatch(cxt, 1);
|
|
|
|
|
2013-02-26 07:50:26 -06:00
|
|
|
fs = mnt_table_find_target(tb, spec, MNT_ITER_BACKWARD);
|
|
|
|
if (fs)
|
|
|
|
rc = umount_do_recurse(cxt, tb, fs);
|
|
|
|
else {
|
2017-04-27 07:25:57 -05:00
|
|
|
rc = MNT_EX_USAGE;
|
2018-08-01 02:10:07 -05:00
|
|
|
if (!quiet)
|
|
|
|
warnx(access(spec, F_OK) == 0 ?
|
2013-02-26 07:50:26 -06:00
|
|
|
_("%s: not mounted") :
|
|
|
|
_("%s: not found"), spec);
|
|
|
|
}
|
2012-11-15 04:55:48 -06:00
|
|
|
|
2013-08-21 09:07:51 -05:00
|
|
|
mnt_unref_table(tb);
|
2013-02-26 07:50:26 -06:00
|
|
|
return rc;
|
|
|
|
}
|
2012-11-15 22:18:07 -06:00
|
|
|
|
2013-02-26 07:50:26 -06:00
|
|
|
static int umount_alltargets(struct libmnt_context *cxt, const char *spec, int rec)
|
|
|
|
{
|
|
|
|
struct libmnt_fs *fs;
|
|
|
|
struct libmnt_table *tb;
|
|
|
|
struct libmnt_iter *itr = NULL;
|
2013-04-23 03:25:02 -05:00
|
|
|
dev_t devno = 0;
|
2013-02-26 07:50:26 -06:00
|
|
|
int rc;
|
|
|
|
|
|
|
|
/* Convert @spec to device name, Use the same logic like regular
|
|
|
|
* "umount <spec>".
|
2012-11-07 12:02:28 -06:00
|
|
|
*/
|
2013-02-26 07:50:26 -06:00
|
|
|
rc = mnt_context_find_umount_fs(cxt, spec, &fs);
|
|
|
|
if (rc == 1) {
|
2017-04-27 07:25:57 -05:00
|
|
|
rc = MNT_EX_USAGE;
|
2018-08-01 02:10:07 -05:00
|
|
|
if (!quiet)
|
|
|
|
warnx(access(spec, F_OK) == 0 ?
|
2013-02-26 07:50:26 -06:00
|
|
|
_("%s: not mounted") :
|
|
|
|
_("%s: not found"), spec);
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
if (rc < 0)
|
|
|
|
return mk_exit_code(cxt, rc); /* error */
|
2012-11-07 12:02:28 -06:00
|
|
|
|
2013-04-23 03:25:02 -05:00
|
|
|
if (!mnt_fs_get_srcpath(fs) || !mnt_fs_get_devno(fs))
|
2017-04-27 07:25:57 -05:00
|
|
|
errx(MNT_EX_USAGE, _("%s: failed to determine source "
|
2014-05-26 04:37:02 -05:00
|
|
|
"(--all-targets is unsupported on systems with "
|
|
|
|
"regular mtab file)."), spec);
|
2013-02-26 07:50:26 -06:00
|
|
|
|
|
|
|
itr = mnt_new_iter(MNT_ITER_BACKWARD);
|
|
|
|
if (!itr)
|
2017-04-27 07:25:57 -05:00
|
|
|
err(MNT_EX_SYSERR, _("libmount iterator allocation failed"));
|
2013-02-26 07:50:26 -06:00
|
|
|
|
|
|
|
/* get on @cxt independent mountinfo */
|
|
|
|
tb = new_mountinfo(cxt);
|
2014-07-17 08:12:35 -05:00
|
|
|
if (!tb) {
|
2017-04-27 07:25:57 -05:00
|
|
|
rc = MNT_EX_SOFTWARE;
|
2014-07-17 08:12:35 -05:00
|
|
|
goto done;
|
|
|
|
}
|
2013-02-26 07:50:26 -06:00
|
|
|
|
2016-05-29 16:11:53 -05:00
|
|
|
/* Note that @fs is from mount context and the context will be reset
|
2013-02-26 07:50:26 -06:00
|
|
|
* after each umount() call */
|
2013-04-23 03:25:02 -05:00
|
|
|
devno = mnt_fs_get_devno(fs);
|
2013-02-26 07:50:26 -06:00
|
|
|
fs = NULL;
|
|
|
|
|
|
|
|
mnt_reset_context(cxt);
|
|
|
|
|
|
|
|
while (mnt_table_next_fs(tb, itr, &fs) == 0) {
|
2013-04-23 03:25:02 -05:00
|
|
|
if (mnt_fs_get_devno(fs) != devno)
|
2013-02-26 07:50:26 -06:00
|
|
|
continue;
|
|
|
|
mnt_context_disable_swapmatch(cxt, 1);
|
|
|
|
if (rec)
|
2012-11-07 12:02:28 -06:00
|
|
|
rc = umount_do_recurse(cxt, tb, fs);
|
2013-02-26 07:50:26 -06:00
|
|
|
else
|
|
|
|
rc = umount_one_if_mounted(cxt, mnt_fs_get_target(fs));
|
|
|
|
|
2017-04-27 07:25:57 -05:00
|
|
|
if (rc != MNT_EX_SUCCESS)
|
2013-02-26 07:50:26 -06:00
|
|
|
break;
|
2012-11-07 12:02:28 -06:00
|
|
|
}
|
|
|
|
|
2014-07-17 08:12:35 -05:00
|
|
|
done:
|
2013-02-26 07:50:26 -06:00
|
|
|
mnt_free_iter(itr);
|
2013-08-21 09:07:51 -05:00
|
|
|
mnt_unref_table(tb);
|
2013-02-26 07:50:26 -06:00
|
|
|
|
2012-11-07 12:02:28 -06:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
2012-11-26 09:25:46 -06:00
|
|
|
/*
|
|
|
|
* Check path -- non-root user should not be able to resolve path which is
|
2020-08-28 12:17:00 -05:00
|
|
|
* unreadable for them.
|
2012-11-26 09:25:46 -06:00
|
|
|
*/
|
|
|
|
static char *sanitize_path(const char *path)
|
|
|
|
{
|
|
|
|
char *p;
|
|
|
|
|
|
|
|
if (!path)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
p = canonicalize_path_restricted(path);
|
|
|
|
if (!p)
|
2017-04-27 07:25:57 -05:00
|
|
|
err(MNT_EX_USAGE, "%s", path);
|
2012-11-26 09:25:46 -06:00
|
|
|
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2018-04-20 10:57:39 -05:00
|
|
|
static pid_t parse_pid(const char *str)
|
|
|
|
{
|
|
|
|
char *end;
|
|
|
|
pid_t ret;
|
|
|
|
|
|
|
|
errno = 0;
|
|
|
|
ret = strtoul(str, &end, 10);
|
|
|
|
|
|
|
|
if (ret < 0 || errno || end == str || (end && *end))
|
|
|
|
return 0;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2011-11-29 12:02:27 -06:00
|
|
|
int main(int argc, char **argv)
|
|
|
|
{
|
2013-02-26 07:50:26 -06:00
|
|
|
int c, rc = 0, all = 0, recursive = 0, alltargets = 0;
|
2011-11-29 12:02:27 -06:00
|
|
|
struct libmnt_context *cxt;
|
|
|
|
char *types = NULL;
|
|
|
|
|
|
|
|
enum {
|
|
|
|
UMOUNT_OPT_FAKE = CHAR_MAX + 1,
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct option longopts[] = {
|
2017-02-11 14:23:26 -06:00
|
|
|
{ "all", no_argument, NULL, 'a' },
|
|
|
|
{ "all-targets", no_argument, NULL, 'A' },
|
|
|
|
{ "detach-loop", no_argument, NULL, 'd' },
|
|
|
|
{ "fake", no_argument, NULL, UMOUNT_OPT_FAKE },
|
|
|
|
{ "force", no_argument, NULL, 'f' },
|
|
|
|
{ "help", no_argument, NULL, 'h' },
|
|
|
|
{ "internal-only", no_argument, NULL, 'i' },
|
|
|
|
{ "lazy", no_argument, NULL, 'l' },
|
|
|
|
{ "no-canonicalize", no_argument, NULL, 'c' },
|
|
|
|
{ "no-mtab", no_argument, NULL, 'n' },
|
2018-08-01 02:10:07 -05:00
|
|
|
{ "quiet", no_argument, NULL, 'q' },
|
2017-02-11 14:23:26 -06:00
|
|
|
{ "read-only", no_argument, NULL, 'r' },
|
|
|
|
{ "recursive", no_argument, NULL, 'R' },
|
|
|
|
{ "test-opts", required_argument, NULL, 'O' },
|
|
|
|
{ "types", required_argument, NULL, 't' },
|
|
|
|
{ "verbose", no_argument, NULL, 'v' },
|
|
|
|
{ "version", no_argument, NULL, 'V' },
|
2018-03-15 08:06:48 -05:00
|
|
|
{ "namespace", required_argument, NULL, 'N' },
|
2017-02-11 14:23:26 -06:00
|
|
|
{ NULL, 0, NULL, 0 }
|
2011-11-29 12:02:27 -06:00
|
|
|
};
|
|
|
|
|
2017-02-10 05:05:04 -06:00
|
|
|
static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
|
2013-02-26 07:50:26 -06:00
|
|
|
{ 'A','a' }, /* all-targets,all */
|
2012-11-15 04:55:48 -06:00
|
|
|
{ 'R','a' }, /* recursive,all */
|
|
|
|
{ 'O','R','t'}, /* options,recursive,types */
|
|
|
|
{ 'R','r' }, /* recursive,read-only */
|
|
|
|
{ 0 }
|
|
|
|
};
|
|
|
|
int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
|
|
|
|
|
2020-08-25 03:48:29 -05:00
|
|
|
__sanitize_env(&envs_removed);
|
2011-11-29 12:02:27 -06:00
|
|
|
setlocale(LC_ALL, "");
|
|
|
|
bindtextdomain(PACKAGE, LOCALEDIR);
|
|
|
|
textdomain(PACKAGE);
|
2019-04-16 08:14:13 -05:00
|
|
|
close_stdout_atexit();
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
mnt_init_debug(0);
|
|
|
|
cxt = mnt_new_context();
|
|
|
|
if (!cxt)
|
2017-04-27 07:25:57 -05:00
|
|
|
err(MNT_EX_SYSERR, _("libmount context allocation failed"));
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
mnt_context_set_tables_errcb(cxt, table_parser_errcb);
|
|
|
|
|
2018-12-10 07:34:12 -06:00
|
|
|
while ((c = getopt_long(argc, argv, "aAcdfhilnqRrO:t:vVN:",
|
2011-11-29 12:02:27 -06:00
|
|
|
longopts, NULL)) != -1) {
|
|
|
|
|
|
|
|
|
|
|
|
/* only few options are allowed for non-root users */
|
2020-11-19 04:12:06 -06:00
|
|
|
if (mnt_context_is_restricted(cxt) && !strchr("hdilqVv", c)) {
|
|
|
|
|
|
|
|
/* Silently ignore options without direct impact to the
|
|
|
|
* umount operation, but with security sensitive
|
|
|
|
* side-effects */
|
|
|
|
if (strchr("c", c))
|
|
|
|
continue; /* ignore */
|
|
|
|
|
|
|
|
/* drop permissions, continue as regular user */
|
mount: no exit on EPERM, continue without suid
The current libmount assumes that mount(8) and umount(8) are suid
binaries. For this reason it implements internal rules which
restrict what is allowed for non-root users. Unfortunately, it's
out of reality for some use-cases where root permissions are no
required. Nice example are fuse filesystems.
So, the current situation is to call exit() always when mount, umount or
libmount are unsure with non-root user rights. This patch removes the
exit() call and replaces it with suid permissions drop, after that it
continues as usually. It means after suid-drop all depend on kernel
and no another security rule is used by libmount (simply because any
rule is no more necessary).
Example:
old version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
mount: only root can use "--types" option
new version:
$ mount -t fuse.sshfs kzak@192.168.111.1:/home/kzak /home/kzak/mnt
kzak@192.168.111.1's password:
$ findmnt /home/kzak/mnt
TARGET SOURCE FSTYPE OPTIONS
/home/kzak/mnt kzak@192.168.111.1:/home/kzak fuse.sshfs rw,nosuid,nodev,relatime,user_id=1000,group_id=1000
$ umount /home/kzak/mnt
$ echo $?
0
Note that fuse user umount is supported since v2.34 due to user_id= in
kernel mount table.
Signed-off-by: Karel Zak <kzak@redhat.com>
2019-11-19 07:58:20 -06:00
|
|
|
suid_drop(cxt);
|
2020-11-19 04:12:06 -06:00
|
|
|
}
|
2011-11-29 12:02:27 -06:00
|
|
|
|
2012-11-15 04:55:48 -06:00
|
|
|
err_exclusive_options(c, longopts, excl, excl_st);
|
|
|
|
|
2011-11-29 12:02:27 -06:00
|
|
|
switch(c) {
|
|
|
|
case 'a':
|
|
|
|
all = 1;
|
|
|
|
break;
|
2013-02-26 07:50:26 -06:00
|
|
|
case 'A':
|
|
|
|
alltargets = 1;
|
|
|
|
break;
|
2011-11-29 12:02:27 -06:00
|
|
|
case 'c':
|
|
|
|
mnt_context_disable_canonicalize(cxt, TRUE);
|
|
|
|
break;
|
|
|
|
case 'd':
|
|
|
|
mnt_context_enable_loopdel(cxt, TRUE);
|
|
|
|
break;
|
|
|
|
case UMOUNT_OPT_FAKE:
|
|
|
|
mnt_context_enable_fake(cxt, TRUE);
|
|
|
|
break;
|
|
|
|
case 'f':
|
|
|
|
mnt_context_enable_force(cxt, TRUE);
|
|
|
|
break;
|
|
|
|
case 'i':
|
|
|
|
mnt_context_disable_helpers(cxt, TRUE);
|
|
|
|
break;
|
|
|
|
case 'l':
|
|
|
|
mnt_context_enable_lazy(cxt, TRUE);
|
|
|
|
break;
|
|
|
|
case 'n':
|
|
|
|
mnt_context_disable_mtab(cxt, TRUE);
|
|
|
|
break;
|
2018-08-01 02:10:07 -05:00
|
|
|
case 'q':
|
|
|
|
quiet = 1;
|
|
|
|
break;
|
2011-11-29 12:02:27 -06:00
|
|
|
case 'r':
|
|
|
|
mnt_context_enable_rdonly_umount(cxt, TRUE);
|
|
|
|
break;
|
2012-11-07 12:02:28 -06:00
|
|
|
case 'R':
|
|
|
|
recursive = TRUE;
|
|
|
|
break;
|
2011-11-29 12:02:27 -06:00
|
|
|
case 'O':
|
|
|
|
if (mnt_context_set_options_pattern(cxt, optarg))
|
2017-04-27 07:25:57 -05:00
|
|
|
err(MNT_EX_SYSERR, _("failed to set options pattern"));
|
2011-11-29 12:02:27 -06:00
|
|
|
break;
|
|
|
|
case 't':
|
|
|
|
types = optarg;
|
|
|
|
break;
|
|
|
|
case 'v':
|
|
|
|
mnt_context_enable_verbose(cxt, TRUE);
|
|
|
|
break;
|
2018-03-15 08:06:48 -05:00
|
|
|
case 'N':
|
2018-04-20 10:57:39 -05:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
pid_t pid = parse_pid(optarg);
|
|
|
|
|
|
|
|
if (pid)
|
|
|
|
snprintf(path, sizeof(path), "/proc/%i/ns/mnt", pid);
|
|
|
|
|
|
|
|
if (mnt_context_set_target_ns(cxt, pid ? path : optarg))
|
|
|
|
err(MNT_EX_SYSERR, _("failed to set target namespace to %s"), pid ? path : optarg);
|
2018-06-11 09:06:17 -05:00
|
|
|
break;
|
2018-03-15 08:06:48 -05:00
|
|
|
}
|
2019-04-16 08:14:13 -05:00
|
|
|
|
|
|
|
case 'h':
|
|
|
|
mnt_free_context(cxt);
|
|
|
|
usage();
|
|
|
|
case 'V':
|
|
|
|
mnt_free_context(cxt);
|
|
|
|
umount_print_version();
|
2011-11-29 12:02:27 -06:00
|
|
|
default:
|
2017-04-27 07:25:57 -05:00
|
|
|
errtryhelp(MNT_EX_USAGE);
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
argc -= optind;
|
|
|
|
argv += optind;
|
|
|
|
|
|
|
|
if (all) {
|
2019-06-06 07:52:40 -05:00
|
|
|
if (argc) {
|
|
|
|
warnx(_("unexpected number of arguments"));
|
|
|
|
errtryhelp(MNT_EX_USAGE);
|
|
|
|
}
|
2011-11-29 12:02:27 -06:00
|
|
|
if (!types)
|
2017-02-09 04:21:49 -06:00
|
|
|
types = "noproc,nodevfs,nodevpts,nosysfs,norpc_pipefs,nonfsd,noselinuxfs";
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
mnt_context_set_fstype_pattern(cxt, types);
|
|
|
|
rc = umount_all(cxt);
|
|
|
|
|
|
|
|
} else if (argc < 1) {
|
2017-06-19 13:52:50 -05:00
|
|
|
warnx(_("bad usage"));
|
|
|
|
errtryhelp(MNT_EX_USAGE);
|
2011-11-29 12:02:27 -06:00
|
|
|
|
2013-02-26 07:50:26 -06:00
|
|
|
} else if (alltargets) {
|
|
|
|
while (argc--)
|
|
|
|
rc += umount_alltargets(cxt, *argv++, recursive);
|
2012-11-07 12:02:28 -06:00
|
|
|
} else if (recursive) {
|
|
|
|
while (argc--)
|
|
|
|
rc += umount_recursive(cxt, *argv++);
|
|
|
|
} else {
|
2012-11-26 09:25:46 -06:00
|
|
|
while (argc--) {
|
2013-11-19 10:55:12 -06:00
|
|
|
char *path = *argv;
|
2012-11-26 09:25:46 -06:00
|
|
|
|
2013-11-19 10:55:12 -06:00
|
|
|
if (mnt_context_is_restricted(cxt)
|
|
|
|
&& !mnt_tag_is_valid(path))
|
2012-11-26 09:25:46 -06:00
|
|
|
path = sanitize_path(path);
|
|
|
|
|
|
|
|
rc += umount_one(cxt, path);
|
|
|
|
|
2013-11-19 10:55:12 -06:00
|
|
|
if (path != *argv)
|
2012-11-26 09:25:46 -06:00
|
|
|
free(path);
|
2013-11-19 10:55:12 -06:00
|
|
|
argv++;
|
2012-11-26 09:25:46 -06:00
|
|
|
}
|
2012-11-07 12:02:28 -06:00
|
|
|
}
|
2011-11-29 12:02:27 -06:00
|
|
|
|
|
|
|
mnt_free_context(cxt);
|
2020-08-25 03:48:29 -05:00
|
|
|
env_list_free(envs_removed);
|
|
|
|
|
2014-06-07 08:38:00 -05:00
|
|
|
return (rc < 256) ? rc : 255;
|
2011-11-29 12:02:27 -06:00
|
|
|
}
|
|
|
|
|