]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/mount.c
sys-utils: verify writing to streams was successful
[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
772cce37
KZ
352 /*
353 * TODO: add mnt_context_fstab_applied() to check if we found
354 * target/source in the file.
355 */
356 if (!tgt) {
ce433404
KZ
357 if (mflags & MS_REMOUNT)
358 warnx(_("%s not mounted"), src ? src : tgt);
359 else
360 warnx(_("can't find %s in %s"), src ? src : tgt,
361 mnt_get_fstab_path());
497d2ce7 362 return MOUNT_EX_USAGE;
ce433404
KZ
363 }
364
365 if (!mnt_context_get_fstype(cxt)) {
366 if (restricted)
367 warnx(_("I could not determine the filesystem type, "
368 "and none was specified"));
369 else
370 warnx(_("you must specify the filesystem type"));
497d2ce7 371 return MOUNT_EX_USAGE;
ce433404 372 }
2e86597f
KZ
373 return handle_generic_errors(rc, _("%s: mount failed"),
374 tgt ? tgt : src);
ce433404
KZ
375
376 } else if (mnt_context_get_syscall_errno(cxt) == 0) {
377 /*
378 * mount(2) syscall success, but something else failed
379 * (probably error in mtab processing).
380 */
381 if (rc < 0)
382 return handle_generic_errors(rc,
2e86597f
KZ
383 _("%s: filesystem mounted, but mount(8) failed"),
384 tgt ? tgt : src);
ce433404 385
497d2ce7 386 return MOUNT_EX_SOFTWARE; /* internal error */
ce433404
KZ
387
388 }
389
390 /*
391 * mount(2) errors
392 */
393 syserr = mnt_context_get_syscall_errno(cxt);
394
395 mnt_context_get_mflags(cxt, &mflags); /* mount(2) flags */
396 mnt_context_get_user_mflags(cxt, &uflags); /* userspace flags */
397
398 switch(syserr) {
399 case EPERM:
400 if (geteuid() == 0) {
401 if (stat(tgt, &st) || !S_ISDIR(st.st_mode))
402 warnx(_("mount point %s is not a directory"), tgt);
403 else
404 warnx(_("permission denied"));
405 } else
406 warnx(_("must be superuser to use mount"));
407 break;
408
409 case EBUSY:
410 {
411 struct libmnt_table *tb;
ce433404
KZ
412
413 if (mflags & MS_REMOUNT) {
414 warnx(_("%s is busy"), tgt);
415 break;
416 }
417
418 warnx(_("%s is already mounted or %s busy"), src, tgt);
419
420 if (src && mnt_context_get_mtab(cxt, &tb) == 0) {
421 struct libmnt_iter *itr = mnt_new_iter(MNT_ITER_FORWARD);
422 struct libmnt_fs *fs;
423
424 while(mnt_table_next_fs(tb, itr, &fs) == 0) {
425 const char *s = mnt_fs_get_srcpath(fs),
426 *t = mnt_fs_get_target(fs);
427
6699e742 428 if (t && s && mnt_fs_streq_srcpath(fs, src))
ce433404
KZ
429 fprintf(stderr, _(
430 " %s is already mounted on %s\n"), s, t);
431 }
432 mnt_free_iter(itr);
433 }
434 break;
435 }
436 case ENOENT:
437 if (lstat(tgt, &st))
438 warnx(_("mount point %s does not exist"), tgt);
439 else if (stat(tgt, &st))
440 warnx(_("mount point %s is a symbolic link to nowhere"), tgt);
441 else if (stat(src, &st)) {
442 if (uflags & MNT_MS_NOFAIL)
497d2ce7 443 return MOUNT_EX_SUCCESS;
ce433404
KZ
444
445 warnx(_("special device %s does not exist"), src);
446 } else {
447 errno = syserr;
448 warn(_("mount(2) failed")); /* print errno */
449 }
450 break;
451
452 case ENOTDIR:
453 if (stat(tgt, &st) || ! S_ISDIR(st.st_mode))
454 warnx(_("mount point %s is not a directory"), tgt);
455 else if (stat(src, &st) && errno == ENOTDIR) {
456 if (uflags & MNT_MS_NOFAIL)
497d2ce7 457 return MOUNT_EX_SUCCESS;
ce433404
KZ
458
459 warnx(_("special device %s does not exist "
460 "(a path prefix is not a directory)"), src);
461 } else {
462 errno = syserr;
463 warn(_("mount(2) failed")); /* print errno */
464 }
465 break;
466
467 case EINVAL:
468 if (mflags & MS_REMOUNT)
469 warnx(_("%s not mounted or bad option"), tgt);
470 else
471 warnx(_("wrong fs type, bad option, bad superblock on %s,\n"
472 " missing codepage or helper program, or other error"),
473 src);
474
475 if (mnt_fs_is_netfs(mnt_context_get_fs(cxt)))
476 fprintf(stderr, _(
477 " (for several filesystems (e.g. nfs, cifs) you might\n"
478 " need a /sbin/mount.<type> helper program)\n"));
479
480 fprintf(stderr, _(
481 " In some cases useful info is found in syslog - try\n"
482 " dmesg | tail or so\n"));
483 break;
484
485 case EMFILE:
486 warnx(_("mount table full"));
487 break;
488
489 case EIO:
490 warnx(_("%s: can't read superblock"), src);
491 break;
492
493 case ENODEV:
494 warnx(_("unknown filesystem type '%s'"), mnt_context_get_fstype(cxt));
495 break;
496
497 case ENOTBLK:
498 if (uflags & MNT_MS_NOFAIL)
497d2ce7 499 return MOUNT_EX_SUCCESS;
ce433404
KZ
500
501 if (stat(src, &st))
502 warnx(_("%s is not a block device, and stat(2) fails?"), src);
503 else if (S_ISBLK(st.st_mode))
504 warnx(_("the kernel does not recognize %s as a block device\n"
505 " (maybe `modprobe driver'?)"), src);
506 else if (S_ISREG(st.st_mode))
507 warnx(_("%s is not a block device (maybe try `-o loop'?)"), src);
508 else
509 warnx(_(" %s is not a block device"), src);
510 break;
511
512 case ENXIO:
513 if (uflags & MNT_MS_NOFAIL)
497d2ce7 514 return MOUNT_EX_SUCCESS;
ce433404
KZ
515
516 warnx(_("%s is not a valid block device"), src);
517 break;
518
519 case EACCES:
520 case EROFS:
521 if (mflags & MS_RDONLY)
522 warnx(_("cannot mount %s read-only"), src);
523
524 else if (readwrite)
525 warnx(_("%s is write-protected but explicit `-w' flag given"), src);
526
527 else if (mflags & MS_REMOUNT)
528 warnx(_("cannot remount %s read-write, is write-protected"), src);
529
530 else {
531 warnx(_("%s is write-protected, mounting read-only"), src);
532
533 mnt_context_reset_status(cxt);
534 mnt_context_set_mflags(cxt, mflags | MS_RDONLY);
535 rc = mnt_context_do_mount(cxt);
536 if (!rc)
537 rc = mnt_context_finalize_mount(cxt);
538
539 goto try_readonly;
540 }
541 break;
542
543 case ENOMEDIUM:
544 warnx(_("no medium found on %s"), src);
545 break;
546
547 default:
548 warn(_("mount %s on %s failed"), src, tgt);
549 break;
550 }
551
497d2ce7 552 return MOUNT_EX_FAIL;
ce433404
KZ
553}
554
64b6bc4f
KZ
555static struct libmnt_table *append_fstab(struct libmnt_context *cxt,
556 struct libmnt_table *fstab,
557 const char *path)
558{
559
560 if (!fstab) {
561 fstab = mnt_new_table();
562 if (!fstab)
563 err(MOUNT_EX_SYSERR, _("failed to initialize libmount table"));
564
565 mnt_table_set_parser_errcb(fstab, table_parser_errcb);
566 mnt_context_set_fstab(cxt, fstab);
567 }
568
569 if (mnt_table_parse_fstab(fstab, path))
570 errx(MOUNT_EX_USAGE,_("%s: failed to parse"), path);
571
572 return fstab;
573}
574
97073441
KZ
575static void __attribute__((__noreturn__)) usage(FILE *out)
576{
e4c92d06
KZ
577 fputs(USAGE_HEADER, out);
578 fprintf(out, _(
97073441
KZ
579 " %1$s [-lhV]\n"
580 " %1$s -a [options]\n"
581 " %1$s [options] <source> | <directory>\n"
582 " %1$s [options] <source> <directory>\n"
583 " %1$s <operation> <mountpoint> [<target>]\n"),
584 program_invocation_short_name);
585
e4c92d06 586 fputs(USAGE_OPTIONS, out);
97073441 587 fprintf(out, _(
97073441 588 " -a, --all mount all filesystems mentioned in fstab\n"
97073441 589 " -c, --no-canonicalize don't canonicalize paths\n"
eaca47f7 590 " -f, --fake dry run; skip the mount(2) syscall\n"
64b6bc4f
KZ
591 " -F, --fork fork off for each device (use with -a)\n"
592 " -T, --fstab <path> alternative file to /etc/fstab\n"));
eaca47f7
BS
593 fprintf(out, _(
594 " -h, --help display this help text and exit\n"
97073441
KZ
595 " -i, --internal-only don't call the mount.<type> helpers\n"
596 " -l, --show-labels lists all mounts with LABELs\n"
eaca47f7
BS
597 " -n, --no-mtab don't write to /etc/mtab\n"));
598 fprintf(out, _(
599 " -o, --options <list> comma-separated list of mount options\n"
600 " -O, --test-opts <list> limit the set of filesystems (use with -a)\n"
dbae36fe 601 " -p, --pass-fd <num> read the passphrase from file descriptor\n"
eaca47f7
BS
602 " -r, --read-only mount the filesystem read-only (same as -o ro)\n"
603 " -t, --types <list> limit the set of filesystem types\n"));
604 fprintf(out, _(
605 " -v, --verbose say what is being done\n"
606 " -V, --version display version information and exit\n"
607 " -w, --read-write mount the filesystem read-write (default)\n"));
97073441 608
e4c92d06
KZ
609 fputs(USAGE_SEPARATOR, out);
610 fputs(USAGE_HELP, out);
611 fputs(USAGE_VERSION, out);
612
eaca47f7 613 fprintf(out, _(
97073441
KZ
614 "\nSource:\n"
615 " -L, --label <label> synonym for LABEL=<label>\n"
616 " -U, --uuid <uuid> synonym for UUID=<uuid>\n"
617 " LABEL=<label> specifies device by filesystem label\n"
eaca47f7
BS
618 " UUID=<uuid> specifies device by filesystem UUID\n"));
619 fprintf(out, _(
97073441
KZ
620 " <device> specifies device by path\n"
621 " <directory> mountpoint for bind mounts (see --bind/rbind)\n"
eaca47f7 622 " <file> regular file for loopdev setup\n"));
97073441 623
eaca47f7 624 fprintf(out, _(
97073441
KZ
625 "\nOperations:\n"
626 " -B, --bind mount a subtree somewhere else (same as -o bind)\n"
627 " -M, --move move a subtree to some other place\n"
eaca47f7
BS
628 " -R, --rbind mount a subtree and all submounts somewhere else\n"));
629 fprintf(out, _(
97073441
KZ
630 " --make-shared mark a subtree as shared\n"
631 " --make-slave mark a subtree as slave\n"
632 " --make-private mark a subtree as private\n"
eaca47f7
BS
633 " --make-unbindable mark a subtree as unbindable\n"));
634 fprintf(out, _(
97073441
KZ
635 " --make-rshared recursively mark a whole subtree as shared\n"
636 " --make-rslave recursively mark a whole subtree as slave\n"
637 " --make-rprivate recursively mark a whole subtree as private\n"
eaca47f7 638 " --make-runbindable recursively mark a whole subtree as unbindable\n"));
97073441 639
e4c92d06 640 fprintf(out, USAGE_MAN_TAIL("mount(8)"));
97073441 641
497d2ce7 642 exit(out == stderr ? MOUNT_EX_USAGE : MOUNT_EX_SUCCESS);
97073441
KZ
643}
644
645int main(int argc, char **argv)
646{
497d2ce7 647 int c, rc = MOUNT_EX_SUCCESS, all = 0, show_labels = 0;
68164f6c 648 struct libmnt_context *cxt;
64b6bc4f 649 struct libmnt_table *fstab = NULL;
97073441
KZ
650 char *source = NULL, *srcbuf = NULL;
651 char *types = NULL;
652 unsigned long oper = 0;
653
2492f713
KZ
654 enum {
655 MOUNT_OPT_SHARED = CHAR_MAX + 1,
656 MOUNT_OPT_SLAVE,
657 MOUNT_OPT_PRIVATE,
658 MOUNT_OPT_UNBINDABLE,
659 MOUNT_OPT_RSHARED,
660 MOUNT_OPT_RSLAVE,
661 MOUNT_OPT_RPRIVATE,
662 MOUNT_OPT_RUNBINDABLE
663 };
664
6c7d5ae9 665 static const struct option longopts[] = {
97073441
KZ
666 { "all", 0, 0, 'a' },
667 { "fake", 0, 0, 'f' },
64b6bc4f 668 { "fstab", 1, 0, 'T' },
97073441
KZ
669 { "fork", 0, 0, 'F' },
670 { "help", 0, 0, 'h' },
671 { "no-mtab", 0, 0, 'n' },
672 { "read-only", 0, 0, 'r' },
673 { "ro", 0, 0, 'r' },
674 { "verbose", 0, 0, 'v' },
675 { "version", 0, 0, 'V' },
676 { "read-write", 0, 0, 'w' },
677 { "rw", 0, 0, 'w' },
678 { "options", 1, 0, 'o' },
679 { "test-opts", 1, 0, 'O' },
dbae36fe 680 { "pass-fd", 1, 0, 'p' },
97073441
KZ
681 { "types", 1, 0, 't' },
682 { "uuid", 1, 0, 'U' },
683 { "label", 1, 0, 'L'},
684 { "bind", 0, 0, 'B' },
685 { "move", 0, 0, 'M' },
686 { "rbind", 0, 0, 'R' },
2492f713
KZ
687 { "make-shared", 0, 0, MOUNT_OPT_SHARED },
688 { "make-slave", 0, 0, MOUNT_OPT_SLAVE },
689 { "make-private", 0, 0, MOUNT_OPT_PRIVATE },
690 { "make-unbindable", 0, 0, MOUNT_OPT_UNBINDABLE },
691 { "make-rshared", 0, 0, MOUNT_OPT_RSHARED },
692 { "make-rslave", 0, 0, MOUNT_OPT_RSLAVE },
693 { "make-rprivate", 0, 0, MOUNT_OPT_RPRIVATE },
694 { "make-runbindable", 0, 0, MOUNT_OPT_RUNBINDABLE },
97073441
KZ
695 { "no-canonicalize", 0, 0, 'c' },
696 { "internal-only", 0, 0, 'i' },
697 { "show-labels", 0, 0, 'l' },
698 { NULL, 0, 0, 0 }
699 };
700
6189ace3 701 sanitize_env();
97073441
KZ
702 setlocale(LC_ALL, "");
703 bindtextdomain(PACKAGE, LOCALEDIR);
704 textdomain(PACKAGE);
efb8854f 705 atexit(close_stdout);
97073441
KZ
706
707 mnt_init_debug(0);
708 cxt = mnt_new_context();
709 if (!cxt)
497d2ce7 710 err(MOUNT_EX_SYSERR, _("libmount context allocation failed"));
97073441 711
9f7472b0
KZ
712 mnt_context_set_tables_errcb(cxt, table_parser_errcb);
713
64b6bc4f 714 while ((c = getopt_long(argc, argv, "aBcfFhilL:Mno:O:p:rRsU:vVwt:T:",
97073441
KZ
715 longopts, NULL)) != -1) {
716
717 /* only few options are allowed for non-root users */
50d0ad98 718 if (mnt_context_is_restricted(cxt) && !strchr("hlLUVvpri", c))
732a6311 719 exit_non_root(option_to_longopt(c, longopts));
97073441
KZ
720
721 switch(c) {
722 case 'a':
723 all = 1;
97073441
KZ
724 break;
725 case 'c':
726 mnt_context_disable_canonicalize(cxt, TRUE);
727 break;
728 case 'f':
729 mnt_context_enable_fake(cxt, TRUE);
730 break;
731 case 'F':
d2c97887 732 mnt_context_enable_fork(cxt, TRUE);
97073441
KZ
733 break;
734 case 'h':
735 usage(stdout);
736 break;
737 case 'i':
738 mnt_context_disable_helpers(cxt, TRUE);
739 break;
740 case 'n':
741 mnt_context_disable_mtab(cxt, TRUE);
742 break;
743 case 'r':
744 if (mnt_context_append_options(cxt, "ro"))
497d2ce7 745 err(MOUNT_EX_SYSERR, _("failed to append options"));
ce433404 746 readwrite = 0;
97073441
KZ
747 break;
748 case 'v':
749 mnt_context_enable_verbose(cxt, TRUE);
750 break;
751 case 'V':
752 print_version();
753 break;
754 case 'w':
755 if (mnt_context_append_options(cxt, "rw"))
497d2ce7 756 err(MOUNT_EX_SYSERR, _("failed to append options"));
ce433404 757 readwrite = 1;
97073441
KZ
758 break;
759 case 'o':
760 if (mnt_context_append_options(cxt, optarg))
497d2ce7 761 err(MOUNT_EX_SYSERR, _("failed to append options"));
97073441
KZ
762 break;
763 case 'O':
764 if (mnt_context_set_options_pattern(cxt, optarg))
497d2ce7 765 err(MOUNT_EX_SYSERR, _("failed to set options pattern"));
97073441 766 break;
dbae36fe
KZ
767 case 'p':
768 passfd = strtol_or_err(optarg,
769 _("invalid passphrase file descriptor"));
770 break;
97073441
KZ
771 case 'L':
772 case 'U':
773 if (source)
497d2ce7 774 errx(MOUNT_EX_USAGE, _("only one <source> may be specified"));
6f312c89 775 if (xasprintf(&srcbuf, "%s=\"%s\"",
97073441 776 c == 'L' ? "LABEL" : "UUID", optarg) <= 0)
497d2ce7 777 err(MOUNT_EX_SYSERR, _("failed to allocate source buffer"));
97073441
KZ
778 source = srcbuf;
779 break;
780 case 'l':
781 show_labels = 1;
782 break;
783 case 't':
784 types = optarg;
785 break;
64b6bc4f
KZ
786 case 'T':
787 fstab = append_fstab(cxt, fstab, optarg);
788 break;
97073441
KZ
789 case 's':
790 mnt_context_enable_sloppy(cxt, TRUE);
791 break;
792 case 'B':
793 oper = MS_BIND;
794 break;
795 case 'M':
796 oper = MS_MOVE;
797 break;
798 case 'R':
799 oper = (MS_BIND | MS_REC);
800 break;
2492f713 801 case MOUNT_OPT_SHARED:
97073441
KZ
802 oper = MS_SHARED;
803 break;
2492f713 804 case MOUNT_OPT_SLAVE:
97073441
KZ
805 oper = MS_SLAVE;
806 break;
2492f713 807 case MOUNT_OPT_PRIVATE:
97073441
KZ
808 oper = MS_PRIVATE;
809 break;
2492f713 810 case MOUNT_OPT_UNBINDABLE:
97073441
KZ
811 oper = MS_UNBINDABLE;
812 break;
2492f713 813 case MOUNT_OPT_RSHARED:
97073441
KZ
814 oper = (MS_SHARED | MS_REC);
815 break;
2492f713 816 case MOUNT_OPT_RSLAVE:
97073441
KZ
817 oper = (MS_SLAVE | MS_REC);
818 break;
2492f713 819 case MOUNT_OPT_RPRIVATE:
97073441
KZ
820 oper = (MS_PRIVATE | MS_REC);
821 break;
2492f713 822 case MOUNT_OPT_RUNBINDABLE:
97073441
KZ
823 oper = (MS_UNBINDABLE | MS_REC);
824 break;
825 default:
826 usage(stderr);
827 break;
828 }
829 }
830
831 argc -= optind;
832 argv += optind;
833
834 if (!source && !argc && !all) {
835 if (oper)
836 usage(stderr);
11754572 837 print_all(cxt, types, show_labels);
97073441
KZ
838 goto done;
839 }
840
841 if (oper && (types || all || source))
842 usage(stderr);
843
9f7472b0
KZ
844 if (types && (all || strchr(types, ',') ||
845 strncmp(types, "no", 2) == 0))
97073441
KZ
846 mnt_context_set_fstype_pattern(cxt, types);
847 else if (types)
848 mnt_context_set_fstype(cxt, types);
849
dbae36fe
KZ
850 mnt_context_set_passwd_cb(cxt, encrypt_pass_get, encrypt_pass_release);
851
a9ae3955
KZ
852 if (all) {
853 /*
854 * A) Mount all
855 */
d2c97887 856 rc = mount_all(cxt);
11754572 857 goto done;
a9ae3955
KZ
858
859 } else if (argc == 0 && source) {
860 /*
861 * B) mount -L|-U
862 */
97073441
KZ
863 mnt_context_set_source(cxt, source);
864
865 } else if (argc == 1) {
a9ae3955
KZ
866 /*
867 * C) mount [-L|-U] <target>
868 * mount <source|target>
869 */
97073441
KZ
870 if (source) {
871 if (mnt_context_is_restricted(cxt))
872 exit_non_root(NULL);
873 mnt_context_set_source(cxt, source);
874 }
875 mnt_context_set_target(cxt, argv[0]);
876
877 } else if (argc == 2 && !source) {
a9ae3955
KZ
878 /*
879 * D) mount <source> <target>
880 */
97073441
KZ
881 if (mnt_context_is_restricted(cxt))
882 exit_non_root(NULL);
883 mnt_context_set_source(cxt, argv[0]);
884 mnt_context_set_target(cxt, argv[1]);
885 } else
886 usage(stderr);
887
374fd21a
KZ
888 if (oper) {
889 /* MS_PROPAGATION operations, let's set the mount flags */
68164f6c 890 mnt_context_set_mflags(cxt, oper);
97073441 891
374fd21a
KZ
892 /* For -make* or --bind is fstab unnecessary */
893 mnt_context_set_optsmode(cxt, MNT_OMODE_NOTAB);
894 }
895
cfb9db30 896 rc = mnt_context_mount(cxt);
ce433404
KZ
897 rc = mk_exit_code(cxt, rc);
898
97073441
KZ
899done:
900 free(srcbuf);
901 mnt_free_context(cxt);
64b6bc4f 902 mnt_free_table(fstab);
97073441
KZ
903 return rc;
904}
905