]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/mount.c
libmount: add special MNT_ERR_ codes
[thirdparty/util-linux.git] / sys-utils / mount.c
CommitLineData
97073441
KZ
1/*
2 * mount(8) -- mount a filesystem
3 *
4 * Copyright (C) 2011 Red Hat, Inc. All rights reserved.
5 * Written by Karel Zak <kzak@redhat.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it would be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
7cebf0bb
SK
17 * You should have received a copy of the GNU General Public License along
18 * with this program; if not, write to the Free Software Foundation, Inc.,
19 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
97073441
KZ
20 */
21
22#include <stdio.h>
23#include <stdlib.h>
24#include <errno.h>
25#include <string.h>
26#include <getopt.h>
97073441
KZ
27#include <unistd.h>
28#include <sys/types.h>
dbae36fe 29#include <sys/mman.h>
ce433404 30#include <sys/stat.h>
2e86597f 31#include <stdarg.h>
2a1f429a
KZ
32#include <libmount.h>
33
97073441
KZ
34#include "nls.h"
35#include "c.h"
6189ace3 36#include "env.h"
732a6311 37#include "optutils.h"
dbae36fe
KZ
38#include "strutils.h"
39#include "xgetpass.h"
497d2ce7 40#include "exitcodes.h"
a5ebeca5 41#include "xalloc.h"
efb8854f 42#include "closestream.h"
97073441
KZ
43
44/*** TODO: DOCS:
45 *
97073441 46 * --guess-fstype is unsupported
374fd21a
KZ
47 *
48 * --options-mode={ignore,append,prepend,replace} MNT_OMODE_{IGNORE, ...}
49 * --options-source={fstab,mtab,disable} MNT_OMODE_{FSTAB,MTAB,NOTAB}
50 * --options-source-force MNT_OMODE_FORCE
97073441
KZ
51 */
52
dbae36fe 53static int passfd = -1;
ce433404 54static int readwrite;
dbae36fe 55
d946359a
KZ
56static int mk_exit_code(struct libmnt_context *cxt, int rc);
57
97073441
KZ
58static void __attribute__((__noreturn__)) exit_non_root(const char *option)
59{
60 const uid_t ruid = getuid();
61 const uid_t euid = geteuid();
62
63 if (ruid == 0 && euid != 0) {
64 /* user is root, but setuid to non-root */
65 if (option)
497d2ce7 66 errx(MOUNT_EX_USAGE, _("only root can use \"--%s\" option "
97073441
KZ
67 "(effective UID is %u)"),
68 option, euid);
497d2ce7 69 errx(MOUNT_EX_USAGE, _("only root can do that "
97073441
KZ
70 "(effective UID is %u)"), euid);
71 }
72 if (option)
497d2ce7
KZ
73 errx(MOUNT_EX_USAGE, _("only root can use \"--%s\" option"), option);
74 errx(MOUNT_EX_USAGE, _("only root can do that"));
97073441
KZ
75}
76
77static void __attribute__((__noreturn__)) print_version(void)
78{
79 const char *ver = NULL;
ac8ecab4 80 const char **features = NULL, **p;
97073441
KZ
81
82 mnt_get_library_version(&ver);
ac8ecab4
KZ
83 mnt_get_library_features(&features);
84
85 printf(_("%s from %s (libmount %s"),
86 program_invocation_short_name,
87 PACKAGE_STRING,
88 ver);
89 p = features;
90 while (p && *p) {
91 fputs(p == features ? ": " : ", ", stdout);
92 fputs(*p++, stdout);
93 }
94 fputs(")\n", stdout);
497d2ce7 95 exit(MOUNT_EX_SUCCESS);
97073441
KZ
96}
97
7fc6d2b8 98static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
9f7472b0
KZ
99 const char *filename, int line)
100{
101 if (filename)
102 warnx(_("%s: parse error: ignore entry at line %d."),
103 filename, line);
104 return 0;
105}
106
dbae36fe
KZ
107static char *encrypt_pass_get(struct libmnt_context *cxt)
108{
109 if (!cxt)
110 return 0;
111
112#ifdef MCL_FUTURE
113 if (mlockall(MCL_CURRENT | MCL_FUTURE)) {
114 warn(_("couldn't lock into memory"));
115 return NULL;
116 }
117#endif
118 return xgetpass(passfd, _("Password: "));
119}
120
56dec8b7
KZ
121static void encrypt_pass_release(struct libmnt_context *cxt
122 __attribute__((__unused__)), char *pwd)
dbae36fe
KZ
123{
124 char *p = pwd;
125
126 while (p && *p)
127 *p++ = '\0';
128
129 free(pwd);
130 munlockall();
131}
132
11754572 133static void print_all(struct libmnt_context *cxt, char *pattern, int show_label)
97073441 134{
68164f6c 135 struct libmnt_table *tb;
a0c014dc 136 struct libmnt_iter *itr = NULL;
68164f6c
KZ
137 struct libmnt_fs *fs;
138 struct libmnt_cache *cache = NULL;
97073441 139
11754572 140 if (mnt_context_get_mtab(cxt, &tb))
497d2ce7 141 err(MOUNT_EX_SYSERR, _("failed to read mtab"));
97073441
KZ
142
143 itr = mnt_new_iter(MNT_ITER_FORWARD);
11754572 144 if (!itr)
497d2ce7 145 err(MOUNT_EX_SYSERR, _("failed to initialize libmount iterator"));
97073441
KZ
146 if (show_label)
147 cache = mnt_new_cache();
148
9f7472b0 149 while (mnt_table_next_fs(tb, itr, &fs) == 0) {
97073441
KZ
150 const char *type = mnt_fs_get_fstype(fs);
151 const char *src = mnt_fs_get_source(fs);
7cf389f7 152 const char *optstr = mnt_fs_get_options(fs);
aa397ce5 153 char *xsrc = NULL;
97073441
KZ
154
155 if (type && pattern && !mnt_match_fstype(type, pattern))
156 continue;
157
aa397ce5
DR
158 if (!mnt_fs_is_pseudofs(fs))
159 xsrc = mnt_pretty_path(src, cache);
160 printf ("%s on %s", xsrc ? xsrc : src, mnt_fs_get_target(fs));
97073441
KZ
161 if (type)
162 printf (" type %s", type);
163 if (optstr)
164 printf (" (%s)", optstr);
165 if (show_label && src) {
166 char *lb = mnt_cache_find_tag_value(cache, src, "LABEL");
167 if (lb)
168 printf (" [%s]", lb);
169 }
170 fputc('\n', stdout);
2576b4e7 171 free(xsrc);
97073441 172 }
11754572 173
97073441 174 mnt_free_cache(cache);
b192b7b9 175 mnt_free_iter(itr);
97073441
KZ
176}
177
9f7472b0
KZ
178/*
179 * mount -a [-F]
9f7472b0 180 */
d2c97887 181static int mount_all(struct libmnt_context *cxt)
a9ae3955 182{
9f7472b0
KZ
183 struct libmnt_iter *itr;
184 struct libmnt_fs *fs;
497d2ce7 185 int mntrc, ignored, rc = MOUNT_EX_SUCCESS;
9f7472b0 186
16b73aae
KZ
187 int nsucc = 0, nerrs = 0;
188
9f7472b0
KZ
189 itr = mnt_new_iter(MNT_ITER_FORWARD);
190 if (!itr) {
191 warn(_("failed to initialize libmount iterator"));
497d2ce7 192 return MOUNT_EX_SYSERR;
9f7472b0
KZ
193 }
194
195 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
196
197 const char *tgt = mnt_fs_get_target(fs);
198
199 if (ignored) {
200 if (mnt_context_is_verbose(cxt))
b3f7a0ec
KZ
201 printf(ignored == 1 ? _("%-25s: ignored\n") :
202 _("%-25s: already mounted\n"),
9f7472b0 203 tgt);
d2c97887 204 } else if (mnt_context_is_fork(cxt)) {
d946359a
KZ
205 if (mnt_context_is_verbose(cxt))
206 printf("%-25s: mount successfully forked\n", tgt);
9f7472b0 207 } else {
16b73aae 208 mk_exit_code(cxt, mntrc); /* to print warnings */
9f7472b0 209
d946359a 210 if (mnt_context_get_status(cxt)) {
16b73aae 211 nsucc++;
d946359a
KZ
212
213 if (mnt_context_is_verbose(cxt))
214 printf("%-25s: successfully mounted\n", tgt);
16b73aae
KZ
215 } else
216 nerrs++;
9f7472b0
KZ
217 }
218 }
219
d2c97887
KZ
220 if (mnt_context_is_parent(cxt)) {
221 /* wait for mount --fork children */
16b73aae
KZ
222 int nchildren = 0;
223
224 nerrs = 0, nsucc = 0;
d2c97887
KZ
225
226 rc = mnt_context_wait_for_children(cxt, &nchildren, &nerrs);
227 if (!rc && nchildren)
16b73aae 228 nsucc = nchildren - nerrs;
d2c97887
KZ
229 }
230
16b73aae
KZ
231 if (nerrs == 0)
232 rc = MOUNT_EX_SUCCESS; /* all success */
233 else if (nsucc == 0)
234 rc = MOUNT_EX_FAIL; /* all failed */
235 else
236 rc = MOUNT_EX_SOMEOK; /* some success, some failed */
237
25609ee1 238 mnt_free_iter(itr);
9f7472b0 239 return rc;
a9ae3955
KZ
240}
241
ce433404
KZ
242/*
243 * Handles generic errors like ENOMEM, ...
244 *
245 * rc = 0 success
246 * <0 error (usually -errno)
247 *
497d2ce7 248 * Returns exit status (MOUNT_EX_*) and prints error message.
ce433404 249 */
2e86597f 250static int handle_generic_errors(int rc, const char *msg, ...)
ce433404 251{
2e86597f
KZ
252 va_list va;
253
254 va_start(va, msg);
ce433404
KZ
255 errno = -rc;
256
257 switch(errno) {
258 case EINVAL:
259 case EPERM:
2e86597f 260 vwarn(msg, va);
497d2ce7 261 rc = MOUNT_EX_USAGE;
2e86597f 262 break;
ce433404 263 case ENOMEM:
2e86597f 264 vwarn(msg, va);
497d2ce7 265 rc = MOUNT_EX_SYSERR;
2e86597f 266 break;
ce433404 267 default:
2e86597f 268 vwarn(msg, va);
497d2ce7 269 rc = MOUNT_EX_FAIL;
ce433404
KZ
270 break;
271 }
2e86597f
KZ
272 va_end(va);
273 return rc;
ce433404
KZ
274}
275
4e45dfb9
KZ
276#if defined(HAVE_LIBSELINUX) && defined(HAVE_SECURITY_GET_INITIAL_CONTEXT)
277#include <selinux/selinux.h>
278#include <selinux/context.h>
279
280static void selinux_warning(struct libmnt_context *cxt, const char *tgt)
281{
282
283 if (tgt && mnt_context_is_verbose(cxt) && is_selinux_enabled() > 0) {
284 security_context_t raw = NULL, def = NULL;
285
286 if (getfilecon(tgt, &raw) > 0
287 && security_get_initial_context("file", &def) == 0) {
288
289 if (!selinux_file_context_cmp(raw, def))
290 printf(_(
291 "mount: %s does not contain SELinux labels.\n"
292 " You just mounted an file system that supports labels which does not\n"
293 " contain labels, onto an SELinux box. It is likely that confined\n"
294 " applications will generate AVC messages and not be allowed access to\n"
295 " this file system. For more details see restorecon(8) and mount(8).\n"),
296 tgt);
297 }
298 freecon(raw);
299 freecon(def);
300 }
301}
302#else
b8c0f4fb 303# define selinux_warning(_x, _y)
4e45dfb9
KZ
304#endif
305
306
ce433404
KZ
307/*
308 * rc = 0 success
309 * <0 error (usually -errno or -1)
310 *
497d2ce7 311 * Returns exit status (MOUNT_EX_*) and/or prints error message.
ce433404
KZ
312 */
313static int mk_exit_code(struct libmnt_context *cxt, int rc)
314{
315 int syserr;
316 struct stat st;
317 unsigned long uflags = 0, mflags = 0;
318
319 int restricted = mnt_context_is_restricted(cxt);
320 const char *tgt = mnt_context_get_target(cxt);
321 const char *src = mnt_context_get_source(cxt);
322
323try_readonly:
ce433404
KZ
324 if (mnt_context_helper_executed(cxt))
325 /*
326 * /sbin/mount.<type> called, return status
327 */
328 return mnt_context_get_helper_status(cxt);
329
4e45dfb9 330 if (rc == 0 && mnt_context_get_status(cxt) == 1) {
ce433404
KZ
331 /*
332 * Libmount success && syscall success.
333 */
4e45dfb9
KZ
334 selinux_warning(cxt, tgt);
335
497d2ce7 336 return MOUNT_EX_SUCCESS; /* mount(2) success */
4e45dfb9 337 }
ce433404
KZ
338
339 if (!mnt_context_syscall_called(cxt)) {
340 /*
8b470b20 341 * libmount errors (extra library checks)
ce433404 342 */
8b470b20
KZ
343 switch (rc) {
344 case -EPERM:
ce433404 345 warnx(_("only root can mount %s on %s"), src, tgt);
497d2ce7 346 return MOUNT_EX_USAGE;
8b470b20
KZ
347 case -EBUSY:
348 warnx(_("%s is already mounted"), src);
497d2ce7 349 return MOUNT_EX_USAGE;
ce433404
KZ
350 }
351
58f108ef
KZ
352 if (!tgt || (!src && !(mflags & MS_PROPAGATION))) {
353 if (!mnt_context_fstab_applied(cxt))
ce433404
KZ
354 warnx(_("can't find %s in %s"), src ? src : tgt,
355 mnt_get_fstab_path());
58f108ef
KZ
356 else if (mflags & MS_REMOUNT)
357 warnx(_("%s not mounted"), src ? src : tgt);
358
497d2ce7 359 return MOUNT_EX_USAGE;
ce433404
KZ
360 }
361
362 if (!mnt_context_get_fstype(cxt)) {
363 if (restricted)
364 warnx(_("I could not determine the filesystem type, "
365 "and none was specified"));
366 else
367 warnx(_("you must specify the filesystem type"));
497d2ce7 368 return MOUNT_EX_USAGE;
ce433404 369 }
2e86597f
KZ
370 return handle_generic_errors(rc, _("%s: mount failed"),
371 tgt ? tgt : src);
ce433404
KZ
372
373 } else if (mnt_context_get_syscall_errno(cxt) == 0) {
374 /*
375 * mount(2) syscall success, but something else failed
376 * (probably error in mtab processing).
377 */
378 if (rc < 0)
379 return handle_generic_errors(rc,
2e86597f
KZ
380 _("%s: filesystem mounted, but mount(8) failed"),
381 tgt ? tgt : src);
ce433404 382
497d2ce7 383 return MOUNT_EX_SOFTWARE; /* internal error */
ce433404
KZ
384
385 }
386
387 /*
388 * mount(2) errors
389 */
390 syserr = mnt_context_get_syscall_errno(cxt);
391
392 mnt_context_get_mflags(cxt, &mflags); /* mount(2) flags */
393 mnt_context_get_user_mflags(cxt, &uflags); /* userspace flags */
394
395 switch(syserr) {
396 case EPERM:
397 if (geteuid() == 0) {
398 if (stat(tgt, &st) || !S_ISDIR(st.st_mode))
399 warnx(_("mount point %s is not a directory"), tgt);
400 else
401 warnx(_("permission denied"));
402 } else
403 warnx(_("must be superuser to use mount"));
404 break;
405
406 case EBUSY:
407 {
408 struct libmnt_table *tb;
ce433404
KZ
409
410 if (mflags & MS_REMOUNT) {
411 warnx(_("%s is busy"), tgt);
412 break;
413 }
414
415 warnx(_("%s is already mounted or %s busy"), src, tgt);
416
417 if (src && mnt_context_get_mtab(cxt, &tb) == 0) {
418 struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
419 struct libmnt_fs *fs;
420
421 while(mnt_table_next_fs(tb, itr, &fs) == 0) {
422 const char *s = mnt_fs_get_srcpath(fs),
423 *t = mnt_fs_get_target(fs);
424
6699e742 425 if (t && s && mnt_fs_streq_srcpath(fs, src))
ce433404
KZ
426 fprintf(stderr, _(
427 " %s is already mounted on %s\n"), s, t);
428 }
429 mnt_free_iter(itr);
430 }
431 break;
432 }
433 case ENOENT:
434 if (lstat(tgt, &st))
435 warnx(_("mount point %s does not exist"), tgt);
436 else if (stat(tgt, &st))
437 warnx(_("mount point %s is a symbolic link to nowhere"), tgt);
438 else if (stat(src, &st)) {
439 if (uflags & MNT_MS_NOFAIL)
497d2ce7 440 return MOUNT_EX_SUCCESS;
ce433404
KZ
441
442 warnx(_("special device %s does not exist"), src);
443 } else {
444 errno = syserr;
445 warn(_("mount(2) failed")); /* print errno */
446 }
447 break;
448
449 case ENOTDIR:
450 if (stat(tgt, &st) || ! S_ISDIR(st.st_mode))
451 warnx(_("mount point %s is not a directory"), tgt);
452 else if (stat(src, &st) && errno == ENOTDIR) {
453 if (uflags & MNT_MS_NOFAIL)
497d2ce7 454 return MOUNT_EX_SUCCESS;
ce433404
KZ
455
456 warnx(_("special device %s does not exist "
457 "(a path prefix is not a directory)"), src);
458 } else {
459 errno = syserr;
460 warn(_("mount(2) failed")); /* print errno */
461 }
462 break;
463
464 case EINVAL:
465 if (mflags & MS_REMOUNT)
466 warnx(_("%s not mounted or bad option"), tgt);
58f108ef
KZ
467 else if (mflags & MS_PROPAGATION)
468 warnx(_("%s is not mountpoint or bad option"), tgt);
ce433404
KZ
469 else
470 warnx(_("wrong fs type, bad option, bad superblock on %s,\n"
471 " missing codepage or helper program, or other error"),
472 src);
473
474 if (mnt_fs_is_netfs(mnt_context_get_fs(cxt)))
475 fprintf(stderr, _(
476 " (for several filesystems (e.g. nfs, cifs) you might\n"
477 " need a /sbin/mount.<type> helper program)\n"));
478
479 fprintf(stderr, _(
480 " In some cases useful info is found in syslog - try\n"
481 " dmesg | tail or so\n"));
482 break;
483
484 case EMFILE:
485 warnx(_("mount table full"));
486 break;
487
488 case EIO:
489 warnx(_("%s: can't read superblock"), src);
490 break;
491
492 case ENODEV:
493 warnx(_("unknown filesystem type '%s'"), mnt_context_get_fstype(cxt));
494 break;
495
496 case ENOTBLK:
497 if (uflags & MNT_MS_NOFAIL)
497d2ce7 498 return MOUNT_EX_SUCCESS;
ce433404
KZ
499
500 if (stat(src, &st))
501 warnx(_("%s is not a block device, and stat(2) fails?"), src);
502 else if (S_ISBLK(st.st_mode))
503 warnx(_("the kernel does not recognize %s as a block device\n"
504 " (maybe `modprobe driver'?)"), src);
505 else if (S_ISREG(st.st_mode))
506 warnx(_("%s is not a block device (maybe try `-o loop'?)"), src);
507 else
508 warnx(_(" %s is not a block device"), src);
509 break;
510
511 case ENXIO:
512 if (uflags & MNT_MS_NOFAIL)
497d2ce7 513 return MOUNT_EX_SUCCESS;
ce433404
KZ
514
515 warnx(_("%s is not a valid block device"), src);
516 break;
517
518 case EACCES:
519 case EROFS:
520 if (mflags & MS_RDONLY)
521 warnx(_("cannot mount %s read-only"), src);
522
523 else if (readwrite)
524 warnx(_("%s is write-protected but explicit `-w' flag given"), src);
525
526 else if (mflags & MS_REMOUNT)
527 warnx(_("cannot remount %s read-write, is write-protected"), src);
528
529 else {
530 warnx(_("%s is write-protected, mounting read-only"), src);
531
532 mnt_context_reset_status(cxt);
533 mnt_context_set_mflags(cxt, mflags | MS_RDONLY);
534 rc = mnt_context_do_mount(cxt);
535 if (!rc)
536 rc = mnt_context_finalize_mount(cxt);
537
538 goto try_readonly;
539 }
540 break;
541
542 case ENOMEDIUM:
543 warnx(_("no medium found on %s"), src);
544 break;
545
546 default:
547 warn(_("mount %s on %s failed"), src, tgt);
548 break;
549 }
550
497d2ce7 551 return MOUNT_EX_FAIL;
ce433404
KZ
552}
553
64b6bc4f
KZ
554static struct libmnt_table *append_fstab(struct libmnt_context *cxt,
555 struct libmnt_table *fstab,
556 const char *path)
557{
558
559 if (!fstab) {
560 fstab = mnt_new_table();
561 if (!fstab)
562 err(MOUNT_EX_SYSERR, _("failed to initialize libmount table"));
563
564 mnt_table_set_parser_errcb(fstab, table_parser_errcb);
565 mnt_context_set_fstab(cxt, fstab);
566 }
567
568 if (mnt_table_parse_fstab(fstab, path))
569 errx(MOUNT_EX_USAGE,_("%s: failed to parse"), path);
570
571 return fstab;
572}
573
97073441
KZ
574static void __attribute__((__noreturn__)) usage(FILE *out)
575{
e4c92d06
KZ
576 fputs(USAGE_HEADER, out);
577 fprintf(out, _(
97073441
KZ
578 " %1$s [-lhV]\n"
579 " %1$s -a [options]\n"
580 " %1$s [options] <source> | <directory>\n"
581 " %1$s [options] <source> <directory>\n"
582 " %1$s <operation> <mountpoint> [<target>]\n"),
583 program_invocation_short_name);
584
e4c92d06 585 fputs(USAGE_OPTIONS, out);
97073441 586 fprintf(out, _(
97073441 587 " -a, --all mount all filesystems mentioned in fstab\n"
97073441 588 " -c, --no-canonicalize don't canonicalize paths\n"
eaca47f7 589 " -f, --fake dry run; skip the mount(2) syscall\n"
64b6bc4f
KZ
590 " -F, --fork fork off for each device (use with -a)\n"
591 " -T, --fstab <path> alternative file to /etc/fstab\n"));
eaca47f7
BS
592 fprintf(out, _(
593 " -h, --help display this help text and exit\n"
97073441
KZ
594 " -i, --internal-only don't call the mount.<type> helpers\n"
595 " -l, --show-labels lists all mounts with LABELs\n"
eaca47f7
BS
596 " -n, --no-mtab don't write to /etc/mtab\n"));
597 fprintf(out, _(
598 " -o, --options <list> comma-separated list of mount options\n"
599 " -O, --test-opts <list> limit the set of filesystems (use with -a)\n"
dbae36fe 600 " -p, --pass-fd <num> read the passphrase from file descriptor\n"
eaca47f7
BS
601 " -r, --read-only mount the filesystem read-only (same as -o ro)\n"
602 " -t, --types <list> limit the set of filesystem types\n"));
603 fprintf(out, _(
604 " -v, --verbose say what is being done\n"
605 " -V, --version display version information and exit\n"
606 " -w, --read-write mount the filesystem read-write (default)\n"));
97073441 607
e4c92d06
KZ
608 fputs(USAGE_SEPARATOR, out);
609 fputs(USAGE_HELP, out);
610 fputs(USAGE_VERSION, out);
611
eaca47f7 612 fprintf(out, _(
97073441
KZ
613 "\nSource:\n"
614 " -L, --label <label> synonym for LABEL=<label>\n"
615 " -U, --uuid <uuid> synonym for UUID=<uuid>\n"
616 " LABEL=<label> specifies device by filesystem label\n"
eb0eb262
KZ
617 " UUID=<uuid> specifies device by filesystem UUID\n"
618 " PARTLABEL=<label> specifies device by partition label\n"
619 " PARTUUID=<uuid> specifies device by partition UUID\n"));
620
eaca47f7 621 fprintf(out, _(
97073441
KZ
622 " <device> specifies device by path\n"
623 " <directory> mountpoint for bind mounts (see --bind/rbind)\n"
eaca47f7 624 " <file> regular file for loopdev setup\n"));
97073441 625
eaca47f7 626 fprintf(out, _(
97073441
KZ
627 "\nOperations:\n"
628 " -B, --bind mount a subtree somewhere else (same as -o bind)\n"
629 " -M, --move move a subtree to some other place\n"
eaca47f7
BS
630 " -R, --rbind mount a subtree and all submounts somewhere else\n"));
631 fprintf(out, _(
97073441
KZ
632 " --make-shared mark a subtree as shared\n"
633 " --make-slave mark a subtree as slave\n"
634 " --make-private mark a subtree as private\n"
eaca47f7
BS
635 " --make-unbindable mark a subtree as unbindable\n"));
636 fprintf(out, _(
97073441
KZ
637 " --make-rshared recursively mark a whole subtree as shared\n"
638 " --make-rslave recursively mark a whole subtree as slave\n"
639 " --make-rprivate recursively mark a whole subtree as private\n"
eaca47f7 640 " --make-runbindable recursively mark a whole subtree as unbindable\n"));
97073441 641
e4c92d06 642 fprintf(out, USAGE_MAN_TAIL("mount(8)"));
97073441 643
497d2ce7 644 exit(out == stderr ? MOUNT_EX_USAGE : MOUNT_EX_SUCCESS);
97073441
KZ
645}
646
647int main(int argc, char **argv)
648{
497d2ce7 649 int c, rc = MOUNT_EX_SUCCESS, all = 0, show_labels = 0;
68164f6c 650 struct libmnt_context *cxt;
64b6bc4f 651 struct libmnt_table *fstab = NULL;
97073441
KZ
652 char *source = NULL, *srcbuf = NULL;
653 char *types = NULL;
654 unsigned long oper = 0;
655
2492f713
KZ
656 enum {
657 MOUNT_OPT_SHARED = CHAR_MAX + 1,
658 MOUNT_OPT_SLAVE,
659 MOUNT_OPT_PRIVATE,
660 MOUNT_OPT_UNBINDABLE,
661 MOUNT_OPT_RSHARED,
662 MOUNT_OPT_RSLAVE,
663 MOUNT_OPT_RPRIVATE,
664 MOUNT_OPT_RUNBINDABLE
665 };
666
6c7d5ae9 667 static const struct option longopts[] = {
97073441
KZ
668 { "all", 0, 0, 'a' },
669 { "fake", 0, 0, 'f' },
64b6bc4f 670 { "fstab", 1, 0, 'T' },
97073441
KZ
671 { "fork", 0, 0, 'F' },
672 { "help", 0, 0, 'h' },
673 { "no-mtab", 0, 0, 'n' },
674 { "read-only", 0, 0, 'r' },
675 { "ro", 0, 0, 'r' },
676 { "verbose", 0, 0, 'v' },
677 { "version", 0, 0, 'V' },
678 { "read-write", 0, 0, 'w' },
679 { "rw", 0, 0, 'w' },
680 { "options", 1, 0, 'o' },
681 { "test-opts", 1, 0, 'O' },
dbae36fe 682 { "pass-fd", 1, 0, 'p' },
97073441
KZ
683 { "types", 1, 0, 't' },
684 { "uuid", 1, 0, 'U' },
685 { "label", 1, 0, 'L'},
686 { "bind", 0, 0, 'B' },
687 { "move", 0, 0, 'M' },
688 { "rbind", 0, 0, 'R' },
2492f713
KZ
689 { "make-shared", 0, 0, MOUNT_OPT_SHARED },
690 { "make-slave", 0, 0, MOUNT_OPT_SLAVE },
691 { "make-private", 0, 0, MOUNT_OPT_PRIVATE },
692 { "make-unbindable", 0, 0, MOUNT_OPT_UNBINDABLE },
693 { "make-rshared", 0, 0, MOUNT_OPT_RSHARED },
694 { "make-rslave", 0, 0, MOUNT_OPT_RSLAVE },
695 { "make-rprivate", 0, 0, MOUNT_OPT_RPRIVATE },
696 { "make-runbindable", 0, 0, MOUNT_OPT_RUNBINDABLE },
97073441
KZ
697 { "no-canonicalize", 0, 0, 'c' },
698 { "internal-only", 0, 0, 'i' },
699 { "show-labels", 0, 0, 'l' },
700 { NULL, 0, 0, 0 }
701 };
702
6189ace3 703 sanitize_env();
97073441
KZ
704 setlocale(LC_ALL, "");
705 bindtextdomain(PACKAGE, LOCALEDIR);
706 textdomain(PACKAGE);
efb8854f 707 atexit(close_stdout);
97073441
KZ
708
709 mnt_init_debug(0);
710 cxt = mnt_new_context();
711 if (!cxt)
497d2ce7 712 err(MOUNT_EX_SYSERR, _("libmount context allocation failed"));
97073441 713
9f7472b0
KZ
714 mnt_context_set_tables_errcb(cxt, table_parser_errcb);
715
64b6bc4f 716 while ((c = getopt_long(argc, argv, "aBcfFhilL:Mno:O:p:rRsU:vVwt:T:",
97073441
KZ
717 longopts, NULL)) != -1) {
718
719 /* only few options are allowed for non-root users */
50d0ad98 720 if (mnt_context_is_restricted(cxt) && !strchr("hlLUVvpri", c))
732a6311 721 exit_non_root(option_to_longopt(c, longopts));
97073441
KZ
722
723 switch(c) {
724 case 'a':
725 all = 1;
97073441
KZ
726 break;
727 case 'c':
728 mnt_context_disable_canonicalize(cxt, TRUE);
729 break;
730 case 'f':
731 mnt_context_enable_fake(cxt, TRUE);
732 break;
733 case 'F':
d2c97887 734 mnt_context_enable_fork(cxt, TRUE);
97073441
KZ
735 break;
736 case 'h':
737 usage(stdout);
738 break;
739 case 'i':
740 mnt_context_disable_helpers(cxt, TRUE);
741 break;
742 case 'n':
743 mnt_context_disable_mtab(cxt, TRUE);
744 break;
745 case 'r':
746 if (mnt_context_append_options(cxt, "ro"))
497d2ce7 747 err(MOUNT_EX_SYSERR, _("failed to append options"));
ce433404 748 readwrite = 0;
97073441
KZ
749 break;
750 case 'v':
751 mnt_context_enable_verbose(cxt, TRUE);
752 break;
753 case 'V':
754 print_version();
755 break;
756 case 'w':
757 if (mnt_context_append_options(cxt, "rw"))
497d2ce7 758 err(MOUNT_EX_SYSERR, _("failed to append options"));
ce433404 759 readwrite = 1;
97073441
KZ
760 break;
761 case 'o':
762 if (mnt_context_append_options(cxt, optarg))
497d2ce7 763 err(MOUNT_EX_SYSERR, _("failed to append options"));
97073441
KZ
764 break;
765 case 'O':
766 if (mnt_context_set_options_pattern(cxt, optarg))
497d2ce7 767 err(MOUNT_EX_SYSERR, _("failed to set options pattern"));
97073441 768 break;
dbae36fe
KZ
769 case 'p':
770 passfd = strtol_or_err(optarg,
771 _("invalid passphrase file descriptor"));
772 break;
97073441
KZ
773 case 'L':
774 case 'U':
775 if (source)
497d2ce7 776 errx(MOUNT_EX_USAGE, _("only one <source> may be specified"));
6f312c89 777 if (xasprintf(&srcbuf, "%s=\"%s\"",
97073441 778 c == 'L' ? "LABEL" : "UUID", optarg) <= 0)
497d2ce7 779 err(MOUNT_EX_SYSERR, _("failed to allocate source buffer"));
97073441
KZ
780 source = srcbuf;
781 break;
782 case 'l':
783 show_labels = 1;
784 break;
785 case 't':
786 types = optarg;
787 break;
64b6bc4f
KZ
788 case 'T':
789 fstab = append_fstab(cxt, fstab, optarg);
790 break;
97073441
KZ
791 case 's':
792 mnt_context_enable_sloppy(cxt, TRUE);
793 break;
794 case 'B':
d7890778 795 oper |= MS_BIND;
97073441
KZ
796 break;
797 case 'M':
d7890778 798 oper |= MS_MOVE;
97073441
KZ
799 break;
800 case 'R':
d7890778 801 oper |= (MS_BIND | MS_REC);
97073441 802 break;
2492f713 803 case MOUNT_OPT_SHARED:
d7890778 804 oper |= MS_SHARED;
97073441 805 break;
2492f713 806 case MOUNT_OPT_SLAVE:
d7890778 807 oper |= MS_SLAVE;
97073441 808 break;
2492f713 809 case MOUNT_OPT_PRIVATE:
d7890778 810 oper |= MS_PRIVATE;
97073441 811 break;
2492f713 812 case MOUNT_OPT_UNBINDABLE:
d7890778 813 oper |= MS_UNBINDABLE;
97073441 814 break;
2492f713 815 case MOUNT_OPT_RSHARED:
d7890778 816 oper |= (MS_SHARED | MS_REC);
97073441 817 break;
2492f713 818 case MOUNT_OPT_RSLAVE:
d7890778 819 oper |= (MS_SLAVE | MS_REC);
97073441 820 break;
2492f713 821 case MOUNT_OPT_RPRIVATE:
d7890778 822 oper |= (MS_PRIVATE | MS_REC);
97073441 823 break;
2492f713 824 case MOUNT_OPT_RUNBINDABLE:
d7890778 825 oper |= (MS_UNBINDABLE | MS_REC);
97073441
KZ
826 break;
827 default:
828 usage(stderr);
829 break;
830 }
831 }
832
833 argc -= optind;
834 argv += optind;
835
836 if (!source && !argc && !all) {
837 if (oper)
838 usage(stderr);
11754572 839 print_all(cxt, types, show_labels);
97073441
KZ
840 goto done;
841 }
842
843 if (oper && (types || all || source))
844 usage(stderr);
845
9f7472b0
KZ
846 if (types && (all || strchr(types, ',') ||
847 strncmp(types, "no", 2) == 0))
97073441
KZ
848 mnt_context_set_fstype_pattern(cxt, types);
849 else if (types)
850 mnt_context_set_fstype(cxt, types);
851
dbae36fe
KZ
852 mnt_context_set_passwd_cb(cxt, encrypt_pass_get, encrypt_pass_release);
853
a9ae3955
KZ
854 if (all) {
855 /*
856 * A) Mount all
857 */
d2c97887 858 rc = mount_all(cxt);
11754572 859 goto done;
a9ae3955
KZ
860
861 } else if (argc == 0 && source) {
862 /*
863 * B) mount -L|-U
864 */
97073441
KZ
865 mnt_context_set_source(cxt, source);
866
867 } else if (argc == 1) {
a9ae3955
KZ
868 /*
869 * C) mount [-L|-U] <target>
870 * mount <source|target>
871 */
97073441
KZ
872 if (source) {
873 if (mnt_context_is_restricted(cxt))
874 exit_non_root(NULL);
875 mnt_context_set_source(cxt, source);
876 }
877 mnt_context_set_target(cxt, argv[0]);
878
879 } else if (argc == 2 && !source) {
a9ae3955
KZ
880 /*
881 * D) mount <source> <target>
882 */
97073441
KZ
883 if (mnt_context_is_restricted(cxt))
884 exit_non_root(NULL);
885 mnt_context_set_source(cxt, argv[0]);
886 mnt_context_set_target(cxt, argv[1]);
887 } else
888 usage(stderr);
889
374fd21a 890 if (oper) {
d7890778
KZ
891 if (!is_power_of_2(oper))
892 errx(MOUNT_EX_USAGE, _("propagation flags (--make-* or --bind options) are mutually exclusive"));
893
894 if (oper != MS_BIND && mnt_context_get_options(cxt))
895 errx(MOUNT_EX_USAGE, _("propagation flags (--make-* options) cannot be mixed with another mount options"));
896
374fd21a 897 /* MS_PROPAGATION operations, let's set the mount flags */
68164f6c 898 mnt_context_set_mflags(cxt, oper);
97073441 899
374fd21a
KZ
900 /* For -make* or --bind is fstab unnecessary */
901 mnt_context_set_optsmode(cxt, MNT_OMODE_NOTAB);
902 }
903
cfb9db30 904 rc = mnt_context_mount(cxt);
ce433404
KZ
905 rc = mk_exit_code(cxt, rc);
906
97073441
KZ
907done:
908 free(srcbuf);
909 mnt_free_context(cxt);
64b6bc4f 910 mnt_free_table(fstab);
97073441
KZ
911 return rc;
912}
913