]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/mount.c
taskset: Accept 0 pid for current process
[thirdparty/util-linux.git] / sys-utils / mount.c
CommitLineData
97073441 1/*
9abd5e4b
KZ
2 * SPDX-License-Identifier: GPL-2.0-or-later
3 *
97073441
KZ
4 * mount(8) -- mount a filesystem
5 *
6 * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
7 * Written by Karel Zak <kzak@redhat.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
97073441 13 */
97073441
KZ
14#include <stdio.h>
15#include <stdlib.h>
16#include <errno.h>
17#include <string.h>
18#include <getopt.h>
97073441
KZ
19#include <unistd.h>
20#include <sys/types.h>
dbae36fe 21#include <sys/mman.h>
ce433404 22#include <sys/stat.h>
2e86597f 23#include <stdarg.h>
2a1f429a 24#include <libmount.h>
5f7c1890 25#include <ctype.h>
2a1f429a 26
97073441
KZ
27#include "nls.h"
28#include "c.h"
6189ace3 29#include "env.h"
dbae36fe 30#include "strutils.h"
efb8854f 31#include "closestream.h"
5ebbc386 32#include "canonicalize.h"
1db07151 33#include "pathnames.h"
a5d0e6a8 34#include "strv.h"
97073441 35
778ca2a0
RM
36#define XALLOC_EXIT_CODE MNT_EX_SYSERR
37#include "xalloc.h"
38
e3a7a5f8 39#define OPTUTILS_EXIT_CODE MNT_EX_USAGE
38483b86
SK
40#include "optutils.h"
41
f1f48270
KZ
42static struct ul_env_list *envs_removed;
43
d946359a
KZ
44static int mk_exit_code(struct libmnt_context *cxt, int rc);
45
6497f2d9 46static void suid_drop(struct libmnt_context *cxt)
97073441
KZ
47{
48 const uid_t ruid = getuid();
49 const uid_t euid = geteuid();
50
17fc8693
KZ
51 if (ruid != 0 && euid == 0 && drop_permissions() != 0)
52 err(MNT_EX_FAIL, _("drop permissions failed"));
6497f2d9
KZ
53
54 /* be paranoid and check it, setuid(0) has to fail */
55 if (ruid != 0 && setuid(0) == 0)
56 errx(MNT_EX_FAIL, _("drop permissions failed."));
57
58 mnt_context_force_unrestricted(cxt);
f1f48270
KZ
59
60 /* restore "bad" environment variables */
61 if (envs_removed) {
0d87646b 62 env_list_setenv(envs_removed, 0);
f1f48270
KZ
63 env_list_free(envs_removed);
64 envs_removed = NULL;
65 }
97073441
KZ
66}
67
68224d10 68static void __attribute__((__noreturn__)) mount_print_version(void)
97073441
KZ
69{
70 const char *ver = NULL;
ac8ecab4 71 const char **features = NULL, **p;
97073441
KZ
72
73 mnt_get_library_version(&ver);
ac8ecab4
KZ
74 mnt_get_library_features(&features);
75
76 printf(_("%s from %s (libmount %s"),
77 program_invocation_short_name,
78 PACKAGE_STRING,
79 ver);
80 p = features;
81 while (p && *p) {
82 fputs(p == features ? ": " : ", ", stdout);
83 fputs(*p++, stdout);
84 }
85 fputs(")\n", stdout);
e3a7a5f8 86 exit(MNT_EX_SUCCESS);
97073441
KZ
87}
88
7fc6d2b8 89static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
9f7472b0
KZ
90 const char *filename, int line)
91{
92 if (filename)
b779c1ae 93 warnx(_("%s: parse error at line %d -- ignored"), filename, line);
1cd9d0d7 94 return 1;
9f7472b0
KZ
95}
96
5f7c1890
KZ
97/*
98 * Replace control chars with '?' to be compatible with coreutils. For more
99 * robust solution use findmnt(1) where we use \x?? hex encoding.
100 */
101static void safe_fputs(const char *data)
102{
103 const char *p;
104
105 for (p = data; p && *p; p++) {
106 if (iscntrl((unsigned char) *p))
107 fputc('?', stdout);
108 else
109 fputc(*p, stdout);
110 }
111}
112
11754572 113static void print_all(struct libmnt_context *cxt, char *pattern, int show_label)
97073441 114{
68164f6c 115 struct libmnt_table *tb;
a0c014dc 116 struct libmnt_iter *itr = NULL;
68164f6c
KZ
117 struct libmnt_fs *fs;
118 struct libmnt_cache *cache = NULL;
97073441 119
9004e76b
IK
120 mnt_context_enable_noautofs(cxt, 1);
121
11754572 122 if (mnt_context_get_mtab(cxt, &tb))
e3a7a5f8 123 err(MNT_EX_SYSERR, _("failed to read mtab"));
97073441
KZ
124
125 itr = mnt_new_iter(MNT_ITER_FORWARD);
11754572 126 if (!itr)
e3a7a5f8 127 err(MNT_EX_SYSERR, _("failed to initialize libmount iterator"));
97073441
KZ
128 if (show_label)
129 cache = mnt_new_cache();
130
9f7472b0 131 while (mnt_table_next_fs(tb, itr, &fs) == 0) {
97073441
KZ
132 const char *type = mnt_fs_get_fstype(fs);
133 const char *src = mnt_fs_get_source(fs);
7cf389f7 134 const char *optstr = mnt_fs_get_options(fs);
aa397ce5 135 char *xsrc = NULL;
97073441
KZ
136
137 if (type && pattern && !mnt_match_fstype(type, pattern))
138 continue;
139
902d2164 140 if (mnt_fs_is_regularfs(fs))
aa397ce5 141 xsrc = mnt_pretty_path(src, cache);
5f7c1890
KZ
142 printf ("%s on ", xsrc ? xsrc : src);
143 safe_fputs(mnt_fs_get_target(fs));
144
97073441
KZ
145 if (type)
146 printf (" type %s", type);
147 if (optstr)
148 printf (" (%s)", optstr);
149 if (show_label && src) {
150 char *lb = mnt_cache_find_tag_value(cache, src, "LABEL");
151 if (lb)
152 printf (" [%s]", lb);
153 }
154 fputc('\n', stdout);
2576b4e7 155 free(xsrc);
97073441 156 }
11754572 157
6195f9e6 158 mnt_unref_cache(cache);
b192b7b9 159 mnt_free_iter(itr);
97073441
KZ
160}
161
9f7472b0
KZ
162/*
163 * mount -a [-F]
9f7472b0 164 */
d2c97887 165static int mount_all(struct libmnt_context *cxt)
a9ae3955 166{
9f7472b0
KZ
167 struct libmnt_iter *itr;
168 struct libmnt_fs *fs;
e3a7a5f8 169 int mntrc, ignored, rc = MNT_EX_SUCCESS;
9f7472b0 170
16b73aae
KZ
171 int nsucc = 0, nerrs = 0;
172
9f7472b0
KZ
173 itr = mnt_new_iter(MNT_ITER_FORWARD);
174 if (!itr) {
175 warn(_("failed to initialize libmount iterator"));
e3a7a5f8 176 return MNT_EX_SYSERR;
9f7472b0
KZ
177 }
178
179 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
180
181 const char *tgt = mnt_fs_get_target(fs);
182
183 if (ignored) {
184 if (mnt_context_is_verbose(cxt))
b3f7a0ec
KZ
185 printf(ignored == 1 ? _("%-25s: ignored\n") :
186 _("%-25s: already mounted\n"),
9f7472b0 187 tgt);
d2c97887 188 } else if (mnt_context_is_fork(cxt)) {
d946359a
KZ
189 if (mnt_context_is_verbose(cxt))
190 printf("%-25s: mount successfully forked\n", tgt);
9f7472b0 191 } else {
e3a7a5f8 192 if (mk_exit_code(cxt, mntrc) == MNT_EX_SUCCESS) {
16b73aae 193 nsucc++;
d946359a 194
e3a7a5f8 195 /* Note that MNT_EX_SUCCESS return code does
8ab82185
KZ
196 * not mean that FS has been really mounted
197 * (e.g. nofail option) */
2bb3aa36 198 if (mnt_context_get_status(cxt)
8ab82185 199 && mnt_context_is_verbose(cxt))
d946359a 200 printf("%-25s: successfully mounted\n", tgt);
16b73aae
KZ
201 } else
202 nerrs++;
9f7472b0
KZ
203 }
204 }
205
d2c97887
KZ
206 if (mnt_context_is_parent(cxt)) {
207 /* wait for mount --fork children */
16b73aae
KZ
208 int nchildren = 0;
209
210 nerrs = 0, nsucc = 0;
d2c97887
KZ
211
212 rc = mnt_context_wait_for_children(cxt, &nchildren, &nerrs);
213 if (!rc && nchildren)
16b73aae 214 nsucc = nchildren - nerrs;
d2c97887
KZ
215 }
216
16b73aae 217 if (nerrs == 0)
e3a7a5f8 218 rc = MNT_EX_SUCCESS; /* all success */
16b73aae 219 else if (nsucc == 0)
e3a7a5f8 220 rc = MNT_EX_FAIL; /* all failed */
16b73aae 221 else
e3a7a5f8 222 rc = MNT_EX_SOMEOK; /* some success, some failed */
16b73aae 223
25609ee1 224 mnt_free_iter(itr);
9f7472b0 225 return rc;
a9ae3955
KZ
226}
227
189a1bf3
KZ
228
229/*
230 * mount -a -o remount
231 */
232static int remount_all(struct libmnt_context *cxt)
233{
234 struct libmnt_iter *itr;
235 struct libmnt_fs *fs;
236 int mntrc, ignored, rc = MNT_EX_SUCCESS;
237
238 int nsucc = 0, nerrs = 0;
239
240 itr = mnt_new_iter(MNT_ITER_FORWARD);
241 if (!itr) {
242 warn(_("failed to initialize libmount iterator"));
243 return MNT_EX_SYSERR;
244 }
245
246 while (mnt_context_next_remount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
247
248 const char *tgt = mnt_fs_get_target(fs);
249
250 if (ignored) {
251 if (mnt_context_is_verbose(cxt))
252 printf(_("%-25s: ignored\n"), tgt);
253 } else {
254 if (mk_exit_code(cxt, mntrc) == MNT_EX_SUCCESS) {
255 nsucc++;
256
257 /* Note that MNT_EX_SUCCESS return code does
258 * not mean that FS has been really mounted
259 * (e.g. nofail option) */
260 if (mnt_context_get_status(cxt)
261 && mnt_context_is_verbose(cxt))
262 printf("%-25s: successfully remounted\n", tgt);
263 } else
264 nerrs++;
265 }
266 }
267
268 if (nerrs == 0)
269 rc = MNT_EX_SUCCESS; /* all success */
270 else if (nsucc == 0)
271 rc = MNT_EX_FAIL; /* all failed */
272 else
273 rc = MNT_EX_SOMEOK; /* some success, some failed */
274
275 mnt_free_iter(itr);
276 return rc;
277}
278
84600ddc
KZ
279static void success_message(struct libmnt_context *cxt)
280{
281 unsigned long mflags = 0;
f5ae1d70 282 const char *tgt, *src, *pr = program_invocation_short_name;
84600ddc
KZ
283
284 if (mnt_context_helper_executed(cxt)
285 || mnt_context_get_status(cxt) != 1)
286 return;
287
288 mnt_context_get_mflags(cxt, &mflags);
289 tgt = mnt_context_get_target(cxt);
290 src = mnt_context_get_source(cxt);
291
292 if (mflags & MS_MOVE)
f5ae1d70 293 printf(_("%s: %s moved to %s.\n"), pr, src, tgt);
84600ddc 294 else if (mflags & MS_BIND)
9b4257c8 295 printf(_("%s: %s bound on %s.\n"), pr, src, tgt);
b4ec4573
KZ
296 else if (mflags & MS_PROPAGATION) {
297 if (src && strcmp(src, "none") != 0 && tgt)
298 printf(_("%s: %s mounted on %s.\n"), pr, src, tgt);
299
f5ae1d70 300 printf(_("%s: %s propagation flags changed.\n"), pr, tgt);
b4ec4573 301 } else
f5ae1d70 302 printf(_("%s: %s mounted on %s.\n"), pr, src, tgt);
84600ddc
KZ
303}
304
4e45dfb9 305#if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
eba9ef59
KZ
306# include <selinux/selinux.h>
307# include <selinux/context.h>
4e45dfb9
KZ
308
309static void selinux_warning(struct libmnt_context *cxt, const char *tgt)
310{
311
312 if (tgt && mnt_context_is_verbose(cxt) && is_selinux_enabled() > 0) {
ca27216a 313 char *raw = NULL, *def = NULL;
4e45dfb9
KZ
314
315 if (getfilecon(tgt, &raw) > 0
316 && security_get_initial_context("file", &def) == 0) {
317
318 if (!selinux_file_context_cmp(raw, def))
319 printf(_(
320 "mount: %s does not contain SELinux labels.\n"
3c560686 321 " You just mounted a file system that supports labels which does not\n"
4e45dfb9
KZ
322 " contain labels, onto an SELinux box. It is likely that confined\n"
323 " applications will generate AVC messages and not be allowed access to\n"
324 " this file system. For more details see restorecon(8) and mount(8).\n"),
325 tgt);
326 }
327 freecon(raw);
328 freecon(def);
329 }
330}
331#else
b8c0f4fb 332# define selinux_warning(_x, _y)
4e45dfb9
KZ
333#endif
334
1db07151
KZ
335
336#ifdef USE_SYSTEMD
cdc8b265
KZ
337/*
338* Note that this mount(8) message may generate thousands of lines of output
339* when mount(8) is called from any script in systems with large fstab, etc.
340*
341* The goal is to avoid spamming system logs (don't print on stderr) and hide
342* the hint if stderr is redirected/piped (in this case mount(8) is probably
343* executed in a script).
344*
345* The target audience is users on a terminal who directly use mount(8).
346*/
1db07151
KZ
347static void systemd_hint(void)
348{
349 static int fstab_check_done = 0;
350
351 if (fstab_check_done == 0) {
352 struct stat a, b;
353
354 if (isatty(STDERR_FILENO) &&
cdc8b265 355 isatty(STDOUT_FILENO) &&
1db07151
KZ
356 stat(_PATH_SD_UNITSLOAD, &a) == 0 &&
357 stat(_PATH_MNTTAB, &b) == 0 &&
358 cmp_stat_mtime(&a, &b, <))
359 printf(_(
360 "mount: (hint) your fstab has been modified, but systemd still uses\n"
361 " the old version; use 'systemctl daemon-reload' to reload.\n"));
362
363 fstab_check_done = 1;
364 }
365}
366#else
367# define systemd_hint()
368#endif
369
a5d0e6a8
KZ
370static size_t libmount_mesgs(struct libmnt_context *cxt, char type)
371{
372 size_t n = mnt_context_get_nmesgs(cxt, type);
373 char **mesgs = mnt_context_get_mesgs(cxt);
374 char **s;
375
376 if (!n)
377 return 0;
378
379 /* Header */
380 switch (type) {
381 case 'e':
382 fputs(P_("mount error:\n", "mount errors:\n", n), stderr);
383 break;
384 case 'w':
385 fputs(P_("mount warning:\n", "mount warnings:\n", n), stdout);
386 break;
387 case 'i':
388 fputs(P_("mount info:\n", "mount infos:\n", n), stdout);
389 break;
390 }
391
c722cb59 392 /* Messages */
f39ffccf 393 UL_STRV_FOREACH(s, mesgs) {
a5d0e6a8
KZ
394 switch (type) {
395 case 'e':
aa07db0a 396 if (!ul_startswith(*s, "e "))
a5d0e6a8
KZ
397 break;
398 fprintf(stderr, " * %s\n", (*s) + 2);
399 break;
400 case 'w':
aa07db0a 401 if (!ul_startswith(*s, "w "))
a5d0e6a8
KZ
402 break;
403 fprintf(stdout, " * %s\n", (*s) + 2);
404 break;
405 case 'i':
aa07db0a 406 if (!ul_startswith(*s, "i "))
a5d0e6a8
KZ
407 break;
408 fprintf(stdout, " * %s\n", (*s) + 2);
409 break;
410 }
411 }
412
413 return n;
414}
1db07151 415
fcc0413a 416/*
e1706a67 417 * Returns exit status (MNT_EX_*) and/or prints error message.
ce433404
KZ
418 */
419static int mk_exit_code(struct libmnt_context *cxt, int rc)
420{
e1706a67
KZ
421 const char *tgt;
422 char buf[BUFSIZ] = { 0 };
6dede2f2 423
e1706a67
KZ
424 rc = mnt_context_get_excode(cxt, rc, buf, sizeof(buf));
425 tgt = mnt_context_get_target(cxt);
ce433404 426
a5d0e6a8
KZ
427 /* error messages
428 *
429 * Note that mnt_context_get_excode() is used for backward compatibility and
430 * will fill @buf with error messages from mnt_context_get_mesgs(). Therefore,
431 * calling libmount_mesgs(cxt, 'e') is currently unnecessary.
432 */
e1706a67
KZ
433 if (*buf) {
434 const char *spec = tgt;
435 if (!spec)
436 spec = mnt_context_get_source(cxt);
437 if (!spec)
438 spec = "???";
14056588 439 warnx("%s: %s.", spec, buf);
79534c0d
KZ
440
441 if (mnt_context_syscall_called(cxt) &&
442 mnt_context_get_syscall_errno(cxt) != 0)
443 fprintf(stderr, _(" dmesg(1) may have more information after failed mount system call.\n"));
ce433404 444 }
ce433404 445
a5d0e6a8
KZ
446 /* warning messages */
447 libmount_mesgs(cxt, 'w');
448
449 /* info messages */
450 if (mnt_context_is_verbose(cxt))
451 libmount_mesgs(cxt, 'i');
452
453 /* extra mount(8) messages */
0361cb6f
KZ
454 if (rc == MNT_EX_SUCCESS && mnt_context_get_status(cxt) == 1) {
455 selinux_warning(cxt, tgt);
ce433404 456 }
1db07151
KZ
457
458 systemd_hint();
459
e1706a67 460 return rc;
ce433404
KZ
461}
462
64b6bc4f
KZ
463static struct libmnt_table *append_fstab(struct libmnt_context *cxt,
464 struct libmnt_table *fstab,
465 const char *path)
466{
467
468 if (!fstab) {
469 fstab = mnt_new_table();
470 if (!fstab)
e3a7a5f8 471 err(MNT_EX_SYSERR, _("failed to initialize libmount table"));
64b6bc4f
KZ
472
473 mnt_table_set_parser_errcb(fstab, table_parser_errcb);
474 mnt_context_set_fstab(cxt, fstab);
50fccba1
KZ
475
476 mnt_unref_table(fstab); /* reference is handled by @cxt now */
64b6bc4f
KZ
477 }
478
479 if (mnt_table_parse_fstab(fstab, path))
e3a7a5f8 480 errx(MNT_EX_USAGE,_("%s: failed to parse"), path);
64b6bc4f
KZ
481
482 return fstab;
483}
484
5ebbc386
KZ
485/*
486 * Check source and target paths -- non-root user should not be able to
3a039030 487 * resolve paths which are unreadable for them.
5ebbc386 488 */
6b0094d0 489static int sanitize_paths(struct libmnt_context *cxt)
5ebbc386
KZ
490{
491 const char *p;
492 struct libmnt_fs *fs = mnt_context_get_fs(cxt);
493
494 if (!fs)
6b0094d0 495 return 0;
5ebbc386
KZ
496
497 p = mnt_fs_get_target(fs);
498 if (p) {
499 char *np = canonicalize_path_restricted(p);
500 if (!np)
6b0094d0 501 return -EPERM;
5ebbc386
KZ
502 mnt_fs_set_target(fs, np);
503 free(np);
504 }
505
506 p = mnt_fs_get_srcpath(fs);
507 if (p) {
508 char *np = canonicalize_path_restricted(p);
509 if (!np)
6b0094d0 510 return -EPERM;
5ebbc386
KZ
511 mnt_fs_set_source(fs, np);
512 free(np);
513 }
6b0094d0 514 return 0;
5ebbc386
KZ
515}
516
5a72054b 517static void append_option(struct libmnt_context *cxt, const char *opt, const char *arg)
be6904b9 518{
5a72054b
KZ
519 char *o = NULL;
520
ee1a3f83 521 if (opt && !ul_optstr_is_valid(opt))
e3a7a5f8 522 errx(MNT_EX_USAGE, _("unsupported option format: %s"), opt);
5a72054b 523
ee1a3f83 524 if (opt && arg && *arg)
5a72054b
KZ
525 xasprintf(&o, "%s=\"%s\"", opt, arg);
526
527 if (mnt_context_append_options(cxt, o ? : opt))
528 err(MNT_EX_SYSERR, _("failed to append option '%s'"), o ? : opt);
529
530 free(o);
be6904b9
KZ
531}
532
ba986e81
KZ
533static int has_remount_flag(struct libmnt_context *cxt)
534{
535 unsigned long mflags = 0;
536
537 if (mnt_context_get_mflags(cxt, &mflags))
538 return 0;
539
540 return mflags & MS_REMOUNT;
541}
542
6e1eda6f 543static void __attribute__((__noreturn__)) usage(void)
97073441 544{
6e1eda6f 545 FILE *out = stdout;
a58600d0 546
e4c92d06 547 fputs(USAGE_HEADER, out);
bad4c729 548 fprintf(out, _(
97073441
KZ
549 " %1$s [-lhV]\n"
550 " %1$s -a [options]\n"
aedeaa40 551 " %1$s [options] [--source] <source> | [--target] <directory>\n"
97073441
KZ
552 " %1$s [options] <source> <directory>\n"
553 " %1$s <operation> <mountpoint> [<target>]\n"),
554 program_invocation_short_name);
555
451dbcfa
BS
556 fputs(USAGE_SEPARATOR, out);
557 fputs(_("Mount a filesystem.\n"), out);
558
e4c92d06 559 fputs(USAGE_OPTIONS, out);
a58600d0
KZ
560 fputs(_(" -a, --all mount all filesystems mentioned in fstab\n"), out);
561 fputs(_(" -c, --no-canonicalize don't canonicalize paths\n"), out);
562 fputs(_(" -f, --fake dry run; skip the mount(2) syscall\n"), out);
563 fputs(_(" -F, --fork fork off for each device (use with -a)\n"), out);
564 fputs(_(" -T, --fstab <path> alternative file to /etc/fstab\n"), out);
565 fputs(_(" -i, --internal-only don't call the mount.<type> helpers\n"), out);
566 fputs(_(" -l, --show-labels show also filesystem labels\n"), out);
a61bbb37
CW
567 fputs(_(" --map-groups <inner>:<outer>:<count>\n"
568 " add the specified GID map to an ID-mapped mount\n"), out);
569 fputs(_(" --map-users <inner>:<outer>:<count>\n"
570 " add the specified UID map to an ID-mapped mount\n"), out);
571 fputs(_(" --map-users /proc/<pid>/ns/user\n"
572 " specify the user namespace for an ID-mapped mount\n"), out);
a58600d0
KZ
573 fputs(_(" -m, --mkdir[=<mode>] alias to '-o X-mount.mkdir[=<mode>]'\n"), out);
574 fputs(_(" -n, --no-mtab don't write to /etc/mtab\n"), out);
575 fputs(_(" --options-mode <mode>\n"
576 " what to do with options loaded from fstab\n"), out);
577 fputs(_(" --options-source <source>\n"
578 " mount options source\n"), out);
579 fputs(_(" --options-source-force\n"
580 " force use of options from fstab/mtab\n"), out);
581 fputs(_(" --onlyonce check if filesystem is already mounted\n"), out);
582 fputs(_(" -o, --options <list> comma-separated list of mount options\n"), out);
583 fputs(_(" -O, --test-opts <list> limit the set of filesystems (use with -a)\n"), out);
584 fputs(_(" -r, --read-only mount the filesystem read-only (same as -o ro)\n"), out);
585 fputs(_(" -t, --types <list> limit the set of filesystem types\n"), out);
586 fputs(_(" --source <src> explicitly specifies source (path, label, uuid)\n"), out);
587 fputs(_(" --target <target> explicitly specifies mountpoint\n"), out);
588 fputs(_(" --target-prefix <path>\n"
589 " specifies path used for all mountpoints\n"), out);
590 fputs(_(" -v, --verbose say what is being done\n"), out);
591 fputs(_(" -w, --rw, --read-write mount the filesystem read-write (default)\n"), out);
592 fputs(_(" -N, --namespace <ns> perform mount in another namespace\n"), out);
97073441 593
e4c92d06 594 fputs(USAGE_SEPARATOR, out);
bad4c729 595 fprintf(out, USAGE_HELP_OPTIONS(25));
e4c92d06 596
a58600d0
KZ
597 fputs(USAGE_SEPARATOR, out);
598 fputs(_("Source:\n"), out);
599 fputs(_(" -L, --label <label> synonym for LABEL=<label>\n"), out);
600 fputs(_(" -U, --uuid <uuid> synonym for UUID=<uuid>\n"), out);
601 fputs(_(" LABEL=<label> specifies device by filesystem label\n"), out);
602 fputs(_(" UUID=<uuid> specifies device by filesystem UUID\n"), out);
603 fputs(_(" PARTLABEL=<label> specifies device by partition label\n"), out);
604 fputs(_(" PARTUUID=<uuid> specifies device by partition UUID\n"), out);
605 fputs(_(" ID=<id> specifies device by udev hardware ID\n"), out);
606 fputs(_(" <device> specifies device by path\n"), out);
607 fputs(_(" <directory> mountpoint for bind mounts (see --bind/rbind)\n"), out);
608 fputs(_(" <file> regular file for loopdev setup\n"), out);
609
610 fputs(USAGE_SEPARATOR, out);
611 fputs(_("Operations:\n"), out);
612 fputs(_(" -B, --bind mount a subtree somewhere else (same as -o bind)\n"), out);
613 fputs(_(" -M, --move move a subtree to some other place\n"), out);
614 fputs(_(" -R, --rbind mount a subtree and all submounts somewhere else\n"), out);
615 fputs(_(" --make-shared mark a subtree as shared\n"), out);
616 fputs(_(" --make-slave mark a subtree as slave\n"), out);
617 fputs(_(" --make-private mark a subtree as private\n"), out);
618 fputs(_(" --make-unbindable mark a subtree as unbindable\n"), out);
619 fputs(_(" --make-rshared recursively mark a whole subtree as shared\n"), out);
620 fputs(_(" --make-rslave recursively mark a whole subtree as slave\n"), out);
621 fputs(_(" --make-rprivate recursively mark a whole subtree as private\n"), out);
622 fputs(_(" --make-runbindable recursively mark a whole subtree as unbindable\n"), out);
97073441 623
bad4c729 624 fprintf(out, USAGE_MAN_TAIL("mount(8)"));
97073441 625
6e1eda6f 626 exit(MNT_EX_SUCCESS);
97073441
KZ
627}
628
db9185bf
VD
629struct flag_str {
630 int value;
631 char *str;
632};
633
9730aa40 634static int omode2mask(const char *str)
db9185bf 635{
9730aa40
VD
636 size_t i;
637
638 static const struct flag_str flags[] = {
639 { MNT_OMODE_IGNORE, "ignore" },
640 { MNT_OMODE_APPEND, "append" },
641 { MNT_OMODE_PREPEND, "prepend" },
642 { MNT_OMODE_REPLACE, "replace" },
643 };
644
645 for (i = 0; i < ARRAY_SIZE(flags); i++) {
646 if (!strcmp(str, flags[i].str))
647 return flags[i].value;
db9185bf
VD
648 }
649 return -EINVAL;
650}
651
9730aa40 652static long osrc2mask(const char *str, size_t len)
db9185bf 653{
9730aa40
VD
654 size_t i;
655
656 static const struct flag_str flags[] = {
657 { MNT_OMODE_FSTAB, "fstab" },
658 { MNT_OMODE_MTAB, "mtab" },
659 { MNT_OMODE_NOTAB, "disable" },
660 };
661
662 for (i = 0; i < ARRAY_SIZE(flags); i++) {
663 if (!strncmp(str, flags[i].str, len) && !flags[i].str[len])
664 return flags[i].value;
db9185bf 665 }
9730aa40 666 return -EINVAL;
db9185bf
VD
667}
668
d59766a6
VD
669static pid_t parse_pid(const char *str)
670{
671 char *end;
672 pid_t ret;
673
674 errno = 0;
675 ret = strtoul(str, &end, 10);
676
677 if (ret < 0 || errno || end == str || (end && *end))
678 return 0;
679 return ret;
680}
681
97073441
KZ
682int main(int argc, char **argv)
683{
e3a7a5f8 684 int c, rc = MNT_EX_SUCCESS, all = 0, show_labels = 0;
68164f6c 685 struct libmnt_context *cxt;
64b6bc4f 686 struct libmnt_table *fstab = NULL;
a61bbb37 687 char *idmap = NULL;
aedeaa40 688 char *srcbuf = NULL;
97073441 689 char *types = NULL;
6691d537 690 int oper = 0, is_move = 0;
be6904b9 691 int propa = 0;
db9185bf 692 int optmode = 0, optmode_mode = 0, optmode_src = 0;
97073441 693
2492f713
KZ
694 enum {
695 MOUNT_OPT_SHARED = CHAR_MAX + 1,
696 MOUNT_OPT_SLAVE,
697 MOUNT_OPT_PRIVATE,
698 MOUNT_OPT_UNBINDABLE,
699 MOUNT_OPT_RSHARED,
700 MOUNT_OPT_RSLAVE,
701 MOUNT_OPT_RPRIVATE,
aedeaa40 702 MOUNT_OPT_RUNBINDABLE,
a61bbb37
CW
703 MOUNT_OPT_MAP_GROUPS,
704 MOUNT_OPT_MAP_USERS,
aedeaa40 705 MOUNT_OPT_TARGET,
b231e0f7 706 MOUNT_OPT_TARGET_PREFIX,
db9185bf
VD
707 MOUNT_OPT_SOURCE,
708 MOUNT_OPT_OPTMODE,
709 MOUNT_OPT_OPTSRC,
3d1c41c8
KZ
710 MOUNT_OPT_OPTSRC_FORCE,
711 MOUNT_OPT_ONLYONCE
2492f713
KZ
712 };
713
6c7d5ae9 714 static const struct option longopts[] = {
87918040
SK
715 { "all", no_argument, NULL, 'a' },
716 { "fake", no_argument, NULL, 'f' },
717 { "fstab", required_argument, NULL, 'T' },
718 { "fork", no_argument, NULL, 'F' },
719 { "help", no_argument, NULL, 'h' },
720 { "no-mtab", no_argument, NULL, 'n' },
721 { "read-only", no_argument, NULL, 'r' },
722 { "ro", no_argument, NULL, 'r' },
723 { "verbose", no_argument, NULL, 'v' },
724 { "version", no_argument, NULL, 'V' },
725 { "read-write", no_argument, NULL, 'w' },
726 { "rw", no_argument, NULL, 'w' },
727 { "options", required_argument, NULL, 'o' },
728 { "test-opts", required_argument, NULL, 'O' },
729 { "types", required_argument, NULL, 't' },
730 { "uuid", required_argument, NULL, 'U' },
731 { "label", required_argument, NULL, 'L' },
732 { "bind", no_argument, NULL, 'B' },
733 { "move", no_argument, NULL, 'M' },
734 { "rbind", no_argument, NULL, 'R' },
735 { "make-shared", no_argument, NULL, MOUNT_OPT_SHARED },
736 { "make-slave", no_argument, NULL, MOUNT_OPT_SLAVE },
737 { "make-private", no_argument, NULL, MOUNT_OPT_PRIVATE },
738 { "make-unbindable", no_argument, NULL, MOUNT_OPT_UNBINDABLE },
739 { "make-rshared", no_argument, NULL, MOUNT_OPT_RSHARED },
740 { "make-rslave", no_argument, NULL, MOUNT_OPT_RSLAVE },
741 { "make-rprivate", no_argument, NULL, MOUNT_OPT_RPRIVATE },
742 { "make-runbindable", no_argument, NULL, MOUNT_OPT_RUNBINDABLE },
a61bbb37
CW
743 { "map-groups", required_argument, NULL, MOUNT_OPT_MAP_GROUPS },
744 { "map-users", required_argument, NULL, MOUNT_OPT_MAP_USERS },
5a72054b 745 { "mkdir", optional_argument, NULL, 'm' },
87918040
SK
746 { "no-canonicalize", no_argument, NULL, 'c' },
747 { "internal-only", no_argument, NULL, 'i' },
748 { "show-labels", no_argument, NULL, 'l' },
749 { "target", required_argument, NULL, MOUNT_OPT_TARGET },
b231e0f7 750 { "target-prefix", required_argument, NULL, MOUNT_OPT_TARGET_PREFIX },
87918040 751 { "source", required_argument, NULL, MOUNT_OPT_SOURCE },
3d1c41c8 752 { "onlyonce", no_argument, NULL, MOUNT_OPT_ONLYONCE },
db9185bf
VD
753 { "options-mode", required_argument, NULL, MOUNT_OPT_OPTMODE },
754 { "options-source", required_argument, NULL, MOUNT_OPT_OPTSRC },
755 { "options-source-force", no_argument, NULL, MOUNT_OPT_OPTSRC_FORCE},
21edc0f7 756 { "namespace", required_argument, NULL, 'N' },
87918040 757 { NULL, 0, NULL, 0 }
97073441
KZ
758 };
759
a7349ee3 760 static const ul_excl_t excl[] = { /* rows and cols in ASCII order */
be6904b9 761 { 'B','M','R' }, /* bind,move,rbind */
51a37c19
KZ
762 { 'L','U', MOUNT_OPT_SOURCE }, /* label,uuid,source */
763 { 0 }
764 };
765 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
766
f1f48270 767 __sanitize_env(&envs_removed);
97073441
KZ
768 setlocale(LC_ALL, "");
769 bindtextdomain(PACKAGE, LOCALEDIR);
770 textdomain(PACKAGE);
2c308875 771 close_stdout_atexit();
97073441 772
0b2b32e8
RM
773 strutils_set_exitcode(MNT_EX_USAGE);
774
97073441
KZ
775 mnt_init_debug(0);
776 cxt = mnt_new_context();
777 if (!cxt)
e3a7a5f8 778 err(MNT_EX_SYSERR, _("libmount context allocation failed"));
97073441 779
9f7472b0
KZ
780 mnt_context_set_tables_errcb(cxt, table_parser_errcb);
781
5a72054b 782 while ((c = getopt_long(argc, argv, "aBcfFhilL:m::Mno:O:rRsU:vVwt:T:N:",
97073441
KZ
783 longopts, NULL)) != -1) {
784
785 /* only few options are allowed for non-root users */
aedeaa40 786 if (mnt_context_is_restricted(cxt) &&
961d69f7 787 !strchr("hlLUVvrist", c) &&
aedeaa40
KZ
788 c != MOUNT_OPT_TARGET &&
789 c != MOUNT_OPT_SOURCE)
6497f2d9 790 suid_drop(cxt);
97073441 791
51a37c19
KZ
792 err_exclusive_options(c, longopts, excl, excl_st);
793
97073441
KZ
794 switch(c) {
795 case 'a':
796 all = 1;
97073441
KZ
797 break;
798 case 'c':
799 mnt_context_disable_canonicalize(cxt, TRUE);
800 break;
801 case 'f':
802 mnt_context_enable_fake(cxt, TRUE);
803 break;
804 case 'F':
d2c97887 805 mnt_context_enable_fork(cxt, TRUE);
97073441 806 break;
97073441
KZ
807 case 'i':
808 mnt_context_disable_helpers(cxt, TRUE);
809 break;
810 case 'n':
811 mnt_context_disable_mtab(cxt, TRUE);
812 break;
813 case 'r':
5a72054b 814 append_option(cxt, "ro", NULL);
6dede2f2 815 mnt_context_enable_rwonly_mount(cxt, FALSE);
97073441
KZ
816 break;
817 case 'v':
818 mnt_context_enable_verbose(cxt, TRUE);
819 break;
97073441 820 case 'w':
5a72054b 821 append_option(cxt, "rw", NULL);
6dede2f2 822 mnt_context_enable_rwonly_mount(cxt, TRUE);
97073441
KZ
823 break;
824 case 'o':
a8906113
KZ
825 /* "move" is not supported as option string in libmount
826 * to avoid use in fstab */
827 if (mnt_optstr_get_option(optarg, "move", NULL, 0) == 0) {
828 char *o = xstrdup(optarg);
829
830 mnt_optstr_remove_option(&o, "move");
831 if (o && *o)
5a72054b 832 append_option(cxt, o, NULL);
a8906113
KZ
833 oper = is_move = 1;
834 free(o);
835 } else
5a72054b 836 append_option(cxt, optarg, NULL);
97073441
KZ
837 break;
838 case 'O':
839 if (mnt_context_set_options_pattern(cxt, optarg))
e3a7a5f8 840 err(MNT_EX_SYSERR, _("failed to set options pattern"));
97073441
KZ
841 break;
842 case 'L':
aedeaa40
KZ
843 xasprintf(&srcbuf, "LABEL=\"%s\"", optarg);
844 mnt_context_disable_swapmatch(cxt, 1);
845 mnt_context_set_source(cxt, srcbuf);
846 free(srcbuf);
847 break;
97073441 848 case 'U':
aedeaa40
KZ
849 xasprintf(&srcbuf, "UUID=\"%s\"", optarg);
850 mnt_context_disable_swapmatch(cxt, 1);
851 mnt_context_set_source(cxt, srcbuf);
852 free(srcbuf);
97073441
KZ
853 break;
854 case 'l':
855 show_labels = 1;
856 break;
857 case 't':
858 types = optarg;
859 break;
64b6bc4f
KZ
860 case 'T':
861 fstab = append_fstab(cxt, fstab, optarg);
862 break;
97073441
KZ
863 case 's':
864 mnt_context_enable_sloppy(cxt, TRUE);
865 break;
866 case 'B':
4ebea84b 867 oper = 1;
5a72054b 868 append_option(cxt, "bind", NULL);
97073441
KZ
869 break;
870 case 'M':
4ebea84b 871 oper = 1;
6691d537 872 is_move = 1;
97073441 873 break;
5a72054b
KZ
874 case 'm':
875 if (optarg && *optarg == '=')
876 optarg++;
877 append_option(cxt, "X-mount.mkdir", optarg);
878 break;
97073441 879 case 'R':
4ebea84b 880 oper = 1;
5a72054b 881 append_option(cxt, "rbind", NULL);
97073441 882 break;
21edc0f7 883 case 'N':
d59766a6
VD
884 {
885 char path[PATH_MAX];
886 pid_t pid = parse_pid(optarg);
887
888 if (pid)
889 snprintf(path, sizeof(path), "/proc/%i/ns/mnt", pid);
890
891 if (mnt_context_set_target_ns(cxt, pid ? path : optarg))
892 err(MNT_EX_SYSERR, _("failed to set target namespace to %s"), pid ? path : optarg);
21edc0f7 893 break;
d59766a6 894 }
2492f713 895 case MOUNT_OPT_SHARED:
5a72054b 896 append_option(cxt, "shared", NULL);
be6904b9 897 propa = 1;
97073441 898 break;
2492f713 899 case MOUNT_OPT_SLAVE:
5a72054b 900 append_option(cxt, "slave", NULL);
be6904b9 901 propa = 1;
97073441 902 break;
2492f713 903 case MOUNT_OPT_PRIVATE:
5a72054b 904 append_option(cxt, "private", NULL);
be6904b9 905 propa = 1;
97073441 906 break;
2492f713 907 case MOUNT_OPT_UNBINDABLE:
5a72054b 908 append_option(cxt, "unbindable", NULL);
be6904b9 909 propa = 1;
97073441 910 break;
2492f713 911 case MOUNT_OPT_RSHARED:
5a72054b 912 append_option(cxt, "rshared", NULL);
be6904b9 913 propa = 1;
97073441 914 break;
2492f713 915 case MOUNT_OPT_RSLAVE:
5a72054b 916 append_option(cxt, "rslave", NULL);
be6904b9 917 propa = 1;
97073441 918 break;
2492f713 919 case MOUNT_OPT_RPRIVATE:
5a72054b 920 append_option(cxt, "rprivate", NULL);
be6904b9 921 propa = 1;
97073441 922 break;
2492f713 923 case MOUNT_OPT_RUNBINDABLE:
5a72054b 924 append_option(cxt, "runbindable", NULL);
be6904b9 925 propa = 1;
97073441 926 break;
a61bbb37
CW
927 case MOUNT_OPT_MAP_GROUPS:
928 case MOUNT_OPT_MAP_USERS:
a5eba504 929 if (*optarg == '=')
a61bbb37
CW
930 optarg++;
931 if (idmap && (*idmap == '/' || *optarg == '/')) {
932 warnx(_("bad usage"));
933 errtryhelp(MNT_EX_USAGE);
934 } else if (*optarg == '/') {
935 idmap = xstrdup(optarg);
936 } else {
937 char *tmp;
938 xasprintf(&tmp, "%s%s%s%s", idmap ? idmap : "", idmap ? " " : "",
939 c == MOUNT_OPT_MAP_GROUPS ? "g:" : "u:", optarg);
940 free(idmap);
941 idmap = tmp;
942 }
943 break;
aedeaa40
KZ
944 case MOUNT_OPT_TARGET:
945 mnt_context_disable_swapmatch(cxt, 1);
946 mnt_context_set_target(cxt, optarg);
947 break;
b231e0f7
KZ
948 case MOUNT_OPT_TARGET_PREFIX:
949 mnt_context_set_target_prefix(cxt, optarg);
950 break;
aedeaa40 951 case MOUNT_OPT_SOURCE:
aedeaa40
KZ
952 mnt_context_disable_swapmatch(cxt, 1);
953 mnt_context_set_source(cxt, optarg);
954 break;
db9185bf 955 case MOUNT_OPT_OPTMODE:
9730aa40 956 optmode_mode = omode2mask(optarg);
db9185bf
VD
957 if (optmode_mode == -EINVAL) {
958 warnx(_("bad usage"));
959 errtryhelp(MNT_EX_USAGE);
960 }
961 break;
962 case MOUNT_OPT_OPTSRC:
9730aa40
VD
963 {
964 unsigned long tmp = 0;
965 if (string_to_bitmask(optarg, &tmp, osrc2mask)) {
db9185bf
VD
966 warnx(_("bad usage"));
967 errtryhelp(MNT_EX_USAGE);
968 }
9730aa40 969 optmode_src = tmp;
db9185bf 970 break;
9730aa40 971 }
db9185bf
VD
972 case MOUNT_OPT_OPTSRC_FORCE:
973 optmode |= MNT_OMODE_FORCE;
974 break;
3d1c41c8
KZ
975 case MOUNT_OPT_ONLYONCE:
976 mnt_context_enable_onlyonce(cxt, 1);
977 break;
2c308875
KZ
978 case 'h':
979 mnt_free_context(cxt);
980 usage();
981 case 'V':
982 mnt_free_context(cxt);
983 mount_print_version();
97073441 984 default:
e3a7a5f8 985 errtryhelp(MNT_EX_USAGE);
97073441
KZ
986 }
987 }
988
989 argc -= optind;
990 argv += optind;
991
a61bbb37
CW
992 if (idmap)
993 append_option(cxt, "X-mount.idmap", idmap);
994
db9185bf
VD
995 optmode |= optmode_mode | optmode_src;
996 if (optmode) {
997 if (!optmode_mode)
998 optmode |= MNT_OMODE_PREPEND;
999 if (!optmode_src)
1000 optmode |= MNT_OMODE_FSTAB | MNT_OMODE_MTAB;
1001 mnt_context_set_optsmode(cxt, optmode);
1002 }
1003
59414c6b
KZ
1004 if (fstab && !mnt_context_is_nocanonicalize(cxt)) {
1005 /*
1006 * We have external (context independent) fstab instance, let's
1007 * make a connection between the fstab and the canonicalization
1008 * cache.
1009 */
6195f9e6 1010 mnt_table_set_cache(fstab, mnt_context_get_cache(cxt));
59414c6b
KZ
1011 }
1012
aedeaa40
KZ
1013 if (!mnt_context_get_source(cxt) &&
1014 !mnt_context_get_target(cxt) &&
1015 !argc &&
1016 !all) {
6e1eda6f
RM
1017 if (oper || mnt_context_get_options(cxt)) {
1018 warnx(_("bad usage"));
1019 errtryhelp(MNT_EX_USAGE);
1020 }
11754572 1021 print_all(cxt, types, show_labels);
97073441
KZ
1022 goto done;
1023 }
1024
1707b9b1
RT
1025 /* Non-root users are allowed to use -t to print_all(),
1026 but not to mount */
1027 if (mnt_context_is_restricted(cxt) && types)
6497f2d9 1028 suid_drop(cxt);
1707b9b1 1029
6e1eda6f
RM
1030 if (oper && (types || all || mnt_context_get_source(cxt))) {
1031 warnx(_("bad usage"));
1032 errtryhelp(MNT_EX_USAGE);
1033 }
97073441 1034
9f7472b0
KZ
1035 if (types && (all || strchr(types, ',') ||
1036 strncmp(types, "no", 2) == 0))
97073441
KZ
1037 mnt_context_set_fstype_pattern(cxt, types);
1038 else if (types)
1039 mnt_context_set_fstype(cxt, types);
1040
a9ae3955
KZ
1041 if (all) {
1042 /*
1043 * A) Mount all
1044 */
189a1bf3
KZ
1045 if (has_remount_flag(cxt))
1046 rc = remount_all(cxt);
1047 else
1048 rc = mount_all(cxt);
11754572 1049 goto done;
a9ae3955 1050
aedeaa40
KZ
1051 } else if (argc == 0 && (mnt_context_get_source(cxt) ||
1052 mnt_context_get_target(cxt))) {
a9ae3955 1053 /*
aedeaa40 1054 * B) mount -L|-U|--source|--target
6751f062
KZ
1055 *
1056 * non-root may specify source *or* target, but not both
a9ae3955 1057 */
aedeaa40
KZ
1058 if (mnt_context_is_restricted(cxt) &&
1059 mnt_context_get_source(cxt) &&
1060 mnt_context_get_target(cxt))
6497f2d9 1061 suid_drop(cxt);
97073441 1062
6751f062
KZ
1063 } else if (argc == 1 && (!mnt_context_get_source(cxt) ||
1064 !mnt_context_get_target(cxt))) {
a9ae3955 1065 /*
aedeaa40 1066 * C) mount [-L|-U|--source] <target>
6751f062 1067 * mount [--target <dir>] <source>
a9ae3955 1068 * mount <source|target>
aedeaa40
KZ
1069 *
1070 * non-root may specify source *or* target, but not both
6751f062
KZ
1071 *
1072 * It does not matter for libmount if we set source or target
1073 * here (the library is able to swap it), but it matters for
1074 * sanitize_paths().
a9ae3955 1075 */
6751f062
KZ
1076 int istag = mnt_tag_is_valid(argv[0]);
1077
1078 if (istag && mnt_context_get_source(cxt))
1079 /* -L, -U or --source together with LABEL= or UUID= */
e3a7a5f8 1080 errx(MNT_EX_USAGE, _("source specified more than once"));
6751f062
KZ
1081 else if (istag || mnt_context_get_target(cxt))
1082 mnt_context_set_source(cxt, argv[0]);
1083 else
1084 mnt_context_set_target(cxt, argv[0]);
1085
aedeaa40 1086 if (mnt_context_is_restricted(cxt) &&
6751f062
KZ
1087 mnt_context_get_source(cxt) &&
1088 mnt_context_get_target(cxt))
6497f2d9 1089 suid_drop(cxt);
aedeaa40 1090
aedeaa40
KZ
1091 } else if (argc == 2 && !mnt_context_get_source(cxt)
1092 && !mnt_context_get_target(cxt)) {
a9ae3955
KZ
1093 /*
1094 * D) mount <source> <target>
1095 */
97073441 1096 if (mnt_context_is_restricted(cxt))
6497f2d9 1097 suid_drop(cxt);
6751f062 1098
97073441
KZ
1099 mnt_context_set_source(cxt, argv[0]);
1100 mnt_context_set_target(cxt, argv[1]);
aedeaa40 1101
6e1eda6f
RM
1102 } else {
1103 warnx(_("bad usage"));
1104 errtryhelp(MNT_EX_USAGE);
1105 }
97073441 1106
6b0094d0
KZ
1107 if (mnt_context_is_restricted(cxt) && sanitize_paths(cxt) != 0)
1108 suid_drop(cxt);
5ebbc386 1109
6691d537
KZ
1110 if (is_move)
1111 /* "move" as option string is not supported by libmount */
1112 mnt_context_set_mflags(cxt, MS_MOVE);
1113
ba986e81
KZ
1114 if ((oper && !has_remount_flag(cxt)) || propa)
1115 /* For --make-* or --bind is fstab/mtab unnecessary */
374fd21a 1116 mnt_context_set_optsmode(cxt, MNT_OMODE_NOTAB);
374fd21a 1117
cfb9db30 1118 rc = mnt_context_mount(cxt);
6497f2d9
KZ
1119
1120 if (rc == -EPERM
1121 && mnt_context_is_restricted(cxt)
1122 && !mnt_context_syscall_called(cxt)) {
1123 /* Try it again without permissions */
1124 suid_drop(cxt);
1125 rc = mnt_context_mount(cxt);
1126 }
ce433404
KZ
1127 rc = mk_exit_code(cxt, rc);
1128
e3a7a5f8 1129 if (rc == MNT_EX_SUCCESS && mnt_context_is_verbose(cxt))
84600ddc 1130 success_message(cxt);
97073441 1131done:
97073441 1132 mnt_free_context(cxt);
f1f48270 1133 env_list_free(envs_removed);
97073441
KZ
1134 return rc;
1135}