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