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