]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/samples/mount.c
docs: add x-mount-mkdir to TODO file
[thirdparty/util-linux.git] / libmount / samples / 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>
29
2a1f429a
KZ
30#include <libmount.h>
31
97073441
KZ
32#include "nls.h"
33#include "c.h"
34
35/*** TODO: DOCS:
36 *
37 * -p, --pass-fd is unsupported
38 * --guess-fstype is unsupported
39 * -c = --no-canonicalize
40 */
41
42/* exit status */
43#define EX_SUCCESS 0
44#define EX_USAGE 1 /* incorrect invocation or permission */
45#define EX_SYSERR 2 /* out of memory, cannot fork, ... */
46#define EX_SOFTWARE 4 /* internal mount bug or wrong version */
47#define EX_USER 8 /* user interrupt */
48#define EX_FILEIO 16 /* problems writing, locking, ... mtab/fstab */
49#define EX_FAIL 32 /* mount failure */
50#define EX_SOMEOK 64 /* some mount succeeded */
51
97073441
KZ
52static void __attribute__((__noreturn__)) exit_non_root(const char *option)
53{
54 const uid_t ruid = getuid();
55 const uid_t euid = geteuid();
56
57 if (ruid == 0 && euid != 0) {
58 /* user is root, but setuid to non-root */
59 if (option)
60 errx(EX_USAGE, _("only root can use \"--%s\" option "
61 "(effective UID is %u)"),
62 option, euid);
63 errx(EX_USAGE, _("only root can do that "
64 "(effective UID is %u)"), euid);
65 }
66 if (option)
67 errx(EX_USAGE, _("only root can use \"--%s\" option"), option);
68 errx(EX_USAGE, _("only root can do that"));
69}
70
71static void __attribute__((__noreturn__)) print_version(void)
72{
73 const char *ver = NULL;
74
75 mnt_get_library_version(&ver);
76
77 printf("%s from %s (libmount %s)\n",
78 program_invocation_short_name, PACKAGE_STRING, ver);
79 exit(EX_SUCCESS);
80}
81
7fc6d2b8 82static int table_parser_errcb(struct libmnt_table *tb __attribute__((__unused__)),
9f7472b0
KZ
83 const char *filename, int line)
84{
85 if (filename)
86 warnx(_("%s: parse error: ignore entry at line %d."),
87 filename, line);
88 return 0;
89}
90
97073441
KZ
91static const char *opt_to_longopt(int c, const struct option *opts)
92{
93 const struct option *o;
94
95 for (o = opts; o->name; o++)
96 if (o->val == c)
97 return o->name;
98 return NULL;
99}
100
11754572 101static void print_all(struct libmnt_context *cxt, char *pattern, int show_label)
97073441 102{
68164f6c 103 struct libmnt_table *tb;
a0c014dc 104 struct libmnt_iter *itr = NULL;
68164f6c
KZ
105 struct libmnt_fs *fs;
106 struct libmnt_cache *cache = NULL;
97073441 107
11754572
KZ
108 if (mnt_context_get_mtab(cxt, &tb))
109 err(EX_SYSERR, _("failed to read mtab"));
97073441
KZ
110
111 itr = mnt_new_iter(MNT_ITER_FORWARD);
11754572
KZ
112 if (!itr)
113 err(EX_SYSERR, _("failed to initialize libmount iterator"));
97073441
KZ
114 if (show_label)
115 cache = mnt_new_cache();
116
9f7472b0 117 while (mnt_table_next_fs(tb, itr, &fs) == 0) {
97073441
KZ
118 const char *type = mnt_fs_get_fstype(fs);
119 const char *src = mnt_fs_get_source(fs);
7cf389f7 120 const char *optstr = mnt_fs_get_options(fs);
2576b4e7 121 char *xsrc;
97073441
KZ
122
123 if (type && pattern && !mnt_match_fstype(type, pattern))
124 continue;
125
2576b4e7
KZ
126 xsrc = mnt_pretty_path(src, cache);
127 printf ("%s on %s", xsrc, mnt_fs_get_target(fs));
97073441
KZ
128 if (type)
129 printf (" type %s", type);
130 if (optstr)
131 printf (" (%s)", optstr);
132 if (show_label && src) {
133 char *lb = mnt_cache_find_tag_value(cache, src, "LABEL");
134 if (lb)
135 printf (" [%s]", lb);
136 }
137 fputc('\n', stdout);
2576b4e7 138 free(xsrc);
97073441 139 }
11754572 140
97073441 141 mnt_free_cache(cache);
b192b7b9 142 mnt_free_iter(itr);
97073441
KZ
143}
144
9f7472b0
KZ
145/*
146 * mount -a [-F]
147 * ... -F is not supported yet (TODO)
148 */
149static int mount_all(struct libmnt_context *cxt,
150 int forkme __attribute__((unused)))
a9ae3955 151{
9f7472b0
KZ
152 struct libmnt_iter *itr;
153 struct libmnt_fs *fs;
154 int mntrc, ignored, rc = EX_SUCCESS;
155
156 itr = mnt_new_iter(MNT_ITER_FORWARD);
157 if (!itr) {
158 warn(_("failed to initialize libmount iterator"));
159 return EX_SYSERR;
160 }
161
162 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
163
164 const char *tgt = mnt_fs_get_target(fs);
165
166 if (ignored) {
167 if (mnt_context_is_verbose(cxt))
168 printf(ignored == 1 ? _("%-20s: ignored\n") :
169 _("%-20s: already mounted\n"),
170 tgt);
171 } else if (!mnt_context_get_status(cxt)) {
172 if (mntrc > 0) {
173 errno = mntrc;
174 printf(_("%-20s: failed: %s\n"), tgt,
175 strerror(mntrc));
176 rc |= EX_FAIL;
177 } else {
178 printf(_("%-20s: failed\n"), tgt);
179 rc |= EX_SYSERR;
180 }
181 } else {
182 if (mnt_context_is_verbose(cxt))
183 printf("%-20s: successfully mounted\n", tgt);
184
185 rc |= EX_SOMEOK;
186 }
187 }
188
189 return rc;
a9ae3955
KZ
190}
191
97073441
KZ
192static void __attribute__((__noreturn__)) usage(FILE *out)
193{
194 fprintf(out, _("Usage:\n"
195 " %1$s [-lhV]\n"
196 " %1$s -a [options]\n"
197 " %1$s [options] <source> | <directory>\n"
198 " %1$s [options] <source> <directory>\n"
199 " %1$s <operation> <mountpoint> [<target>]\n"),
200 program_invocation_short_name);
201
202 fprintf(out, _(
203 "\nOptions:\n"
204 " -a, --all mount all filesystems mentioned in fstab\n"
97073441 205 " -c, --no-canonicalize don't canonicalize paths\n"
eaca47f7
BS
206 " -f, --fake dry run; skip the mount(2) syscall\n"
207 " -F, --fork fork off for each device (use with -a)\n"));
208 fprintf(out, _(
209 " -h, --help display this help text and exit\n"
97073441
KZ
210 " -i, --internal-only don't call the mount.<type> helpers\n"
211 " -l, --show-labels lists all mounts with LABELs\n"
eaca47f7
BS
212 " -n, --no-mtab don't write to /etc/mtab\n"));
213 fprintf(out, _(
214 " -o, --options <list> comma-separated list of mount options\n"
215 " -O, --test-opts <list> limit the set of filesystems (use with -a)\n"
216 " -r, --read-only mount the filesystem read-only (same as -o ro)\n"
217 " -t, --types <list> limit the set of filesystem types\n"));
218 fprintf(out, _(
219 " -v, --verbose say what is being done\n"
220 " -V, --version display version information and exit\n"
221 " -w, --read-write mount the filesystem read-write (default)\n"));
97073441 222
eaca47f7 223 fprintf(out, _(
97073441
KZ
224 "\nSource:\n"
225 " -L, --label <label> synonym for LABEL=<label>\n"
226 " -U, --uuid <uuid> synonym for UUID=<uuid>\n"
227 " LABEL=<label> specifies device by filesystem label\n"
eaca47f7
BS
228 " UUID=<uuid> specifies device by filesystem UUID\n"));
229 fprintf(out, _(
97073441
KZ
230 " <device> specifies device by path\n"
231 " <directory> mountpoint for bind mounts (see --bind/rbind)\n"
eaca47f7 232 " <file> regular file for loopdev setup\n"));
97073441 233
eaca47f7 234 fprintf(out, _(
97073441
KZ
235 "\nOperations:\n"
236 " -B, --bind mount a subtree somewhere else (same as -o bind)\n"
237 " -M, --move move a subtree to some other place\n"
eaca47f7
BS
238 " -R, --rbind mount a subtree and all submounts somewhere else\n"));
239 fprintf(out, _(
97073441
KZ
240 " --make-shared mark a subtree as shared\n"
241 " --make-slave mark a subtree as slave\n"
242 " --make-private mark a subtree as private\n"
eaca47f7
BS
243 " --make-unbindable mark a subtree as unbindable\n"));
244 fprintf(out, _(
97073441
KZ
245 " --make-rshared recursively mark a whole subtree as shared\n"
246 " --make-rslave recursively mark a whole subtree as slave\n"
247 " --make-rprivate recursively mark a whole subtree as private\n"
eaca47f7 248 " --make-runbindable recursively mark a whole subtree as unbindable\n"));
97073441
KZ
249
250 fprintf(out, _("\nFor more information see mount(8).\n"));
251
252 exit(out == stderr ? EX_USAGE : EX_SUCCESS);
253}
254
255int main(int argc, char **argv)
256{
11754572 257 int c, rc = EX_SUCCESS, all = 0, forkme = 0, show_labels = 0;
68164f6c 258 struct libmnt_context *cxt;
97073441
KZ
259 char *source = NULL, *srcbuf = NULL;
260 char *types = NULL;
261 unsigned long oper = 0;
262
6c7d5ae9 263 static const struct option longopts[] = {
97073441
KZ
264 { "all", 0, 0, 'a' },
265 { "fake", 0, 0, 'f' },
266 { "fork", 0, 0, 'F' },
267 { "help", 0, 0, 'h' },
268 { "no-mtab", 0, 0, 'n' },
269 { "read-only", 0, 0, 'r' },
270 { "ro", 0, 0, 'r' },
271 { "verbose", 0, 0, 'v' },
272 { "version", 0, 0, 'V' },
273 { "read-write", 0, 0, 'w' },
274 { "rw", 0, 0, 'w' },
275 { "options", 1, 0, 'o' },
276 { "test-opts", 1, 0, 'O' },
277 { "types", 1, 0, 't' },
278 { "uuid", 1, 0, 'U' },
279 { "label", 1, 0, 'L'},
280 { "bind", 0, 0, 'B' },
281 { "move", 0, 0, 'M' },
282 { "rbind", 0, 0, 'R' },
283 { "make-shared", 0, 0, 136 },
284 { "make-slave", 0, 0, 137 },
285 { "make-private", 0, 0, 138 },
286 { "make-unbindable", 0, 0, 139 },
287 { "make-rshared", 0, 0, 140 },
288 { "make-rslave", 0, 0, 141 },
289 { "make-rprivate", 0, 0, 142 },
290 { "make-runbindable", 0, 0, 143 },
291 { "no-canonicalize", 0, 0, 'c' },
292 { "internal-only", 0, 0, 'i' },
293 { "show-labels", 0, 0, 'l' },
294 { NULL, 0, 0, 0 }
295 };
296
297 setlocale(LC_ALL, "");
298 bindtextdomain(PACKAGE, LOCALEDIR);
299 textdomain(PACKAGE);
300
301 mnt_init_debug(0);
302 cxt = mnt_new_context();
303 if (!cxt)
304 err(EX_SYSERR, _("libmount context allocation failed"));
305
9f7472b0
KZ
306 mnt_context_set_tables_errcb(cxt, table_parser_errcb);
307
97073441
KZ
308 while ((c = getopt_long(argc, argv, "aBcfFhilL:Mno:O:rRsU:vVwt:",
309 longopts, NULL)) != -1) {
310
311 /* only few options are allowed for non-root users */
312 if (mnt_context_is_restricted(cxt) && !strchr("hlLUVv", c))
313 exit_non_root(opt_to_longopt(c, longopts));
314
315 switch(c) {
316 case 'a':
317 all = 1;
97073441
KZ
318 break;
319 case 'c':
320 mnt_context_disable_canonicalize(cxt, TRUE);
321 break;
322 case 'f':
323 mnt_context_enable_fake(cxt, TRUE);
324 break;
325 case 'F':
9f7472b0 326 forkme = 1;
97073441
KZ
327 break;
328 case 'h':
329 usage(stdout);
330 break;
331 case 'i':
332 mnt_context_disable_helpers(cxt, TRUE);
333 break;
334 case 'n':
335 mnt_context_disable_mtab(cxt, TRUE);
336 break;
337 case 'r':
338 if (mnt_context_append_options(cxt, "ro"))
339 err(EX_SYSERR, _("failed to append options"));
340 break;
341 case 'v':
342 mnt_context_enable_verbose(cxt, TRUE);
343 break;
344 case 'V':
345 print_version();
346 break;
347 case 'w':
348 if (mnt_context_append_options(cxt, "rw"))
349 err(EX_SYSERR, _("failed to append options"));
350 break;
351 case 'o':
352 if (mnt_context_append_options(cxt, optarg))
353 err(EX_SYSERR, _("failed to append options"));
354 break;
355 case 'O':
356 if (mnt_context_set_options_pattern(cxt, optarg))
357 err(EX_SYSERR, _("failed to set options pattern"));
358 break;
359 case 'L':
360 case 'U':
361 if (source)
e8ab5ce3 362 errx(EX_USAGE, _("only one <source> may be specified"));
97073441
KZ
363 if (asprintf(&srcbuf, "%s=\"%s\"",
364 c == 'L' ? "LABEL" : "UUID", optarg) <= 0)
365 err(EX_SYSERR, _("failed to allocate source buffer"));
366 source = srcbuf;
367 break;
368 case 'l':
369 show_labels = 1;
370 break;
371 case 't':
372 types = optarg;
373 break;
374 case 's':
375 mnt_context_enable_sloppy(cxt, TRUE);
376 break;
377 case 'B':
378 oper = MS_BIND;
379 break;
380 case 'M':
381 oper = MS_MOVE;
382 break;
383 case 'R':
384 oper = (MS_BIND | MS_REC);
385 break;
386 case 136:
387 oper = MS_SHARED;
388 break;
389 case 137:
390 oper = MS_SLAVE;
391 break;
392 case 138:
393 oper = MS_PRIVATE;
394 break;
395 case 139:
396 oper = MS_UNBINDABLE;
397 break;
398 case 140:
399 oper = (MS_SHARED | MS_REC);
400 break;
401 case 141:
402 oper = (MS_SLAVE | MS_REC);
403 break;
404 case 142:
405 oper = (MS_PRIVATE | MS_REC);
406 break;
407 case 143:
408 oper = (MS_UNBINDABLE | MS_REC);
409 break;
410 default:
411 usage(stderr);
412 break;
413 }
414 }
415
416 argc -= optind;
417 argv += optind;
418
419 if (!source && !argc && !all) {
420 if (oper)
421 usage(stderr);
11754572 422 print_all(cxt, types, show_labels);
97073441
KZ
423 goto done;
424 }
425
426 if (oper && (types || all || source))
427 usage(stderr);
428
9f7472b0
KZ
429 if (types && (all || strchr(types, ',') ||
430 strncmp(types, "no", 2) == 0))
97073441
KZ
431 mnt_context_set_fstype_pattern(cxt, types);
432 else if (types)
433 mnt_context_set_fstype(cxt, types);
434
a9ae3955
KZ
435 if (all) {
436 /*
437 * A) Mount all
438 */
9f7472b0 439 rc = mount_all(cxt, forkme);
11754572 440 goto done;
a9ae3955
KZ
441
442 } else if (argc == 0 && source) {
443 /*
444 * B) mount -L|-U
445 */
97073441
KZ
446 mnt_context_set_source(cxt, source);
447
448 } else if (argc == 1) {
a9ae3955
KZ
449 /*
450 * C) mount [-L|-U] <target>
451 * mount <source|target>
452 */
97073441
KZ
453 if (source) {
454 if (mnt_context_is_restricted(cxt))
455 exit_non_root(NULL);
456 mnt_context_set_source(cxt, source);
457 }
458 mnt_context_set_target(cxt, argv[0]);
459
460 } else if (argc == 2 && !source) {
a9ae3955
KZ
461 /*
462 * D) mount <source> <target>
463 */
97073441
KZ
464 if (mnt_context_is_restricted(cxt))
465 exit_non_root(NULL);
466 mnt_context_set_source(cxt, argv[0]);
467 mnt_context_set_target(cxt, argv[1]);
468 } else
469 usage(stderr);
470
471 if (oper)
68164f6c 472 mnt_context_set_mflags(cxt, oper);
97073441 473
cfb9db30 474 rc = mnt_context_mount(cxt);
97073441
KZ
475 if (rc) {
476 /* TODO: call mnt_context_strerror() */
477 rc = EX_FAIL;
478 } else
479 rc = EX_SUCCESS;
480done:
481 free(srcbuf);
482 mnt_free_context(cxt);
483 return rc;
484}
485