]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
mount: no exit on EPERM, continue without suid
[thirdparty/util-linux.git] / libmount / src / context.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3 * This file is part of libmount from util-linux project.
4 *
5 * Copyright (C) 2010-2018 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 */
12
13 /**
14 * SECTION: context
15 * @title: Library high-level context
16 * @short_description: high-level API to mount/umount devices.
17 *
18 * <informalexample>
19 * <programlisting>
20 * struct libmnt_context *cxt = mnt_new_context();
21 *
22 * mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
23 * mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
24 * mnt_context_set_target(cxt, "/mnt/foo");
25 *
26 * if (!mnt_context_mount(cxt))
27 * printf("successfully mounted\n");
28 * mnt_free_context(cxt);
29 *
30 * </programlisting>
31 * </informalexample>
32 *
33 * This code is similar to:
34 *
35 * mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
36 *
37 */
38
39 #include "mountP.h"
40 #include "fileutils.h"
41 #include "strutils.h"
42 #include "namespace.h"
43
44 #include <sys/wait.h>
45
46 /**
47 * mnt_new_context:
48 *
49 * Returns: newly allocated mount context
50 */
51 struct libmnt_context *mnt_new_context(void)
52 {
53 struct libmnt_context *cxt;
54 uid_t ruid, euid;
55
56 cxt = calloc(1, sizeof(*cxt));
57 if (!cxt)
58 return NULL;
59
60 INIT_LIST_HEAD(&cxt->addmounts);
61
62 ruid = getuid();
63 euid = geteuid();
64
65 mnt_context_reset_status(cxt);
66
67 cxt->loopdev_fd = -1;
68
69 cxt->ns_orig.fd = -1;
70 cxt->ns_tgt.fd = -1;
71 cxt->ns_cur = &cxt->ns_orig;
72
73 /* if we're really root and aren't running setuid */
74 cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
75
76 DBG(CXT, ul_debugobj(cxt, "----> allocate %s",
77 cxt->restricted ? "[RESTRICTED]" : ""));
78
79
80 return cxt;
81 }
82
83 /**
84 * mnt_free_context:
85 * @cxt: mount context
86 *
87 * Deallocates context struct.
88 */
89 void mnt_free_context(struct libmnt_context *cxt)
90 {
91 if (!cxt)
92 return;
93
94 mnt_reset_context(cxt);
95
96 free(cxt->fstype_pattern);
97 free(cxt->optstr_pattern);
98 free(cxt->tgt_prefix);
99
100 mnt_unref_table(cxt->fstab);
101 mnt_unref_cache(cxt->cache);
102 mnt_unref_fs(cxt->fs);
103 mnt_unref_fs(cxt->fs_template);
104
105 mnt_context_clear_loopdev(cxt);
106 mnt_free_lock(cxt->lock);
107 mnt_free_update(cxt->update);
108
109 mnt_context_set_target_ns(cxt, NULL);
110
111 free(cxt->children);
112
113 DBG(CXT, ul_debugobj(cxt, "<---- free"));
114 free(cxt);
115 }
116
117 /**
118 * mnt_reset_context:
119 * @cxt: mount context
120 *
121 * Resets all information in the context that is directly related to
122 * the latest mount (spec, source, target, mount options, ...).
123 *
124 * The match patterns, target namespace, prefix, cached fstab, cached canonicalized
125 * paths and tags and [e]uid are not reset. You have to use
126 *
127 * mnt_context_set_fstab(cxt, NULL);
128 * mnt_context_set_cache(cxt, NULL);
129 * mnt_context_set_fstype_pattern(cxt, NULL);
130 * mnt_context_set_options_pattern(cxt, NULL);
131 * mnt_context_set_target_ns(cxt, NULL);
132 *
133 *
134 * to reset this stuff.
135 *
136 * Returns: 0 on success, negative number in case of error.
137 */
138 int mnt_reset_context(struct libmnt_context *cxt)
139 {
140 int fl;
141
142 if (!cxt)
143 return -EINVAL;
144
145 DBG(CXT, ul_debugobj(cxt, "<---- reset [status=%d] ---->",
146 mnt_context_get_status(cxt)));
147
148 fl = cxt->flags;
149
150 mnt_unref_fs(cxt->fs);
151 mnt_unref_table(cxt->mtab);
152 mnt_unref_table(cxt->utab);
153
154 free(cxt->helper);
155 free(cxt->orig_user);
156
157 cxt->fs = NULL;
158 cxt->mtab = NULL;
159 cxt->utab = NULL;
160 cxt->helper = NULL;
161 cxt->orig_user = NULL;
162 cxt->mountflags = 0;
163 cxt->user_mountflags = 0;
164 cxt->mountdata = NULL;
165 cxt->flags = MNT_FL_DEFAULT;
166
167 /* free additional mounts list */
168 while (!list_empty(&cxt->addmounts)) {
169 struct libmnt_addmount *ad = list_entry(cxt->addmounts.next,
170 struct libmnt_addmount,
171 mounts);
172 mnt_free_addmount(ad);
173 }
174
175 mnt_context_reset_status(cxt);
176
177 if (cxt->table_fltrcb)
178 mnt_context_set_tabfilter(cxt, NULL, NULL);
179
180 /* restore non-resettable flags */
181 cxt->flags |= (fl & MNT_FL_NOMTAB);
182 cxt->flags |= (fl & MNT_FL_FAKE);
183 cxt->flags |= (fl & MNT_FL_SLOPPY);
184 cxt->flags |= (fl & MNT_FL_VERBOSE);
185 cxt->flags |= (fl & MNT_FL_NOHELPERS);
186 cxt->flags |= (fl & MNT_FL_LOOPDEL);
187 cxt->flags |= (fl & MNT_FL_LAZY);
188 cxt->flags |= (fl & MNT_FL_FORK);
189 cxt->flags |= (fl & MNT_FL_FORCE);
190 cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
191 cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
192 cxt->flags |= (fl & MNT_FL_RWONLY_MOUNT);
193 cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
194 cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
195
196 mnt_context_apply_template(cxt);
197
198 return 0;
199 }
200
201 /*
202 * Saves the current context FS setting (mount options, etc) to make it usable after
203 * mnt_reset_context() or by mnt_context_apply_template(). This is usable for
204 * example for mnt_context_next_mount() where for the next mount operation we
205 * need to restore to the original context setting.
206 *
207 * Returns: 0 on success, negative number in case of error.
208 */
209 int mnt_context_save_template(struct libmnt_context *cxt)
210 {
211 struct libmnt_fs *fs = NULL;
212
213 if (!cxt)
214 return -EINVAL;
215
216 DBG(CXT, ul_debugobj(cxt, "save FS as template"));
217
218 if (cxt->fs) {
219 fs = mnt_copy_fs(NULL, cxt->fs);
220 if (!fs)
221 return -ENOMEM;
222 }
223
224 mnt_unref_fs(cxt->fs_template);
225 cxt->fs_template = fs;
226
227 return 0;
228 }
229
230 /*
231 * Restores context FS setting from previously saved template (see
232 * mnt_context_save_template()).
233 *
234 * Returns: 0 on success, negative number in case of error.
235 */
236 int mnt_context_apply_template(struct libmnt_context *cxt)
237 {
238 struct libmnt_fs *fs = NULL;
239 int rc = 0;
240
241 if (!cxt)
242 return -EINVAL;
243
244 if (cxt->fs_template) {
245 DBG(CXT, ul_debugobj(cxt, "copy FS from template"));
246 fs = mnt_copy_fs(NULL, cxt->fs_template);
247 if (!fs)
248 return -ENOMEM;
249 rc = mnt_context_set_fs(cxt, fs);
250 mnt_unref_fs(fs);
251 } else {
252 DBG(CXT, ul_debugobj(cxt, "no FS template, reset only"));
253 mnt_unref_fs(cxt->fs);
254 cxt->fs = NULL;
255 }
256
257 return rc;
258 }
259
260 int mnt_context_has_template(struct libmnt_context *cxt)
261 {
262 return cxt && cxt->fs_template ? 1 : 0;
263 }
264
265 struct libmnt_context *mnt_copy_context(struct libmnt_context *o)
266 {
267 struct libmnt_context *n;
268
269 n = mnt_new_context();
270 if (!n)
271 return NULL;
272
273 DBG(CXT, ul_debugobj(n, "<---- clone ---->"));
274
275 n->flags = o->flags;
276
277 if (o->fs) {
278 n->fs = mnt_copy_fs(NULL, o->fs);
279 if (!n->fs)
280 goto failed;
281 }
282
283 n->mtab = o->mtab;
284 mnt_ref_table(n->mtab);
285
286 n->mtab = o->utab;
287 mnt_ref_table(n->utab);
288
289 if (strdup_between_structs(n, o, tgt_prefix))
290 goto failed;
291 if (strdup_between_structs(n, o, helper))
292 goto failed;
293 if (strdup_between_structs(n, o, orig_user))
294 goto failed;
295
296 n->mountflags = o->mountflags;
297 n->mountdata = o->mountdata;
298
299 mnt_context_reset_status(n);
300
301 n->table_fltrcb = o->table_fltrcb;
302 n->table_fltrcb_data = o->table_fltrcb_data;
303
304 return n;
305 failed:
306 mnt_free_context(n);
307 return NULL;
308 }
309
310 /**
311 * mnt_context_reset_status:
312 * @cxt: context
313 *
314 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
315 * mnt_context_do_umount() could be again called with the same settings.
316 *
317 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
318 * options, evaluate permissions or apply stuff from fstab.
319 *
320 * Returns: 0 on success, negative number in case of error.
321 */
322 int mnt_context_reset_status(struct libmnt_context *cxt)
323 {
324 if (!cxt)
325 return -EINVAL;
326
327 cxt->syscall_status = 1; /* means not called yet */
328 cxt->helper_exec_status = 1;
329 cxt->helper_status = 0;
330 return 0;
331 }
332
333 static int context_init_paths(struct libmnt_context *cxt, int writable)
334 {
335 struct libmnt_ns *ns_old;
336
337 assert(cxt);
338
339 #ifdef USE_LIBMOUNT_SUPPORT_MTAB
340 if (!cxt->mtab_path) {
341 cxt->mtab_path = mnt_get_mtab_path();
342 DBG(CXT, ul_debugobj(cxt, "mtab path initialized to: %s", cxt->mtab_path));
343 }
344 #endif
345 if (!cxt->utab_path) {
346 cxt->utab_path = mnt_get_utab_path();
347 DBG(CXT, ul_debugobj(cxt, "utab path initialized to: %s", cxt->utab_path));
348 }
349
350 if (!writable)
351 return 0; /* only paths wanted */
352 if (mnt_context_is_nomtab(cxt))
353 return 0; /* write mode overridden by mount -n */
354 if (cxt->flags & MNT_FL_TABPATHS_CHECKED)
355 return 0;
356
357 DBG(CXT, ul_debugobj(cxt, "checking for writable tab files"));
358
359 cxt->mtab_writable = 0;
360
361 ns_old = mnt_context_switch_target_ns(cxt);
362 if (!ns_old)
363 return -MNT_ERR_NAMESPACE;
364
365 #ifdef USE_LIBMOUNT_SUPPORT_MTAB
366 mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
367 if (!cxt->mtab_writable)
368 #endif
369 /* use /run/mount/utab if /etc/mtab is useless */
370 mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
371
372 if (!mnt_context_switch_ns(cxt, ns_old))
373 return -MNT_ERR_NAMESPACE;
374
375 cxt->flags |= MNT_FL_TABPATHS_CHECKED;
376 return 0;
377 }
378
379 int mnt_context_mtab_writable(struct libmnt_context *cxt)
380 {
381 assert(cxt);
382
383 context_init_paths(cxt, 1);
384 return cxt->mtab_writable == 1;
385 }
386
387 int mnt_context_utab_writable(struct libmnt_context *cxt)
388 {
389 assert(cxt);
390
391 context_init_paths(cxt, 1);
392 return cxt->utab_writable == 1;
393 }
394
395 const char *mnt_context_get_writable_tabpath(struct libmnt_context *cxt)
396 {
397 assert(cxt);
398
399 context_init_paths(cxt, 1);
400 return cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path;
401 }
402
403
404 static int set_flag(struct libmnt_context *cxt, int flag, int enable)
405 {
406 if (!cxt)
407 return -EINVAL;
408 if (enable) {
409 DBG(CXT, ul_debugobj(cxt, "enabling flag %04x", flag));
410 cxt->flags |= flag;
411 } else {
412 DBG(CXT, ul_debugobj(cxt, "disabling flag %04x", flag));
413 cxt->flags &= ~flag;
414 }
415 return 0;
416 }
417
418 /**
419 * mnt_context_is_restricted:
420 * @cxt: mount context
421 *
422 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
423 */
424 int mnt_context_is_restricted(struct libmnt_context *cxt)
425 {
426 return cxt->restricted;
427 }
428
429 /**
430 * mnt_context_force_unrestricted:
431 * @cxt: mount context
432 *
433 * This function is DANGEROURS as it disables all security policies in libmount.
434 * Don't use if not sure. It removes "restricted" flag from the context, so
435 * libmount will use the current context as for root user.
436 *
437 * This function is designed for case you have no any suid permissions, so you
438 * can depend on kernel.
439 *
440 * Returns: 0 on success, negative number in case of error.
441 *
442 * Since: 2.35
443 */
444 int mnt_context_force_unrestricted(struct libmnt_context *cxt)
445 {
446 if (mnt_context_is_restricted(cxt)) {
447 DBG(CXT, ul_debugobj(cxt, "force UNRESTRICTED"));
448 cxt->restricted = 0;
449 }
450
451 return 0;
452 }
453
454 /**
455 * mnt_context_set_optsmode
456 * @cxt: mount context
457 * @mode: MNT_OMODE_* flags
458 *
459 * Controls how to use mount optionssource and target paths from fstab/mtab.
460 *
461 * @MNT_OMODE_IGNORE: ignore mtab/fstab options
462 *
463 * @MNT_OMODE_APPEND: append mtab/fstab options to existing options
464 *
465 * @MNT_OMODE_PREPEND: prepend mtab/fstab options to existing options
466 *
467 * @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
468 *
469 * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
470 *
471 * @MNT_OMODE_FSTAB: read from fstab
472 *
473 * @MNT_OMODE_MTAB: read from mtab if fstab not enabled or failed
474 *
475 * @MNT_OMODE_NOTAB: do not read fstab/mtab at all
476 *
477 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
478 *
479 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
480 *
481 * Notes:
482 *
483 * - MNT_OMODE_USER is always used if mount context is in restricted mode
484 * - MNT_OMODE_AUTO is used if nothing else is defined
485 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
486 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
487 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
488 *
489 * Returns: 0 on success, negative number in case of error.
490 */
491 int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
492 {
493 if (!cxt)
494 return -EINVAL;
495 cxt->optsmode = mode;
496 return 0;
497 }
498
499 /**
500 * mnt_context_get_optsmode
501 * @cxt: mount context
502 *
503 * Returns: MNT_OMODE_* mask or zero.
504 */
505
506 int mnt_context_get_optsmode(struct libmnt_context *cxt)
507 {
508 return cxt->optsmode;
509 }
510
511 /**
512 * mnt_context_disable_canonicalize:
513 * @cxt: mount context
514 * @disable: TRUE or FALSE
515 *
516 * Enable/disable paths canonicalization and tags evaluation. The libmount context
517 * canonicalizes paths when searching in fstab and when preparing source and target paths
518 * for mount(2) syscall.
519 *
520 * This function has an effect on the private (within context) fstab instance only
521 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
522 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
523 * NULL).
524 *
525 * Returns: 0 on success, negative number in case of error.
526 */
527 int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
528 {
529 return set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
530 }
531
532 /**
533 * mnt_context_is_nocanonicalize:
534 * @cxt: mount context
535 *
536 * Returns: 1 if no-canonicalize mode is enabled or 0.
537 */
538 int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
539 {
540 return cxt->flags & MNT_FL_NOCANONICALIZE ? 1 : 0;
541 }
542
543 /**
544 * mnt_context_enable_lazy:
545 * @cxt: mount context
546 * @enable: TRUE or FALSE
547 *
548 * Enable/disable lazy umount (see umount(8) man page, option -l).
549 *
550 * Returns: 0 on success, negative number in case of error.
551 */
552 int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
553 {
554 return set_flag(cxt, MNT_FL_LAZY, enable);
555 }
556
557 /**
558 * mnt_context_is_lazy:
559 * @cxt: mount context
560 *
561 * Returns: 1 if lazy umount is enabled or 0
562 */
563 int mnt_context_is_lazy(struct libmnt_context *cxt)
564 {
565 return cxt->flags & MNT_FL_LAZY ? 1 : 0;
566 }
567
568 /**
569 * mnt_context_enable_fork:
570 * @cxt: mount context
571 * @enable: TRUE or FALSE
572 *
573 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
574 * page, option -F).
575 *
576 * Returns: 0 on success, negative number in case of error.
577 */
578 int mnt_context_enable_fork(struct libmnt_context *cxt, int enable)
579 {
580 return set_flag(cxt, MNT_FL_FORK, enable);
581 }
582
583 /**
584 * mnt_context_is_fork:
585 * @cxt: mount context
586 *
587 * Returns: 1 if fork (mount -F) is enabled or 0
588 */
589 int mnt_context_is_fork(struct libmnt_context *cxt)
590 {
591 return cxt->flags & MNT_FL_FORK ? 1 : 0;
592 }
593
594 /**
595 * mnt_context_is_parent:
596 * @cxt: mount context
597 *
598 * Return: 1 if mount -F enabled and the current context is parent, or 0
599 */
600 int mnt_context_is_parent(struct libmnt_context *cxt)
601 {
602 return mnt_context_is_fork(cxt) && cxt->pid == 0;
603 }
604
605 /**
606 * mnt_context_is_child:
607 * @cxt: mount context
608 *
609 * Return: 1 f the current context is child, or 0
610 */
611 int mnt_context_is_child(struct libmnt_context *cxt)
612 {
613 /* See mnt_fork_context(), the for fork flag is always disabled
614 * for children to avoid recursive forking.
615 */
616 return !mnt_context_is_fork(cxt) && cxt->pid;
617 }
618
619 /**
620 * mnt_context_enable_rdonly_umount:
621 * @cxt: mount context
622 * @enable: TRUE or FALSE
623 *
624 * Enable/disable read-only remount on failed umount(2)
625 * (see umount(8) man page, option -r).
626 *
627 * Returns: 0 on success, negative number in case of error.
628 */
629 int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
630 {
631 return set_flag(cxt, MNT_FL_RDONLY_UMOUNT, enable);
632 }
633
634 /**
635 * mnt_context_is_rdonly_umount
636 * @cxt: mount context
637 *
638 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
639 * option -r.
640 *
641 * Returns: 1 if read-only remount failed umount(2) is enables or 0
642 */
643 int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
644 {
645 return cxt->flags & MNT_FL_RDONLY_UMOUNT ? 1 : 0;
646 }
647
648 /**
649 * mnt_context_enable_rwonly_mount:
650 * @cxt: mount context
651 * @enable: TRUE or FALSE
652 *
653 * Force read-write mount; if enabled libmount will never try MS_RDONLY
654 * after failed mount(2) EROFS. (See mount(8) man page, option -w).
655 *
656 * Since: 2.30
657 *
658 * Returns: 0 on success, negative number in case of error.
659 */
660 int mnt_context_enable_rwonly_mount(struct libmnt_context *cxt, int enable)
661 {
662 return set_flag(cxt, MNT_FL_RWONLY_MOUNT, enable);
663 }
664
665 /**
666 * mnt_context_is_rwonly_mount
667 * @cxt: mount context
668 *
669 * See also mnt_context_enable_rwonly_mount() and mount(8) man page,
670 * option -w.
671 *
672 * Since: 2.30
673 *
674 * Returns: 1 if only read-write mount is allowed.
675 */
676 int mnt_context_is_rwonly_mount(struct libmnt_context *cxt)
677 {
678 return cxt->flags & MNT_FL_RWONLY_MOUNT ? 1 : 0;
679 }
680
681 /**
682 * mnt_context_forced_rdonly:
683 * @cxt: mount context
684 *
685 * See also mnt_context_enable_rwonly_mount().
686 *
687 * Since: 2.30
688 *
689 * Returns: 1 if mounted read-only on write-protected device.
690 */
691 int mnt_context_forced_rdonly(struct libmnt_context *cxt)
692 {
693 return cxt->flags & MNT_FL_FORCED_RDONLY ? 1 : 0;
694 }
695
696 /**
697 * mnt_context_disable_helpers:
698 * @cxt: mount context
699 * @disable: TRUE or FALSE
700 *
701 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
702 *
703 * Returns: 0 on success, negative number in case of error.
704 */
705 int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable)
706 {
707 return set_flag(cxt, MNT_FL_NOHELPERS, disable);
708 }
709
710 /**
711 * mnt_context_is_nohelpers
712 * @cxt: mount context
713 *
714 * Returns: 1 if helpers are disabled (mount -i) or 0
715 */
716 int mnt_context_is_nohelpers(struct libmnt_context *cxt)
717 {
718 return cxt->flags & MNT_FL_NOHELPERS ? 1 : 0;
719 }
720
721
722 /**
723 * mnt_context_enable_sloppy:
724 * @cxt: mount context
725 * @enable: TRUE or FALSE
726 *
727 * Set/unset sloppy mounting (see mount(8) man page, option -s).
728 *
729 * Returns: 0 on success, negative number in case of error.
730 */
731 int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable)
732 {
733 return set_flag(cxt, MNT_FL_SLOPPY, enable);
734 }
735
736 /**
737 * mnt_context_is_sloppy:
738 * @cxt: mount context
739 *
740 * Returns: 1 if sloppy flag is enabled or 0
741 */
742 int mnt_context_is_sloppy(struct libmnt_context *cxt)
743 {
744 return cxt->flags & MNT_FL_SLOPPY ? 1 : 0;
745 }
746
747 /**
748 * mnt_context_enable_fake:
749 * @cxt: mount context
750 * @enable: TRUE or FALSE
751 *
752 * Enable/disable fake mounting (see mount(8) man page, option -f).
753 *
754 * Returns: 0 on success, negative number in case of error.
755 */
756 int mnt_context_enable_fake(struct libmnt_context *cxt, int enable)
757 {
758 return set_flag(cxt, MNT_FL_FAKE, enable);
759 }
760
761 /**
762 * mnt_context_is_fake:
763 * @cxt: mount context
764 *
765 * Returns: 1 if fake flag is enabled or 0
766 */
767 int mnt_context_is_fake(struct libmnt_context *cxt)
768 {
769 return cxt->flags & MNT_FL_FAKE ? 1 : 0;
770 }
771
772 /**
773 * mnt_context_disable_mtab:
774 * @cxt: mount context
775 * @disable: TRUE or FALSE
776 *
777 * Disable/enable mtab update (see mount(8) man page, option -n).
778 *
779 * Returns: 0 on success, negative number in case of error.
780 */
781 int mnt_context_disable_mtab(struct libmnt_context *cxt, int disable)
782 {
783 return set_flag(cxt, MNT_FL_NOMTAB, disable);
784 }
785
786 /**
787 * mnt_context_is_nomtab:
788 * @cxt: mount context
789 *
790 * Returns: 1 if no-mtab is enabled or 0
791 */
792 int mnt_context_is_nomtab(struct libmnt_context *cxt)
793 {
794 return cxt->flags & MNT_FL_NOMTAB ? 1 : 0;
795 }
796
797 /**
798 * mnt_context_disable_swapmatch:
799 * @cxt: mount context
800 * @disable: TRUE or FALSE
801 *
802 * Disable/enable swap between source and target for mount(8) if only one path
803 * is specified.
804 *
805 * Returns: 0 on success, negative number in case of error.
806 */
807 int mnt_context_disable_swapmatch(struct libmnt_context *cxt, int disable)
808 {
809 return set_flag(cxt, MNT_FL_NOSWAPMATCH, disable);
810 }
811
812 /**
813 * mnt_context_is_swapmatch:
814 * @cxt: mount context
815 *
816 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
817 */
818 int mnt_context_is_swapmatch(struct libmnt_context *cxt)
819 {
820 return cxt->flags & MNT_FL_NOSWAPMATCH ? 0 : 1;
821 }
822
823 /**
824 * mnt_context_enable_force:
825 * @cxt: mount context
826 * @enable: TRUE or FALSE
827 *
828 * Enable/disable force umounting (see umount(8) man page, option -f).
829 *
830 * Returns: 0 on success, negative number in case of error.
831 */
832 int mnt_context_enable_force(struct libmnt_context *cxt, int enable)
833 {
834 return set_flag(cxt, MNT_FL_FORCE, enable);
835 }
836
837 /**
838 * mnt_context_is_force
839 * @cxt: mount context
840 *
841 * Returns: 1 if force umounting flag is enabled or 0
842 */
843 int mnt_context_is_force(struct libmnt_context *cxt)
844 {
845 return cxt->flags & MNT_FL_FORCE ? 1 : 0;
846 }
847
848 /**
849 * mnt_context_enable_verbose:
850 * @cxt: mount context
851 * @enable: TRUE or FALSE
852 *
853 * Enable/disable verbose output (TODO: not implemented yet)
854 *
855 * Returns: 0 on success, negative number in case of error.
856 */
857 int mnt_context_enable_verbose(struct libmnt_context *cxt, int enable)
858 {
859 return set_flag(cxt, MNT_FL_VERBOSE, enable);
860 }
861
862 /**
863 * mnt_context_is_verbose
864 * @cxt: mount context
865 *
866 * Returns: 1 if verbose flag is enabled or 0
867 */
868 int mnt_context_is_verbose(struct libmnt_context *cxt)
869 {
870 return cxt->flags & MNT_FL_VERBOSE ? 1 : 0;
871 }
872
873 /**
874 * mnt_context_enable_loopdel:
875 * @cxt: mount context
876 * @enable: TRUE or FALSE
877 *
878 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
879 *
880 * Returns: 0 on success, negative number in case of error.
881 */
882 int mnt_context_enable_loopdel(struct libmnt_context *cxt, int enable)
883 {
884 return set_flag(cxt, MNT_FL_LOOPDEL, enable);
885 }
886
887 /**
888 * mnt_context_is_loopdel:
889 * @cxt: mount context
890 *
891 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
892 */
893 int mnt_context_is_loopdel(struct libmnt_context *cxt)
894 {
895 return cxt->flags & MNT_FL_LOOPDEL ? 1 : 0;
896 }
897
898 /**
899 * mnt_context_set_fs:
900 * @cxt: mount context
901 * @fs: filesystem description
902 *
903 * The mount context uses private @fs by default. This function allows to
904 * overwrite the private @fs with an external instance. This function
905 * increments @fs reference counter (and decrement reference counter of the
906 * old fs).
907 *
908 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
909 * functions, If the @fs is NULL, then all current FS specific settings (source,
910 * target, etc., exclude spec) are reset.
911 *
912 * Returns: 0 on success, negative number in case of error.
913 */
914 int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
915 {
916 if (!cxt)
917 return -EINVAL;
918
919 DBG(CXT, ul_debugobj(cxt, "setting new FS"));
920 mnt_ref_fs(fs); /* new */
921 mnt_unref_fs(cxt->fs); /* old */
922 cxt->fs = fs;
923 return 0;
924 }
925
926 /**
927 * mnt_context_get_fs:
928 * @cxt: mount context
929 *
930 * The FS contains the basic description of mountpoint, fs type and so on.
931 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
932 * functions.
933 *
934 * Returns: pointer to FS description or NULL in case of a calloc() error.
935 */
936 struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
937 {
938 if (!cxt)
939 return NULL;
940 if (!cxt->fs)
941 cxt->fs = mnt_new_fs();
942 return cxt->fs;
943 }
944
945 /**
946 * mnt_context_get_fs_userdata:
947 * @cxt: mount context
948 *
949 * Returns: pointer to userdata or NULL.
950 */
951 void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
952 {
953 return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
954 }
955
956 /**
957 * mnt_context_get_fstab_userdata:
958 * @cxt: mount context
959 *
960 * Returns: pointer to userdata or NULL.
961 */
962 void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
963 {
964 return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
965 }
966
967 /**
968 * mnt_context_get_mtab_userdata:
969 * @cxt: mount context
970 *
971 * Returns: pointer to userdata or NULL.
972 */
973 void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
974 {
975 return cxt->mtab ? mnt_table_get_userdata(cxt->mtab) : NULL;
976 }
977
978 /**
979 * mnt_context_set_source:
980 * @cxt: mount context
981 * @source: mount source (device, directory, UUID, LABEL, ...)
982 *
983 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
984 * mount option. The real return code is always returned, when
985 * the device does not exist then it's usually MNT_ERR_NOSOURCE
986 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from mount(2).
987 *
988 * Returns: 0 on success, negative number in case of error.
989 */
990 int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
991 {
992 return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
993 }
994
995 /**
996 * mnt_context_get_source:
997 * @cxt: mount context
998 *
999 * Returns: returns pointer or NULL in case of error or if not set.
1000 */
1001 const char *mnt_context_get_source(struct libmnt_context *cxt)
1002 {
1003 return mnt_fs_get_source(mnt_context_get_fs(cxt));
1004 }
1005
1006 /**
1007 * mnt_context_set_target:
1008 * @cxt: mount context
1009 * @target: mountpoint
1010 *
1011 * Returns: 0 on success, negative number in case of error.
1012 */
1013 int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
1014 {
1015 return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
1016 }
1017
1018 /**
1019 * mnt_context_get_target:
1020 * @cxt: mount context
1021 *
1022 * Returns: returns pointer or NULL in case of error or if not set.
1023 */
1024 const char *mnt_context_get_target(struct libmnt_context *cxt)
1025 {
1026 return mnt_fs_get_target(mnt_context_get_fs(cxt));
1027 }
1028
1029 /**
1030 * mnt_context_set_target_prefix:
1031 * @cxt: mount context
1032 * @path: mountpoint prefix
1033 *
1034 * Returns: 0 on success, negative number in case of error.
1035 */
1036 int mnt_context_set_target_prefix(struct libmnt_context *cxt, const char *path)
1037 {
1038 char *p = NULL;
1039
1040 if (!cxt)
1041 return -EINVAL;
1042 if (path) {
1043 p = strdup(path);
1044 if (!p)
1045 return -ENOMEM;
1046 }
1047 free(cxt->tgt_prefix);
1048 cxt->tgt_prefix = p;
1049
1050 return 0;
1051 }
1052
1053 /**
1054 * mnt_context_get_target_prefix:
1055 * @cxt: mount context
1056 *
1057 * Returns: returns pointer or NULL in case of error or if not set.
1058 */
1059 const char *mnt_context_get_target_prefix(struct libmnt_context *cxt)
1060 {
1061 return cxt ? cxt->tgt_prefix : NULL;
1062 }
1063
1064
1065 /**
1066 * mnt_context_set_fstype:
1067 * @cxt: mount context
1068 * @fstype: filesystem type
1069 *
1070 * Note that the @fstype has to be a FS type. For patterns with
1071 * comma-separated list of filesystems or for the "nofs" notation, use
1072 * mnt_context_set_fstype_pattern().
1073 *
1074 * Returns: 0 on success, negative number in case of error.
1075 */
1076 int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
1077 {
1078 return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
1079 }
1080
1081 /**
1082 * mnt_context_get_fstype:
1083 * @cxt: mount context
1084 *
1085 * Returns: pointer or NULL in case of error or if not set.
1086 */
1087 const char *mnt_context_get_fstype(struct libmnt_context *cxt)
1088 {
1089 return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
1090 }
1091
1092 /**
1093 * mnt_context_set_options:
1094 * @cxt: mount context
1095 * @optstr: comma delimited mount options
1096 *
1097 * Note that that MS_MOVE cannot be specified as "string". It's operation that
1098 * is no supported in fstab (etc.)
1099 *
1100 * Returns: 0 on success, negative number in case of error.
1101 */
1102 int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
1103 {
1104 return mnt_fs_set_options(mnt_context_get_fs(cxt), optstr);
1105 }
1106
1107 /**
1108 * mnt_context_append_options:
1109 * @cxt: mount context
1110 * @optstr: comma delimited mount options
1111 *
1112 * Returns: 0 on success, negative number in case of error.
1113 */
1114 int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
1115 {
1116 return mnt_fs_append_options(mnt_context_get_fs(cxt), optstr);
1117 }
1118
1119 /**
1120 * mnt_context_get_options:
1121 * @cxt: mount context
1122 *
1123 * This function returns mount options set by mnt_context_set_options() or
1124 * mnt_context_append_options().
1125 *
1126 * Note that *after* mnt_context_prepare_mount(), the mount options string
1127 * may also include options set by mnt_context_set_mflags() or other options
1128 * generated by this library.
1129 *
1130 * Returns: pointer or NULL
1131 */
1132 const char *mnt_context_get_options(struct libmnt_context *cxt)
1133 {
1134 return mnt_fs_get_options(mnt_context_get_fs(cxt));
1135 }
1136
1137 /**
1138 * mnt_context_set_fstype_pattern:
1139 * @cxt: mount context
1140 * @pattern: FS name pattern (or NULL to reset the current setting)
1141 *
1142 * See mount(8), option -t.
1143 *
1144 * Returns: 0 on success, negative number in case of error.
1145 */
1146 int mnt_context_set_fstype_pattern(struct libmnt_context *cxt, const char *pattern)
1147 {
1148 char *p = NULL;
1149
1150 if (!cxt)
1151 return -EINVAL;
1152 if (pattern) {
1153 p = strdup(pattern);
1154 if (!p)
1155 return -ENOMEM;
1156 }
1157 free(cxt->fstype_pattern);
1158 cxt->fstype_pattern = p;
1159 return 0;
1160 }
1161
1162 /**
1163 * mnt_context_set_options_pattern:
1164 * @cxt: mount context
1165 * @pattern: options pattern (or NULL to reset the current setting)
1166 *
1167 * See mount(8), option -O.
1168 *
1169 * Returns: 0 on success, negative number in case of error.
1170 */
1171 int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *pattern)
1172 {
1173 char *p = NULL;
1174
1175 if (!cxt)
1176 return -EINVAL;
1177 if (pattern) {
1178 p = strdup(pattern);
1179 if (!p)
1180 return -ENOMEM;
1181 }
1182 free(cxt->optstr_pattern);
1183 cxt->optstr_pattern = p;
1184 return 0;
1185 }
1186
1187 /**
1188 * mnt_context_set_fstab:
1189 * @cxt: mount context
1190 * @tb: fstab
1191 *
1192 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
1193 * This function allows to overwrite the private fstab with an external
1194 * instance.
1195 *
1196 * This function modify the @tb reference counter. This function does not set
1197 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
1198 * mnt_context_get_cache(cxt));
1199 *
1200 * The fstab is used read-only and is not modified, it should be possible to
1201 * share the fstab between more mount contexts (TODO: test it.)
1202 *
1203 * If the @tb argument is NULL, then the current private fstab instance is
1204 * reset.
1205 *
1206 * Returns: 0 on success, negative number in case of error.
1207 */
1208 int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
1209 {
1210 if (!cxt)
1211 return -EINVAL;
1212
1213 mnt_ref_table(tb); /* new */
1214 mnt_unref_table(cxt->fstab); /* old */
1215
1216 cxt->fstab = tb;
1217 return 0;
1218 }
1219
1220 /**
1221 * mnt_context_get_fstab:
1222 * @cxt: mount context
1223 * @tb: returns fstab
1224 *
1225 * See also mnt_table_parse_fstab() for more details about fstab.
1226 *
1227 * Returns: 0 on success, negative number in case of error.
1228 */
1229 int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
1230 {
1231 struct libmnt_ns *ns_old;
1232
1233 if (!cxt)
1234 return -EINVAL;
1235 if (!cxt->fstab) {
1236 int rc;
1237
1238 cxt->fstab = mnt_new_table();
1239 if (!cxt->fstab)
1240 return -ENOMEM;
1241 if (cxt->table_errcb)
1242 mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
1243
1244 ns_old = mnt_context_switch_target_ns(cxt);
1245 if (!ns_old)
1246 return -MNT_ERR_NAMESPACE;
1247
1248 mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
1249 rc = mnt_table_parse_fstab(cxt->fstab, NULL);
1250
1251 if (!mnt_context_switch_ns(cxt, ns_old))
1252 return -MNT_ERR_NAMESPACE;
1253
1254 if (rc)
1255 return rc;
1256 }
1257
1258 if (tb)
1259 *tb = cxt->fstab;
1260 return 0;
1261 }
1262
1263 /**
1264 * mnt_context_get_mtab:
1265 * @cxt: mount context
1266 * @tb: returns mtab
1267 *
1268 * See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
1269 * result will be deallocated by mnt_free_context(@cxt).
1270 *
1271 * Returns: 0 on success, negative number in case of error.
1272 */
1273 int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
1274 {
1275 int rc = 0;
1276 struct libmnt_ns *ns_old = NULL;
1277
1278 if (!cxt)
1279 return -EINVAL;
1280 if (!cxt->mtab) {
1281 ns_old = mnt_context_switch_target_ns(cxt);
1282 if (!ns_old)
1283 return -MNT_ERR_NAMESPACE;
1284
1285 context_init_paths(cxt, 0);
1286
1287 cxt->mtab = mnt_new_table();
1288 if (!cxt->mtab) {
1289 rc = -ENOMEM;
1290 goto end;
1291 }
1292
1293 if (cxt->table_errcb)
1294 mnt_table_set_parser_errcb(cxt->mtab, cxt->table_errcb);
1295 if (cxt->table_fltrcb)
1296 mnt_table_set_parser_fltrcb(cxt->mtab,
1297 cxt->table_fltrcb,
1298 cxt->table_fltrcb_data);
1299
1300 mnt_table_set_cache(cxt->mtab, mnt_context_get_cache(cxt));
1301
1302 /*
1303 * Note that mtab_path is NULL if mtab is useless or unsupported
1304 */
1305 if (cxt->utab)
1306 /* utab already parsed, don't parse it again */
1307 rc = __mnt_table_parse_mtab(cxt->mtab,
1308 cxt->mtab_path, cxt->utab);
1309 else
1310 rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
1311 if (rc)
1312 goto end;
1313 }
1314
1315 if (tb)
1316 *tb = cxt->mtab;
1317
1318 DBG(CXT, ul_debugobj(cxt, "mtab requested [nents=%d]",
1319 mnt_table_get_nents(cxt->mtab)));
1320
1321 end:
1322 if (ns_old && !mnt_context_switch_ns(cxt, ns_old))
1323 return -MNT_ERR_NAMESPACE;
1324
1325 return rc;
1326 }
1327
1328 /*
1329 * Called by mtab parser to filter out entries, non-zero means that
1330 * an entry has to be filtered out.
1331 */
1332 static int mtab_filter(struct libmnt_fs *fs, void *data)
1333 {
1334 if (!fs || !data)
1335 return 0;
1336 if (mnt_fs_streq_target(fs, data))
1337 return 0;
1338 if (mnt_fs_streq_srcpath(fs, data))
1339 return 0;
1340 return 1;
1341 }
1342
1343 /*
1344 * The same like mnt_context_get_mtab(), but does not read all mountinfo/mtab
1345 * file, but only entries relevant for @tgt.
1346 */
1347 int mnt_context_get_mtab_for_target(struct libmnt_context *cxt,
1348 struct libmnt_table **mtab,
1349 const char *tgt)
1350 {
1351 struct stat st;
1352 struct libmnt_cache *cache = NULL;
1353 char *cn_tgt = NULL;
1354 int rc;
1355 struct libmnt_ns *ns_old;
1356
1357 ns_old = mnt_context_switch_target_ns(cxt);
1358 if (!ns_old)
1359 return -MNT_ERR_NAMESPACE;
1360
1361 if (mnt_context_is_nocanonicalize(cxt))
1362 mnt_context_set_tabfilter(cxt, mtab_filter, (void *) tgt);
1363
1364 else if (mnt_stat_mountpoint(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
1365 cache = mnt_context_get_cache(cxt);
1366 cn_tgt = mnt_resolve_path(tgt, cache);
1367 if (cn_tgt)
1368 mnt_context_set_tabfilter(cxt, mtab_filter, cn_tgt);
1369 }
1370
1371 rc = mnt_context_get_mtab(cxt, mtab);
1372 mnt_context_set_tabfilter(cxt, NULL, NULL);
1373
1374 if (!mnt_context_switch_ns(cxt, ns_old))
1375 return -MNT_ERR_NAMESPACE;
1376
1377 if (cn_tgt && !cache)
1378 free(cn_tgt);
1379
1380 return rc;
1381 }
1382
1383 /*
1384 * Allows to specify a filter for tab file entries. The filter is called by
1385 * the table parser. Currently used for mtab and utab only.
1386 */
1387 int mnt_context_set_tabfilter(struct libmnt_context *cxt,
1388 int (*fltr)(struct libmnt_fs *, void *),
1389 void *data)
1390 {
1391 if (!cxt)
1392 return -EINVAL;
1393
1394 cxt->table_fltrcb = fltr;
1395 cxt->table_fltrcb_data = data;
1396
1397 if (cxt->mtab)
1398 mnt_table_set_parser_fltrcb(cxt->mtab,
1399 cxt->table_fltrcb,
1400 cxt->table_fltrcb_data);
1401
1402 DBG(CXT, ul_debugobj(cxt, "tabfilter %s", fltr ? "ENABLED!" : "disabled"));
1403 return 0;
1404 }
1405
1406 /**
1407 * mnt_context_get_table:
1408 * @cxt: mount context
1409 * @filename: e.g. /proc/self/mountinfo
1410 * @tb: returns the table
1411 *
1412 * This function allocates a new table and parses the @file. The parser error
1413 * callback and cache for tags and paths is set according to the @cxt setting.
1414 * See also mnt_table_parse_file().
1415 *
1416 * It's strongly recommended to use the mnt_context_get_mtab() and
1417 * mnt_context_get_fstab() functions for mtab and fstab files. This function
1418 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1419 * options.
1420 *
1421 * The result will NOT be deallocated by mnt_free_context(@cxt).
1422 *
1423 * Returns: 0 on success, negative number in case of error.
1424 */
1425 int mnt_context_get_table(struct libmnt_context *cxt,
1426 const char *filename, struct libmnt_table **tb)
1427 {
1428 int rc;
1429 struct libmnt_ns *ns_old;
1430
1431 if (!cxt || !tb)
1432 return -EINVAL;
1433
1434 *tb = mnt_new_table();
1435 if (!*tb)
1436 return -ENOMEM;
1437
1438 if (cxt->table_errcb)
1439 mnt_table_set_parser_errcb(*tb, cxt->table_errcb);
1440
1441 ns_old = mnt_context_switch_target_ns(cxt);
1442 if (!ns_old)
1443 return -MNT_ERR_NAMESPACE;
1444
1445 rc = mnt_table_parse_file(*tb, filename);
1446
1447 if (rc) {
1448 mnt_unref_table(*tb);
1449 goto end;
1450 }
1451
1452 mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
1453
1454 end:
1455 if (!mnt_context_switch_ns(cxt, ns_old))
1456 return -MNT_ERR_NAMESPACE;
1457
1458 return rc;
1459 }
1460
1461 /**
1462 * mnt_context_set_tables_errcb
1463 * @cxt: mount context
1464 * @cb: pointer to callback function
1465 *
1466 * The error callback is used for all tab files (e.g. mtab, fstab)
1467 * parsed within the context.
1468 *
1469 * See also mnt_context_get_mtab(),
1470 * mnt_context_get_fstab(),
1471 * mnt_table_set_parser_errcb().
1472 *
1473 * Returns: 0 on success, negative number in case of error.
1474 */
1475 int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
1476 int (*cb)(struct libmnt_table *tb, const char *filename, int line))
1477 {
1478 if (!cxt)
1479 return -EINVAL;
1480
1481 if (cxt->mtab)
1482 mnt_table_set_parser_errcb(cxt->mtab, cb);
1483 if (cxt->fstab)
1484 mnt_table_set_parser_errcb(cxt->fstab, cb);
1485
1486 cxt->table_errcb = cb;
1487 return 0;
1488 }
1489
1490 /**
1491 * mnt_context_set_cache:
1492 * @cxt: mount context
1493 * @cache: cache instance or NULL
1494 *
1495 * The mount context maintains a private struct libmnt_cache by default. This
1496 * function allows to overwrite the private cache with an external instance.
1497 * This function increments cache reference counter.
1498 *
1499 * If the @cache argument is NULL, then the current cache instance is reset.
1500 * This function apply the cache to fstab and mtab instances (if already
1501 * exists).
1502 *
1503 * The old cache instance reference counter is de-incremented.
1504 *
1505 * Returns: 0 on success, negative number in case of error.
1506 */
1507 int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache)
1508 {
1509 if (!cxt)
1510 return -EINVAL;
1511
1512 mnt_ref_cache(cache); /* new */
1513 mnt_unref_cache(cxt->cache); /* old */
1514
1515 cxt->cache = cache;
1516
1517 if (cxt->mtab)
1518 mnt_table_set_cache(cxt->mtab, cache);
1519 if (cxt->fstab)
1520 mnt_table_set_cache(cxt->fstab, cache);
1521
1522 return 0;
1523 }
1524
1525 /**
1526 * mnt_context_get_cache
1527 * @cxt: mount context
1528 *
1529 * See also mnt_context_set_cache().
1530 *
1531 * Returns: pointer to cache or NULL if canonicalization is disabled.
1532 */
1533 struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
1534 {
1535 if (!cxt || mnt_context_is_nocanonicalize(cxt))
1536 return NULL;
1537
1538 if (!cxt->cache) {
1539 struct libmnt_cache *cache = mnt_new_cache();
1540 mnt_context_set_cache(cxt, cache);
1541 mnt_unref_cache(cache);
1542 }
1543 return cxt->cache;
1544 }
1545
1546 /**
1547 * mnt_context_set_passwd_cb:
1548 * @cxt: mount context
1549 * @get: callback to get password
1550 * @release: callback to release (deallocate) password
1551 *
1552 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1553 * function is deprecated (encrypted loops are no longer supported).
1554 *
1555 * Returns: 0 on success, negative number in case of error.
1556 */
1557 int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
1558 char *(*get)(struct libmnt_context *),
1559 void (*release)(struct libmnt_context *, char *))
1560 {
1561 if (!cxt)
1562 return -EINVAL;
1563 cxt->pwd_get_cb = get;
1564 cxt->pwd_release_cb = release;
1565 return 0;
1566 }
1567
1568 /**
1569 * mnt_context_get_lock:
1570 * @cxt: mount context
1571 *
1572 * The libmount applications don't have to care about mtab locking, but with a
1573 * small exception: the application has to be able to remove the lock file when
1574 * interrupted by signal or signals have to be ignored when the lock is locked.
1575 *
1576 * The default behavior is to ignore all signals (except SIGALRM and
1577 * SIGTRAP for mtab update) when the lock is locked. If this behavior
1578 * is unacceptable, then use:
1579 *
1580 * lc = mnt_context_get_lock(cxt);
1581 * if (lc)
1582 * mnt_lock_block_signals(lc, FALSE);
1583 *
1584 * and don't forget to call mnt_unlock_file(lc) before exit.
1585 *
1586 * Returns: pointer to lock struct or NULL.
1587 */
1588 struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
1589 {
1590 /*
1591 * DON'T call this function within libmount, it will always allocate
1592 * the lock. The mnt_update_* functions are able to allocate the lock
1593 * only when mtab/utab update is really necessary.
1594 */
1595 if (!cxt || mnt_context_is_nomtab(cxt))
1596 return NULL;
1597
1598 if (!cxt->lock) {
1599 cxt->lock = mnt_new_lock(
1600 mnt_context_get_writable_tabpath(cxt), 0);
1601 if (cxt->lock)
1602 mnt_lock_block_signals(cxt->lock, TRUE);
1603 }
1604 return cxt->lock;
1605 }
1606
1607 /**
1608 * mnt_context_set_mflags:
1609 * @cxt: mount context
1610 * @flags: mount(2) flags (MS_* flags)
1611 *
1612 * Sets mount flags (see mount(2) man page).
1613 *
1614 * Note that mount context allows to define mount options by mount flags. It
1615 * means you can for example use
1616 *
1617 * mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
1618 *
1619 * rather than
1620 *
1621 * mnt_context_set_options(cxt, "noexec,nosuid");
1622 *
1623 * both of these calls have the same effect.
1624 *
1625 * Be careful if you want to use MS_REC flag -- in this case the bit is applied
1626 * to all bind/slave/etc. options. If you want to mix more propadation flags
1627 * and/or bind operations than it's better to specify mount options by
1628 * strings.
1629 *
1630 * Returns: 0 on success, negative number in case of error.
1631 */
1632 int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
1633 {
1634 if (!cxt)
1635 return -EINVAL;
1636
1637 cxt->mountflags = flags;
1638
1639 if ((cxt->flags & MNT_FL_MOUNTOPTS_FIXED) && cxt->fs)
1640 /*
1641 * the final mount options are already generated, refresh...
1642 */
1643 return mnt_optstr_apply_flags(
1644 &cxt->fs->vfs_optstr,
1645 cxt->mountflags,
1646 mnt_get_builtin_optmap(MNT_LINUX_MAP));
1647
1648 return 0;
1649 }
1650
1651 /**
1652 * mnt_context_get_mflags:
1653 * @cxt: mount context
1654 * @flags: returns MS_* mount flags
1655 *
1656 * Converts mount options string to MS_* flags and bitwise-OR the result with
1657 * the already defined flags (see mnt_context_set_mflags()).
1658 *
1659 * Returns: 0 on success, negative number in case of error.
1660 */
1661 int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
1662 {
1663 int rc = 0;
1664 struct list_head *p;
1665
1666 if (!cxt || !flags)
1667 return -EINVAL;
1668
1669 *flags = 0;
1670 if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1671 const char *o = mnt_fs_get_options(cxt->fs);
1672 if (o)
1673 rc = mnt_optstr_get_flags(o, flags,
1674 mnt_get_builtin_optmap(MNT_LINUX_MAP));
1675 }
1676
1677 list_for_each(p, &cxt->addmounts) {
1678 struct libmnt_addmount *ad =
1679 list_entry(p, struct libmnt_addmount, mounts);
1680
1681 *flags |= ad->mountflags;
1682 }
1683
1684 if (!rc)
1685 *flags |= cxt->mountflags;
1686 return rc;
1687 }
1688
1689 /**
1690 * mnt_context_set_user_mflags:
1691 * @cxt: mount context
1692 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1693 *
1694 * Sets userspace mount flags.
1695 *
1696 * See also notes for mnt_context_set_mflags().
1697 *
1698 * Returns: 0 on success, negative number in case of error.
1699 */
1700 int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
1701 {
1702 if (!cxt)
1703 return -EINVAL;
1704 cxt->user_mountflags = flags;
1705 return 0;
1706 }
1707
1708 /**
1709 * mnt_context_get_user_mflags:
1710 * @cxt: mount context
1711 * @flags: returns mount flags
1712 *
1713 * Converts mount options string to MNT_MS_* flags and bitwise-OR the result
1714 * with the already defined flags (see mnt_context_set_user_mflags()).
1715 *
1716 * Returns: 0 on success, negative number in case of error.
1717 */
1718 int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
1719 {
1720 int rc = 0;
1721
1722 if (!cxt || !flags)
1723 return -EINVAL;
1724
1725 *flags = 0;
1726 if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1727 const char *o = mnt_fs_get_user_options(cxt->fs);
1728 if (o)
1729 rc = mnt_optstr_get_flags(o, flags,
1730 mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
1731 }
1732 if (!rc)
1733 *flags |= cxt->user_mountflags;
1734 return rc;
1735 }
1736
1737 /**
1738 * mnt_context_set_mountdata:
1739 * @cxt: mount context
1740 * @data: mount(2) data
1741 *
1742 * The mount context generates mountdata from mount options by default. This
1743 * function allows to overwrite this behavior, and @data will be used instead
1744 * of mount options.
1745 *
1746 * The libmount does not deallocate the data by mnt_free_context(). Note that
1747 * NULL is also valid mount data.
1748 *
1749 * Returns: 0 on success, negative number in case of error.
1750 */
1751 int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
1752 {
1753 if (!cxt)
1754 return -EINVAL;
1755 cxt->mountdata = data;
1756 cxt->flags |= MNT_FL_MOUNTDATA;
1757 return 0;
1758 }
1759
1760 /*
1761 * Translates LABEL/UUID/path to mountable path
1762 */
1763 int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
1764 {
1765 const char *path = NULL;
1766 struct libmnt_cache *cache;
1767 const char *t, *v, *src;
1768 int rc = 0;
1769 struct libmnt_ns *ns_old;
1770
1771 assert(cxt);
1772 assert(cxt->fs);
1773 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1774
1775 DBG(CXT, ul_debugobj(cxt, "preparing source path"));
1776
1777 src = mnt_fs_get_source(cxt->fs);
1778
1779 if (!src && mnt_context_propagation_only(cxt))
1780 /* mount --make-{shared,private,...} */
1781 return mnt_fs_set_source(cxt->fs, "none");
1782
1783 /* ignore filesystems without source or filesystems
1784 * where the source is a quasi-path (//foo/bar)
1785 */
1786 if (!src || mnt_fs_is_netfs(cxt->fs))
1787 return 0;
1788
1789 DBG(CXT, ul_debugobj(cxt, "srcpath '%s'", src));
1790
1791 ns_old = mnt_context_switch_target_ns(cxt);
1792 if (!ns_old)
1793 return -MNT_ERR_NAMESPACE;
1794
1795 cache = mnt_context_get_cache(cxt);
1796
1797 if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
1798 /*
1799 * Source is TAG (evaluate)
1800 */
1801 if (cache)
1802 path = mnt_resolve_tag(t, v, cache);
1803
1804 rc = path ? mnt_fs_set_source(cxt->fs, path) : -MNT_ERR_NOSOURCE;
1805
1806 } else if (cache && !mnt_fs_is_pseudofs(cxt->fs)) {
1807 /*
1808 * Source is PATH (canonicalize)
1809 */
1810 path = mnt_resolve_path(src, cache);
1811 if (path && strcmp(path, src))
1812 rc = mnt_fs_set_source(cxt->fs, path);
1813 }
1814
1815 if (rc) {
1816 DBG(CXT, ul_debugobj(cxt, "failed to prepare srcpath [rc=%d]", rc));
1817 goto end;
1818 }
1819
1820 if (!path)
1821 path = src;
1822
1823 if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_REMOUNT))
1824 || mnt_fs_is_pseudofs(cxt->fs)) {
1825 DBG(CXT, ul_debugobj(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
1826 goto end;
1827 }
1828
1829 /*
1830 * Initialize loop device
1831 */
1832 if (mnt_context_is_loopdev(cxt)) {
1833 rc = mnt_context_setup_loopdev(cxt);
1834 if (rc)
1835 goto end;
1836 }
1837
1838 DBG(CXT, ul_debugobj(cxt, "final srcpath '%s'",
1839 mnt_fs_get_source(cxt->fs)));
1840
1841 end:
1842 if (!mnt_context_switch_ns(cxt, ns_old))
1843 return -MNT_ERR_NAMESPACE;
1844 return rc;
1845 }
1846
1847 /* create a mountpoint if X-mount.mkdir[=<mode>] specified */
1848 static int mkdir_target(const char *tgt, struct libmnt_fs *fs)
1849 {
1850 char *mstr = NULL;
1851 size_t mstr_sz = 0;
1852 mode_t mode = 0;
1853 struct stat st;
1854 int rc;
1855
1856 assert(tgt);
1857 assert(fs);
1858
1859 if (mnt_optstr_get_option(fs->user_optstr, "X-mount.mkdir", &mstr, &mstr_sz) != 0 &&
1860 mnt_optstr_get_option(fs->user_optstr, "x-mount.mkdir", &mstr, &mstr_sz) != 0) /* obsolete */
1861 return 0;
1862
1863 DBG(CXT, ul_debug("mkdir %s (%s) wanted", tgt, mstr));
1864
1865 if (mnt_stat_mountpoint(tgt, &st) == 0)
1866 return 0;
1867
1868 if (mstr && mstr_sz) {
1869 char *end = NULL;
1870
1871 errno = 0;
1872 mode = strtol(mstr, &end, 8);
1873
1874 if (errno || !end || mstr + mstr_sz != end) {
1875 DBG(CXT, ul_debug("failed to parse mkdir mode '%s'", mstr));
1876 return -MNT_ERR_MOUNTOPT;
1877 }
1878 }
1879
1880 if (!mode)
1881 mode = S_IRWXU | /* 0755 */
1882 S_IRGRP | S_IXGRP |
1883 S_IROTH | S_IXOTH;
1884
1885 rc = mkdir_p(tgt, mode);
1886 if (rc)
1887 DBG(CXT, ul_debug("mkdir %s failed: %m", tgt));
1888
1889 return rc;
1890 }
1891
1892 int mnt_context_prepare_target(struct libmnt_context *cxt)
1893 {
1894 const char *tgt, *prefix;
1895 struct libmnt_cache *cache;
1896 int rc = 0;
1897 struct libmnt_ns *ns_old;
1898
1899 assert(cxt);
1900 assert(cxt->fs);
1901 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1902
1903 DBG(CXT, ul_debugobj(cxt, "preparing target path"));
1904
1905 tgt = mnt_fs_get_target(cxt->fs);
1906 if (!tgt)
1907 return 0;
1908
1909 /* apply prefix */
1910 prefix = mnt_context_get_target_prefix(cxt);
1911 if (prefix) {
1912 const char *p = *tgt == '/' ? tgt + 1 : tgt;
1913
1914 if (!*p)
1915 /* target is "/", use "/prefix" */
1916 rc = mnt_fs_set_target(cxt->fs, prefix);
1917 else {
1918 char *path = NULL;
1919
1920 if (asprintf(&path, "%s/%s", prefix, p) <= 0)
1921 rc = -ENOMEM;
1922 else {
1923 rc = mnt_fs_set_target(cxt->fs, path);
1924 free(path);
1925 }
1926 }
1927 if (rc)
1928 return rc;
1929 tgt = mnt_fs_get_target(cxt->fs);
1930 }
1931
1932 ns_old = mnt_context_switch_target_ns(cxt);
1933 if (!ns_old)
1934 return -MNT_ERR_NAMESPACE;
1935
1936 /* mkdir target */
1937 if (cxt->action == MNT_ACT_MOUNT
1938 && !mnt_context_is_restricted(cxt)
1939 && (cxt->user_mountflags & MNT_MS_XCOMMENT ||
1940 cxt->user_mountflags & MNT_MS_XFSTABCOMM)) {
1941
1942 rc = mkdir_target(tgt, cxt->fs);
1943 if (rc) {
1944 if (!mnt_context_switch_ns(cxt, ns_old))
1945 return -MNT_ERR_NAMESPACE;
1946 return rc; /* mkdir or parse error */
1947 }
1948 }
1949
1950 /* canonicalize the path */
1951 cache = mnt_context_get_cache(cxt);
1952 if (cache) {
1953 char *path = mnt_resolve_path(tgt, cache);
1954 if (path && strcmp(path, tgt) != 0)
1955 rc = mnt_fs_set_target(cxt->fs, path);
1956 }
1957
1958 if (!mnt_context_switch_ns(cxt, ns_old))
1959 return -MNT_ERR_NAMESPACE;
1960
1961 if (rc)
1962 DBG(CXT, ul_debugobj(cxt, "failed to prepare target '%s'", tgt));
1963 else
1964 DBG(CXT, ul_debugobj(cxt, "final target '%s'",
1965 mnt_fs_get_target(cxt->fs)));
1966 return 0;
1967 }
1968
1969 /* Guess type, but not set to cxt->fs, always use free() for the result. It's
1970 * no error when we're not able to guess a filesystem type. Note that error
1971 * does not mean that result in @type is NULL.
1972 */
1973 int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type)
1974 {
1975 int rc = 0;
1976 struct libmnt_ns *ns_old;
1977 const char *dev;
1978
1979 assert(type);
1980 assert(cxt);
1981
1982 *type = NULL;
1983
1984 dev = mnt_fs_get_srcpath(cxt->fs);
1985 if (!dev)
1986 return 0;
1987
1988 ns_old = mnt_context_switch_target_ns(cxt);
1989 if (!ns_old)
1990 return -MNT_ERR_NAMESPACE;
1991
1992 if (access(dev, F_OK) == 0) {
1993 struct libmnt_cache *cache = mnt_context_get_cache(cxt);
1994 int ambi = 0;
1995
1996 *type = mnt_get_fstype(dev, &ambi, cache);
1997 if (ambi)
1998 rc = -MNT_ERR_AMBIFS;
1999
2000 if (cache && *type) {
2001 *type = strdup(*type);
2002 if (!*type)
2003 rc = -ENOMEM;
2004 }
2005 } else {
2006 DBG(CXT, ul_debugobj(cxt, "access(%s) failed [%m]", dev));
2007 if (strchr(dev, ':') != NULL) {
2008 *type = strdup("nfs");
2009 if (!*type)
2010 rc = -ENOMEM;
2011 } else if (!strncmp(dev, "//", 2)) {
2012 *type = strdup("cifs");
2013 if (!*type)
2014 rc = -ENOMEM;
2015 }
2016 }
2017
2018 if (!mnt_context_switch_ns(cxt, ns_old))
2019 return -MNT_ERR_NAMESPACE;
2020
2021 return rc;
2022 }
2023
2024 /*
2025 * It's usually no error when we're not able to detect the filesystem type -- we
2026 * will try to use the types from /{etc,proc}/filesystems.
2027 */
2028 int mnt_context_guess_fstype(struct libmnt_context *cxt)
2029 {
2030 char *type;
2031 int rc = 0;
2032
2033 assert(cxt);
2034 assert(cxt->fs);
2035 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
2036
2037 DBG(CXT, ul_debugobj(cxt, "preparing fstype"));
2038
2039 if ((cxt->mountflags & (MS_BIND | MS_MOVE))
2040 || mnt_context_propagation_only(cxt))
2041 goto none;
2042
2043 type = (char *) mnt_fs_get_fstype(cxt->fs);
2044 if (type && !strcmp(type, "auto")) {
2045 mnt_fs_set_fstype(cxt->fs, NULL);
2046 type = NULL;
2047 }
2048
2049 if (type)
2050 goto done;
2051 if (cxt->mountflags & MS_REMOUNT)
2052 goto none;
2053 if (cxt->fstype_pattern)
2054 goto done;
2055
2056 rc = mnt_context_guess_srcpath_fstype(cxt, &type);
2057 if (rc == 0 && type)
2058 __mnt_fs_set_fstype_ptr(cxt->fs, type);
2059 else
2060 free(type);
2061 done:
2062 DBG(CXT, ul_debugobj(cxt, "FS type: %s [rc=%d]",
2063 mnt_fs_get_fstype(cxt->fs), rc));
2064 return rc;
2065 none:
2066 return mnt_fs_set_fstype(cxt->fs, "none");
2067 }
2068
2069 /*
2070 * The default is to use fstype from cxt->fs, this could be overwritten by
2071 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
2072 *
2073 * Returns: 0 on success or negative number in case of error. Note that success
2074 * does not mean that there is any usable helper, you have to check cxt->helper.
2075 */
2076 int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
2077 const char *type)
2078 {
2079 char search_path[] = FS_SEARCH_PATH; /* from config.h */
2080 char *p = NULL, *path;
2081 struct libmnt_ns *ns_old;
2082 int rc = 0;
2083
2084 assert(cxt);
2085 assert(cxt->fs);
2086 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
2087
2088 if (!type)
2089 type = mnt_fs_get_fstype(cxt->fs);
2090
2091 if (type && strchr(type, ','))
2092 return 0; /* type is fstype pattern */
2093
2094 if (mnt_context_is_nohelpers(cxt)
2095 || !type
2096 || !strcmp(type, "none")
2097 || strstr(type, "/..") /* don't try to smuggle path */
2098 || mnt_fs_is_swaparea(cxt->fs))
2099 return 0;
2100
2101 ns_old = mnt_context_switch_origin_ns(cxt);
2102 if (!ns_old)
2103 return -MNT_ERR_NAMESPACE;
2104
2105 /* Ignore errors when search in $PATH and do not modify
2106 * @rc due to stat() etc.
2107 */
2108 path = strtok_r(search_path, ":", &p);
2109 while (path) {
2110 char helper[PATH_MAX];
2111 struct stat st;
2112 int xrc;
2113
2114 xrc = snprintf(helper, sizeof(helper), "%s/%s.%s",
2115 path, name, type);
2116 path = strtok_r(NULL, ":", &p);
2117
2118 if (xrc < 0 || (size_t) xrc >= sizeof(helper))
2119 continue;
2120
2121 xrc = stat(helper, &st);
2122 if (rc == -1 && errno == ENOENT && strchr(type, '.')) {
2123 /* If type ends with ".subtype" try without it */
2124 char *hs = strrchr(helper, '.');
2125 if (hs)
2126 *hs = '\0';
2127 xrc = stat(helper, &st);
2128 }
2129
2130 DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
2131 xrc ? "not found" : "found"));
2132 if (xrc)
2133 continue;
2134
2135 /* success */
2136 rc = strdup_to_struct_member(cxt, helper, helper);
2137 break;
2138 }
2139
2140 if (!mnt_context_switch_ns(cxt, ns_old))
2141 rc = -MNT_ERR_NAMESPACE;
2142
2143 /* make sure helper is not set on error */
2144 if (rc) {
2145 free(cxt->helper);
2146 cxt->helper = NULL;
2147 }
2148 return rc;
2149 }
2150
2151 int mnt_context_merge_mflags(struct libmnt_context *cxt)
2152 {
2153 unsigned long fl = 0;
2154 int rc;
2155
2156 assert(cxt);
2157
2158 DBG(CXT, ul_debugobj(cxt, "merging mount flags"));
2159
2160 rc = mnt_context_get_mflags(cxt, &fl);
2161 if (rc)
2162 return rc;
2163 cxt->mountflags = fl;
2164
2165 fl = 0;
2166 rc = mnt_context_get_user_mflags(cxt, &fl);
2167 if (rc)
2168 return rc;
2169 cxt->user_mountflags = fl;
2170
2171 DBG(CXT, ul_debugobj(cxt, "final flags: VFS=%08lx user=%08lx",
2172 cxt->mountflags, cxt->user_mountflags));
2173
2174 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
2175 return 0;
2176 }
2177
2178 /*
2179 * Prepare /etc/mtab or /run/mount/utab
2180 */
2181 int mnt_context_prepare_update(struct libmnt_context *cxt)
2182 {
2183 int rc;
2184 const char *target;
2185
2186 assert(cxt);
2187 assert(cxt->fs);
2188 assert(cxt->action);
2189 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
2190
2191 DBG(CXT, ul_debugobj(cxt, "prepare update"));
2192
2193 if (mnt_context_propagation_only(cxt)) {
2194 DBG(CXT, ul_debugobj(cxt, "skip update: only MS_PROPAGATION"));
2195 return 0;
2196 }
2197
2198 target = mnt_fs_get_target(cxt->fs);
2199
2200 if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/")) {
2201 DBG(CXT, ul_debugobj(cxt, "root umount: setting NOMTAB"));
2202 mnt_context_disable_mtab(cxt, TRUE);
2203 }
2204 if (mnt_context_is_nomtab(cxt)) {
2205 DBG(CXT, ul_debugobj(cxt, "skip update: NOMTAB flag"));
2206 return 0;
2207 }
2208 if (!mnt_context_get_writable_tabpath(cxt)) {
2209 DBG(CXT, ul_debugobj(cxt, "skip update: no writable destination"));
2210 return 0;
2211 }
2212 /* 0 = success, 1 = not called yet */
2213 if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
2214 DBG(CXT, ul_debugobj(cxt,
2215 "skip update: syscall failed [status=%d]",
2216 cxt->syscall_status));
2217 return 0;
2218 }
2219
2220 if (!cxt->update) {
2221 const char *name = mnt_context_get_writable_tabpath(cxt);
2222
2223 if (cxt->action == MNT_ACT_UMOUNT && is_file_empty(name)) {
2224 DBG(CXT, ul_debugobj(cxt,
2225 "skip update: umount, no table"));
2226 return 0;
2227 }
2228
2229 cxt->update = mnt_new_update();
2230 if (!cxt->update)
2231 return -ENOMEM;
2232
2233 mnt_update_set_filename(cxt->update, name,
2234 !mnt_context_mtab_writable(cxt));
2235 }
2236
2237 if (cxt->action == MNT_ACT_UMOUNT)
2238 rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
2239 mnt_context_get_target(cxt), NULL);
2240 else
2241 rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
2242 NULL, cxt->fs);
2243
2244 return rc < 0 ? rc : 0;
2245 }
2246
2247 int mnt_context_update_tabs(struct libmnt_context *cxt)
2248 {
2249 unsigned long fl;
2250 int rc = 0;
2251 struct libmnt_ns *ns_old;
2252
2253 assert(cxt);
2254
2255 if (mnt_context_is_nomtab(cxt)) {
2256 DBG(CXT, ul_debugobj(cxt, "don't update: NOMTAB flag"));
2257 return 0;
2258 }
2259 if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
2260 DBG(CXT, ul_debugobj(cxt, "don't update: no update prepared"));
2261 return 0;
2262 }
2263
2264 ns_old = mnt_context_switch_target_ns(cxt);
2265 if (!ns_old)
2266 return -MNT_ERR_NAMESPACE;
2267
2268 /* check utab update when external helper executed */
2269 if (mnt_context_helper_executed(cxt)
2270 && mnt_context_get_helper_status(cxt) == 0
2271 && mnt_context_utab_writable(cxt)) {
2272
2273 if (mnt_update_already_done(cxt->update, cxt->lock)) {
2274 DBG(CXT, ul_debugobj(cxt, "don't update: error evaluate or already updated"));
2275 goto end;
2276 }
2277 } else if (cxt->helper) {
2278 DBG(CXT, ul_debugobj(cxt, "don't update: external helper"));
2279 goto end;
2280 }
2281
2282 if (cxt->syscall_status != 0
2283 && !(mnt_context_helper_executed(cxt) &&
2284 mnt_context_get_helper_status(cxt) == 0)) {
2285
2286 DBG(CXT, ul_debugobj(cxt, "don't update: syscall/helper failed/not called"));
2287 goto end;
2288 }
2289
2290 fl = mnt_update_get_mflags(cxt->update);
2291 if ((cxt->mountflags & MS_RDONLY) != (fl & MS_RDONLY))
2292 /*
2293 * fix MS_RDONLY in options
2294 */
2295 mnt_update_force_rdonly(cxt->update,
2296 cxt->mountflags & MS_RDONLY);
2297
2298 rc = mnt_update_table(cxt->update, cxt->lock);
2299
2300 end:
2301 if (!mnt_context_switch_ns(cxt, ns_old))
2302 return -MNT_ERR_NAMESPACE;
2303 return rc;
2304 }
2305
2306 /* apply @fs to @cxt -- use mnt_context_apply_fstab() if not sure
2307 */
2308 int mnt_context_apply_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
2309 {
2310 int rc;
2311
2312 if (!cxt->optsmode) {
2313 if (mnt_context_is_restricted(cxt)) {
2314 DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
2315 cxt->optsmode = MNT_OMODE_USER;
2316 } else {
2317 DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
2318 cxt->optsmode = MNT_OMODE_AUTO;
2319 }
2320 }
2321
2322 DBG(CXT, ul_debugobj(cxt, "apply entry:"));
2323 DBG(CXT, mnt_fs_print_debug(fs, stderr));
2324 DBG(CXT, ul_debugobj(cxt, "OPTSMODE (opt-part): ignore=%d, append=%d, prepend=%d, replace=%d",
2325 cxt->optsmode & MNT_OMODE_IGNORE ? 1 : 0,
2326 cxt->optsmode & MNT_OMODE_APPEND ? 1 : 0,
2327 cxt->optsmode & MNT_OMODE_PREPEND ? 1 : 0,
2328 cxt->optsmode & MNT_OMODE_REPLACE ? 1 : 0));
2329
2330 /* copy from fs to our FS description
2331 */
2332 rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
2333 if (!rc)
2334 rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
2335
2336 if (!rc && !mnt_fs_get_fstype(cxt->fs))
2337 rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
2338
2339 if (!rc && !mnt_fs_get_root(cxt->fs) && mnt_fs_get_root(fs))
2340 rc = mnt_fs_set_root(cxt->fs, mnt_fs_get_root(fs));
2341
2342 if (rc)
2343 goto done;
2344
2345 if (cxt->optsmode & MNT_OMODE_IGNORE)
2346 ;
2347 else if (cxt->optsmode & MNT_OMODE_REPLACE)
2348 rc = mnt_fs_set_options(cxt->fs, mnt_fs_get_options(fs));
2349
2350 else if (cxt->optsmode & MNT_OMODE_APPEND)
2351 rc = mnt_fs_append_options(cxt->fs, mnt_fs_get_options(fs));
2352
2353 else if (cxt->optsmode & MNT_OMODE_PREPEND)
2354 rc = mnt_fs_prepend_options(cxt->fs, mnt_fs_get_options(fs));
2355
2356 if (!rc)
2357 cxt->flags |= MNT_FL_TAB_APPLIED;
2358
2359 done:
2360 DBG(CXT, ul_debugobj(cxt, "final entry [rc=%d]:", rc));
2361 DBG(CXT, mnt_fs_print_debug(cxt->fs, stderr));
2362
2363 return rc;
2364 }
2365
2366 static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
2367 int direction)
2368 {
2369 struct libmnt_fs *fs = NULL;
2370 const char *src, *tgt;
2371
2372 assert(cxt);
2373 assert(cxt->fs);
2374
2375 src = mnt_fs_get_source(cxt->fs);
2376 tgt = mnt_fs_get_target(cxt->fs);
2377
2378 if (tgt && src)
2379 fs = mnt_table_find_pair(tb, src, tgt, direction);
2380 else {
2381 if (src)
2382 fs = mnt_table_find_source(tb, src, direction);
2383 else if (tgt)
2384 fs = mnt_table_find_target(tb, tgt, direction);
2385
2386 if (!fs && mnt_context_is_swapmatch(cxt)) {
2387 /* swap source and target (if @src is not LABEL/UUID),
2388 * for example in
2389 *
2390 * mount /foo/bar
2391 *
2392 * the path could be a mountpoint as well as a source (for
2393 * example bind mount, symlink to a device, ...).
2394 */
2395 if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
2396 fs = mnt_table_find_target(tb, src, direction);
2397 if (!fs && tgt)
2398 fs = mnt_table_find_source(tb, tgt, direction);
2399 }
2400 }
2401
2402 if (!fs)
2403 return -MNT_ERR_NOFSTAB; /* not found */
2404
2405 return mnt_context_apply_fs(cxt, fs);
2406 }
2407
2408 /**
2409 * mnt_context_apply_fstab:
2410 * @cxt: mount context
2411 *
2412 * This function is optional.
2413 *
2414 * Returns: 0 on success, negative number in case of error.
2415 */
2416 int mnt_context_apply_fstab(struct libmnt_context *cxt)
2417 {
2418 int rc = -1, isremount = 0, iscmdbind = 0;
2419 struct libmnt_ns *ns_old;
2420 struct libmnt_table *tab = NULL;
2421 const char *src = NULL, *tgt = NULL;
2422 unsigned long mflags = 0;
2423
2424 if (!cxt || !cxt->fs)
2425 return -EINVAL;
2426
2427 if (mnt_context_tab_applied(cxt)) { /* already applied */
2428 DBG(CXT, ul_debugobj(cxt, "fstab already applied -- skip"));
2429 return 0;
2430 }
2431
2432 if (mnt_context_is_restricted(cxt)) {
2433 DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
2434 cxt->optsmode = MNT_OMODE_USER;
2435 } else if (cxt->optsmode == 0) {
2436 DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
2437 cxt->optsmode = MNT_OMODE_AUTO;
2438 } else if (cxt->optsmode & MNT_OMODE_NOTAB) {
2439 cxt->optsmode &= ~MNT_OMODE_FSTAB;
2440 cxt->optsmode &= ~MNT_OMODE_MTAB;
2441 cxt->optsmode &= ~MNT_OMODE_FORCE;
2442 }
2443
2444 if (mnt_context_get_mflags(cxt, &mflags) == 0) {
2445 isremount = !!(mflags & MS_REMOUNT);
2446 iscmdbind = !!(mflags & MS_BIND);
2447 }
2448
2449 if (cxt->fs) {
2450 src = mnt_fs_get_source(cxt->fs);
2451 tgt = mnt_fs_get_target(cxt->fs);
2452 }
2453
2454 DBG(CXT, ul_debugobj(cxt, "OPTSMODE (file-part): force=%d, fstab=%d, mtab=%d",
2455 cxt->optsmode & MNT_OMODE_FORCE ? 1 : 0,
2456 cxt->optsmode & MNT_OMODE_FSTAB ? 1 : 0,
2457 cxt->optsmode & MNT_OMODE_MTAB ? 1 : 0));
2458
2459 /* fstab is not required if source and target are specified */
2460 if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
2461 DBG(CXT, ul_debugobj(cxt, "fstab not required -- skip"));
2462 return 0;
2463 }
2464
2465 if (!src && tgt
2466 && !(cxt->optsmode & MNT_OMODE_FSTAB)
2467 && !(cxt->optsmode & MNT_OMODE_MTAB)) {
2468 DBG(CXT, ul_debugobj(cxt, "only target; fstab/mtab not required "
2469 "-- skip, probably MS_PROPAGATION"));
2470 return 0;
2471 }
2472
2473 /* let's initialize cxt->fs */
2474 ignore_result( mnt_context_get_fs(cxt) );
2475
2476 ns_old = mnt_context_switch_target_ns(cxt);
2477 if (!ns_old)
2478 return -MNT_ERR_NAMESPACE;
2479
2480 /* try fstab */
2481 if (cxt->optsmode & MNT_OMODE_FSTAB) {
2482 DBG(CXT, ul_debugobj(cxt, "trying to apply fstab (src=%s, target=%s)", src, tgt));
2483 rc = mnt_context_get_fstab(cxt, &tab);
2484 if (!rc)
2485 rc = apply_table(cxt, tab, MNT_ITER_FORWARD);
2486 }
2487
2488 /* try mtab */
2489 if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)
2490 && (isremount || cxt->action == MNT_ACT_UMOUNT)) {
2491 DBG(CXT, ul_debugobj(cxt, "trying to apply mtab (src=%s, target=%s)", src, tgt));
2492 if (tgt)
2493 rc = mnt_context_get_mtab_for_target(cxt, &tab, tgt);
2494 else
2495 rc = mnt_context_get_mtab(cxt, &tab);
2496 if (!rc)
2497 rc = apply_table(cxt, tab, MNT_ITER_BACKWARD);
2498 }
2499
2500 if (!mnt_context_switch_ns(cxt, ns_old))
2501 return -MNT_ERR_NAMESPACE;
2502
2503 if (rc) {
2504 if (!mnt_context_is_restricted(cxt)
2505 && tgt && !src
2506 && isremount) {
2507 DBG(CXT, ul_debugobj(cxt, "only target; ignore missing mtab entry on remount"));
2508 return 0;
2509 }
2510
2511 DBG(CXT, ul_debugobj(cxt, "failed to find entry in fstab/mtab [rc=%d]: %m", rc));
2512
2513 /* force to "not found in fstab/mtab" error, the details why
2514 * not found are not so important and may be misinterpreted by
2515 * applications... */
2516 rc = -MNT_ERR_NOFSTAB;
2517
2518
2519 } else if (isremount && !iscmdbind) {
2520
2521 /* remove "bind" from fstab (or no-op if not present) */
2522 mnt_optstr_remove_option(&cxt->fs->optstr, "bind");
2523 }
2524 return rc;
2525 }
2526
2527 /**
2528 * mnt_context_tab_applied:
2529 * @cxt: mount context
2530 *
2531 * Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
2532 */
2533 int mnt_context_tab_applied(struct libmnt_context *cxt)
2534 {
2535 return cxt->flags & MNT_FL_TAB_APPLIED;
2536 }
2537
2538 /*
2539 * This is not a public function!
2540 *
2541 * Returns 1 if *only propagation flags* change is requested.
2542 */
2543 int mnt_context_propagation_only(struct libmnt_context *cxt)
2544 {
2545 if (cxt->action != MNT_ACT_MOUNT)
2546 return 0;
2547
2548 /* has to be called after context_mount.c: fix_opts() */
2549 assert((cxt->flags & MNT_FL_MOUNTOPTS_FIXED));
2550
2551 /* all propagation mounts are in cxt->addmount */
2552 return !list_empty(&cxt->addmounts)
2553 && (cxt->mountflags == 0 || cxt->mountflags == MS_SILENT)
2554 && cxt->fs
2555 && (!cxt->fs->fstype || strcmp(cxt->fs->fstype, "none") == 0)
2556 && (!cxt->fs->source || strcmp(cxt->fs->source, "none") == 0);
2557 }
2558
2559 /**
2560 * mnt_context_get_status:
2561 * @cxt: mount context
2562 *
2563 * Global libmount status.
2564 *
2565 * The real exit code of the mount.type helper has to be tested by
2566 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2567 * that exec() has been successful.
2568 *
2569 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2570 */
2571 int mnt_context_get_status(struct libmnt_context *cxt)
2572 {
2573 return !cxt->syscall_status || !cxt->helper_exec_status;
2574 }
2575
2576 /**
2577 * mnt_context_helper_executed:
2578 * @cxt: mount context
2579 *
2580 * Returns: 1 if mount.type helper has been executed, or 0.
2581 */
2582 int mnt_context_helper_executed(struct libmnt_context *cxt)
2583 {
2584 return cxt->helper_exec_status != 1;
2585 }
2586
2587 /**
2588 * mnt_context_get_helper_status:
2589 * @cxt: mount context
2590 *
2591 * Return: mount.type helper exit status, result is reliable only if
2592 * mnt_context_helper_executed() returns 1.
2593 */
2594 int mnt_context_get_helper_status(struct libmnt_context *cxt)
2595 {
2596 return cxt->helper_status;
2597 }
2598
2599 /**
2600 * mnt_context_syscall_called:
2601 * @cxt: mount context
2602 *
2603 * Returns: 1 if mount(2) syscall has been called, or 0.
2604 */
2605 int mnt_context_syscall_called(struct libmnt_context *cxt)
2606 {
2607 return cxt->syscall_status != 1;
2608 }
2609
2610 /**
2611 * mnt_context_get_syscall_errno:
2612 * @cxt: mount context
2613 *
2614 * The result from this function is reliable only if
2615 * mnt_context_syscall_called() returns 1.
2616 *
2617 * Returns: mount(2) errno if the syscall failed or 0.
2618 */
2619 int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
2620 {
2621 if (cxt->syscall_status < 0)
2622 return -cxt->syscall_status;
2623 return 0;
2624 }
2625
2626 /**
2627 * mnt_context_set_syscall_status:
2628 * @cxt: mount context
2629 * @status: mount(2) status
2630 *
2631 * The @status should be 0 on success, or negative number on error (-errno).
2632 *
2633 * This function should only be used if the [u]mount(2) syscall is NOT called by
2634 * libmount code.
2635 *
2636 * Returns: 0 or negative number in case of error.
2637 */
2638 int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
2639 {
2640 if (!cxt)
2641 return -EINVAL;
2642
2643 DBG(CXT, ul_debugobj(cxt, "syscall status set to: %d", status));
2644 cxt->syscall_status = status;
2645 return 0;
2646 }
2647
2648 /**
2649 * mnt_context_strerror
2650 * @cxt: context
2651 * @buf: buffer
2652 * @bufsiz: size of the buffer
2653 *
2654 * Not implemented, deprecated in favor or mnt_context_get_excode().
2655 *
2656 * Returns: 0 or negative number in case of error.
2657 */
2658 int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
2659 char *buf __attribute__((__unused__)),
2660 size_t bufsiz __attribute__((__unused__)))
2661 {
2662 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2663 return 0;
2664 }
2665
2666
2667 int mnt_context_get_generic_excode(int rc, char *buf, size_t bufsz, char *fmt, ...)
2668 {
2669 va_list va;
2670
2671 if (rc == 0)
2672 return MNT_EX_SUCCESS;
2673
2674 va_start(va, fmt);
2675
2676 /* we need to support "%m" */
2677 errno = rc < 0 ? -rc : rc;
2678
2679 if (buf)
2680 vsnprintf(buf, bufsz, fmt, va);
2681
2682 switch (errno) {
2683 case EINVAL:
2684 case EPERM:
2685 rc = MNT_EX_USAGE;
2686 break;
2687 case ENOMEM:
2688 rc = MNT_EX_SYSERR;
2689 break;
2690 default:
2691 rc = MNT_EX_FAIL;
2692 break;
2693 }
2694 va_end(va);
2695 return rc;
2696 }
2697
2698 /**
2699 * mnt_context_get_excode:
2700 * @cxt: context
2701 * @rc: return code of the previous operation
2702 * @buf: buffer to print error message (optional)
2703 * @bufsz: size of the buffer
2704 *
2705 * This function analyzes context, [u]mount syscall and external helper status
2706 * and @mntrc and generates unified return code (see MNT_EX_*) as expected
2707 * from mount(8) or umount(8).
2708 *
2709 * If the external helper (e.g. /sbin/mount.type) has been executed than it
2710 * returns status from wait() of the helper. It's not libmount fail if helper
2711 * returns some crazy undocumented codes... See mnt_context_helper_executed()
2712 * and mnt_context_get_helper_status(). Note that mount(8) and umount(8) utils
2713 * always return code from helper without extra care about it.
2714 *
2715 * If the argument @buf is not NULL then error message is generated (if
2716 * anything failed).
2717 *
2718 * The @mntrc is usually return code from mnt_context_mount(),
2719 * mnt_context_umount(), or 'mntrc' as returned by mnt_context_next_mount().
2720 *
2721 * Since: 2.30
2722 *
2723 * Returns: MNT_EX_* codes.
2724 */
2725 int mnt_context_get_excode(
2726 struct libmnt_context *cxt,
2727 int rc,
2728 char *buf,
2729 size_t bufsz)
2730 {
2731 if (buf) {
2732 *buf = '\0'; /* for sure */
2733
2734 if (!cxt->enabled_textdomain) {
2735 bindtextdomain(LIBMOUNT_TEXTDOMAIN, LOCALEDIR);
2736 cxt->enabled_textdomain = 1;
2737 }
2738 }
2739
2740 switch (cxt->action) {
2741 case MNT_ACT_MOUNT:
2742 rc = mnt_context_get_mount_excode(cxt, rc, buf, bufsz);
2743 break;
2744 case MNT_ACT_UMOUNT:
2745 rc = mnt_context_get_umount_excode(cxt, rc, buf, bufsz);
2746 break;
2747 default:
2748 if (rc)
2749 rc = mnt_context_get_generic_excode(rc, buf, bufsz,
2750 _("operation failed: %m"));
2751 else
2752 rc = MNT_EX_SUCCESS;
2753 break;
2754 }
2755
2756 DBG(CXT, ul_debugobj(cxt, "excode: rc=%d message=\"%s\"", rc,
2757 buf ? buf : "<no-message>"));
2758 return rc;
2759 }
2760
2761
2762 /**
2763 * mnt_context_init_helper
2764 * @cxt: mount context
2765 * @action: MNT_ACT_{UMOUNT,MOUNT}
2766 * @flags: not used now
2767 *
2768 * This function informs libmount that used from [u]mount.type helper.
2769 *
2770 * The function also calls mnt_context_disable_helpers() to avoid recursive
2771 * mount.type helpers calling. It you really want to call another
2772 * mount.type helper from your helper, then you have to explicitly enable this
2773 * feature by:
2774 *
2775 * mnt_context_disable_helpers(cxt, FALSE);
2776 *
2777 * Returns: 0 on success, negative number in case of error.
2778 */
2779 int mnt_context_init_helper(struct libmnt_context *cxt, int action,
2780 int flags __attribute__((__unused__)))
2781 {
2782 int rc;
2783
2784 if (!cxt)
2785 return -EINVAL;
2786
2787 rc = mnt_context_disable_helpers(cxt, TRUE);
2788 if (!rc)
2789 rc = set_flag(cxt, MNT_FL_HELPER, 1);
2790 if (!rc)
2791 cxt->action = action;
2792
2793 DBG(CXT, ul_debugobj(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
2794 return rc;
2795 }
2796
2797 /**
2798 * mnt_context_helper_setopt:
2799 * @cxt: context
2800 * @c: getopt() result
2801 * @arg: getopt() optarg
2802 *
2803 * This function applies the [u]mount.type command line option (for example parsed
2804 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2805 * then 1 is returned.
2806 *
2807 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2808 */
2809 int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
2810 {
2811 if (cxt) {
2812 switch(cxt->action) {
2813 case MNT_ACT_MOUNT:
2814 return mnt_context_mount_setopt(cxt, c, arg);
2815 case MNT_ACT_UMOUNT:
2816 return mnt_context_umount_setopt(cxt, c, arg);
2817 }
2818 }
2819 return -EINVAL;
2820 }
2821
2822 /**
2823 * mnt_context_is_fs_mounted:
2824 * @cxt: context
2825 * @fs: filesystem
2826 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2827 *
2828 * Please, read the mnt_table_is_fs_mounted() description!
2829 *
2830 * Returns: 0 on success and negative number in case of error.
2831 */
2832 int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
2833 struct libmnt_fs *fs, int *mounted)
2834 {
2835 struct libmnt_table *mtab, *orig;
2836 int rc;
2837 struct libmnt_ns *ns_old;
2838
2839 if (!cxt || !fs || !mounted)
2840 return -EINVAL;
2841
2842 ns_old = mnt_context_switch_target_ns(cxt);
2843 if (!ns_old)
2844 return -MNT_ERR_NAMESPACE;
2845
2846 orig = cxt->mtab;
2847 rc = mnt_context_get_mtab(cxt, &mtab);
2848 if (rc == -ENOENT && mnt_fs_streq_target(fs, "/proc") &&
2849 (!cxt->mtab_path || startswith(cxt->mtab_path, "/proc/"))) {
2850 if (!orig) {
2851 mnt_unref_table(cxt->mtab);
2852 cxt->mtab = NULL;
2853 }
2854 *mounted = 0;
2855 return 0; /* /proc not mounted */
2856 } else if (rc)
2857 return rc;
2858
2859 *mounted = __mnt_table_is_fs_mounted(mtab, fs,
2860 mnt_context_get_target_prefix(cxt));
2861
2862 if (!mnt_context_switch_ns(cxt, ns_old))
2863 return -MNT_ERR_NAMESPACE;
2864 return 0;
2865 }
2866
2867 static int mnt_context_add_child(struct libmnt_context *cxt, pid_t pid)
2868 {
2869 pid_t *pids;
2870
2871 if (!cxt)
2872 return -EINVAL;
2873
2874 pids = realloc(cxt->children, sizeof(pid_t) * cxt->nchildren + 1);
2875 if (!pids)
2876 return -ENOMEM;
2877
2878 DBG(CXT, ul_debugobj(cxt, "add new child %d", pid));
2879 cxt->children = pids;
2880 cxt->children[cxt->nchildren++] = pid;
2881
2882 return 0;
2883 }
2884
2885 int mnt_fork_context(struct libmnt_context *cxt)
2886 {
2887 int rc = 0;
2888 pid_t pid;
2889
2890 assert(cxt);
2891 if (!mnt_context_is_parent(cxt))
2892 return -EINVAL;
2893
2894 DBG(CXT, ul_debugobj(cxt, "forking context"));
2895
2896 DBG_FLUSH;
2897
2898 pid = fork();
2899
2900 switch (pid) {
2901 case -1: /* error */
2902 DBG(CXT, ul_debugobj(cxt, "fork failed %m"));
2903 return -errno;
2904
2905 case 0: /* child */
2906 cxt->pid = getpid();
2907 mnt_context_enable_fork(cxt, FALSE);
2908 DBG(CXT, ul_debugobj(cxt, "child created"));
2909 break;
2910
2911 default:
2912 rc = mnt_context_add_child(cxt, pid);
2913 break;
2914 }
2915
2916 return rc;
2917 }
2918
2919 int mnt_context_wait_for_children(struct libmnt_context *cxt,
2920 int *nchildren, int *nerrs)
2921 {
2922 int i;
2923
2924 if (!cxt)
2925 return -EINVAL;
2926
2927 assert(mnt_context_is_parent(cxt));
2928
2929 for (i = 0; i < cxt->nchildren; i++) {
2930 pid_t pid = cxt->children[i];
2931 int rc = 0, ret = 0;
2932
2933 if (!pid)
2934 continue;
2935 do {
2936 DBG(CXT, ul_debugobj(cxt,
2937 "waiting for child (%d/%d): %d",
2938 i + 1, cxt->nchildren, pid));
2939 errno = 0;
2940 rc = waitpid(pid, &ret, 0);
2941
2942 } while (rc == -1 && errno == EINTR);
2943
2944 if (nchildren)
2945 (*nchildren)++;
2946
2947 if (rc != -1 && nerrs) {
2948 if (WIFEXITED(ret))
2949 (*nerrs) += WEXITSTATUS(ret) == 0 ? 0 : 1;
2950 else
2951 (*nerrs)++;
2952 }
2953 cxt->children[i] = 0;
2954 }
2955
2956 cxt->nchildren = 0;
2957 free(cxt->children);
2958 cxt->children = NULL;
2959 return 0;
2960 }
2961
2962 static void close_ns(struct libmnt_ns *ns)
2963 {
2964 if (ns->fd == -1)
2965 return;
2966
2967 close(ns->fd);
2968 ns->fd = -1;
2969
2970 mnt_unref_cache(ns->cache);
2971 ns->cache = NULL;
2972 }
2973
2974 /**
2975 * mnt_context_set_target_ns:
2976 * @cxt: mount context
2977 * @path: path to target namespace or NULL
2978 *
2979 * Sets target namespace to namespace represented by @path. If @path is NULL,
2980 * target namespace is cleared.
2981 *
2982 * This function sets errno to ENOSYS and returns error if libmount is
2983 * compiled without namespaces support.
2984 *
2985 * Returns: 0 on success, negative number in case of error.
2986 *
2987 * Since: 2.33
2988 */
2989 int mnt_context_set_target_ns(struct libmnt_context *cxt, const char *path)
2990 {
2991 if (!cxt)
2992 return -EINVAL;
2993
2994 DBG(CXT, ul_debugobj(cxt, "Setting %s as target namespace", path));
2995
2996 /* cleanup only */
2997 if (!path) {
2998 close_ns(&cxt->ns_orig);
2999 close_ns(&cxt->ns_tgt);
3000 return 0;
3001 }
3002
3003 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3004 int errsv = 0;
3005 int tmp;
3006
3007 errno = 0;
3008
3009 /* open original namespace */
3010 if (cxt->ns_orig.fd == -1) {
3011 cxt->ns_orig.fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
3012 if (cxt->ns_orig.fd == -1)
3013 return -errno;
3014 cxt->ns_orig.cache = NULL;
3015 }
3016
3017 /* open target (wanted) namespace */
3018 tmp = open(path, O_RDONLY | O_CLOEXEC);
3019 if (tmp == -1)
3020 return -errno;
3021
3022 /* test whether namespace switching works */
3023 DBG(CXT, ul_debugobj(cxt, "Trying whether namespace is valid"));
3024 if (setns(tmp, CLONE_NEWNS)
3025 || setns(cxt->ns_orig.fd, CLONE_NEWNS)) {
3026 errsv = errno;
3027 DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
3028 goto err;
3029 }
3030
3031 close_ns(&cxt->ns_tgt);
3032
3033 cxt->ns_tgt.fd = tmp;
3034 cxt->ns_tgt.cache = NULL;
3035
3036 return 0;
3037 err:
3038 close(tmp);
3039 errno = errsv;
3040
3041 #else /* ! USE_LIBMOUNT_SUPPORT_NAMESPACES */
3042 errno = ENOSYS;
3043 #endif
3044 return -errno;
3045 }
3046
3047 /**
3048 * mnt_context_get_target_ns:
3049 * @cxt: mount context
3050 *
3051 * Returns: pointer to target namespace
3052 *
3053 * Since: 2.33
3054 */
3055 struct libmnt_ns *mnt_context_get_target_ns(struct libmnt_context *cxt)
3056 {
3057 return &cxt->ns_tgt;
3058 }
3059
3060 /**
3061 * mnt_context_get_origin_ns:
3062 * @cxt: mount context
3063 *
3064 * Returns: pointer to original namespace
3065 *
3066 * Since: 2.33
3067 */
3068 struct libmnt_ns *mnt_context_get_origin_ns(struct libmnt_context *cxt)
3069 {
3070 return &cxt->ns_orig;
3071 }
3072
3073
3074 /**
3075 * mnt_context_switch_ns:
3076 * @cxt: mount context
3077 * @ns: namespace to switch to
3078 *
3079 * Switch to namespace specified by ns
3080 *
3081 * Typical usage:
3082 * <informalexample>
3083 * <programlisting>
3084 * struct libmnt_ns *ns_old;
3085 * ns_old = mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3086 * ... code ...
3087 * mnt_context_switch_ns(cxt, ns_old);
3088 * </programlisting>
3089 * </informalexample>
3090 *
3091 * Returns: pointer to previous namespace or NULL on error
3092 *
3093 * Since: 2.33
3094 */
3095 struct libmnt_ns *mnt_context_switch_ns(struct libmnt_context *cxt, struct libmnt_ns *ns)
3096 {
3097 struct libmnt_ns *old = NULL;
3098
3099 if (!cxt || !ns)
3100 return NULL;
3101
3102 /*
3103 * If mnt_context_set_target_ns() has never been used than @ns file
3104 * descriptor is -1 and this function is noop.
3105 */
3106 old = cxt->ns_cur;
3107 if (ns == old || ns->fd == -1)
3108 return old;
3109
3110 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3111 /* remember the curremt cache */
3112 if (old->cache != cxt->cache) {
3113 mnt_unref_cache(old->cache);
3114 old->cache = cxt->cache;
3115 mnt_ref_cache(old->cache);
3116 }
3117
3118 /* switch */
3119 DBG(CXT, ul_debugobj(cxt, "Switching to %s namespace",
3120 ns == mnt_context_get_target_ns(cxt) ? "target" :
3121 ns == mnt_context_get_origin_ns(cxt) ? "original" : "other"));
3122
3123 if (setns(ns->fd, CLONE_NEWNS)) {
3124 int errsv = errno;
3125
3126 DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
3127 errno = errsv;
3128 return NULL;
3129 }
3130
3131 /* update pointer to the current namespace */
3132 cxt->ns_cur = ns;
3133
3134 /* update pointer to the cache */
3135 mnt_unref_cache(cxt->cache);
3136 cxt->cache = ns->cache;
3137 mnt_ref_cache(cxt->cache);
3138 #endif /* USE_LIBMOUNT_SUPPORT_NAMESPACES */
3139
3140 return old;
3141 }
3142
3143 /**
3144 * mnt_context_switch_origin_ns:
3145 * @cxt: mount context
3146 *
3147 * Switch to original namespace
3148 *
3149 * This is shorthand for
3150 * <informalexample>
3151 * <programlisting>
3152 * mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3153 * </programlisting>
3154 * </informalexample>
3155 *
3156 * Returns: pointer to previous namespace or NULL on error
3157 *
3158 * Since: 2.33
3159 */
3160 struct libmnt_ns *mnt_context_switch_origin_ns(struct libmnt_context *cxt)
3161 {
3162 return mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3163 }
3164
3165 /**
3166 * mnt_context_switch_target_ns:
3167 * @cxt: mount context
3168 *
3169 * Switch to target namespace
3170 *
3171 * This is shorthand for
3172 * <informalexample>
3173 * <programlisting>
3174 * mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3175 * </programlisting>
3176 * </informalexample>
3177 *
3178 * Returns: pointer to previous namespace or NULL on error
3179 *
3180 * Since: 2.33
3181 */
3182 struct libmnt_ns *mnt_context_switch_target_ns(struct libmnt_context *cxt)
3183 {
3184 return mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3185 }
3186
3187
3188 #ifdef TEST_PROGRAM
3189
3190 static int test_search_helper(struct libmnt_test *ts, int argc, char *argv[])
3191 {
3192 struct libmnt_context *cxt;
3193 const char *type;
3194 int rc;
3195
3196 if (argc < 2)
3197 return -EINVAL;
3198
3199 cxt = mnt_new_context();
3200 if (!cxt)
3201 return -ENOMEM;
3202
3203 type = argv[1];
3204
3205 mnt_context_get_fs(cxt); /* just to fill cxt->fs */
3206 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED; /* fake */
3207
3208 rc = mnt_context_prepare_helper(cxt, "mount", type);
3209 printf("helper is: %s\n", cxt->helper ? cxt->helper : "not found");
3210
3211 mnt_free_context(cxt);
3212 return rc;
3213 }
3214
3215
3216 static struct libmnt_lock *lock;
3217
3218 static void lock_fallback(void)
3219 {
3220 if (lock)
3221 mnt_unlock_file(lock);
3222 }
3223
3224 static int test_mount(struct libmnt_test *ts, int argc, char *argv[])
3225 {
3226 int idx = 1, rc = 0;
3227 struct libmnt_context *cxt;
3228
3229 if (argc < 2)
3230 return -EINVAL;
3231
3232 cxt = mnt_new_context();
3233 if (!cxt)
3234 return -ENOMEM;
3235
3236 if (!strcmp(argv[idx], "-o")) {
3237 mnt_context_set_options(cxt, argv[idx + 1]);
3238 idx += 2;
3239 }
3240 if (!strcmp(argv[idx], "-t")) {
3241 /* TODO: use mnt_context_set_fstype_pattern() */
3242 mnt_context_set_fstype(cxt, argv[idx + 1]);
3243 idx += 2;
3244 }
3245
3246 if (argc == idx + 1)
3247 /* mount <mountpoint>|<device> */
3248 mnt_context_set_target(cxt, argv[idx++]);
3249
3250 else if (argc == idx + 2) {
3251 /* mount <device> <mountpoint> */
3252 mnt_context_set_source(cxt, argv[idx++]);
3253 mnt_context_set_target(cxt, argv[idx++]);
3254 }
3255
3256 /* this is unnecessary! -- libmount is able to internally
3257 * create and manage the lock
3258 */
3259 lock = mnt_context_get_lock(cxt);
3260 if (lock)
3261 atexit(lock_fallback);
3262
3263 rc = mnt_context_mount(cxt);
3264 if (rc)
3265 warn("failed to mount");
3266 else
3267 printf("successfully mounted\n");
3268
3269 lock = NULL; /* because we use atexit lock_fallback */
3270 mnt_free_context(cxt);
3271 return rc;
3272 }
3273
3274 static int test_umount(struct libmnt_test *ts, int argc, char *argv[])
3275 {
3276 int idx = 1, rc = 0;
3277 struct libmnt_context *cxt;
3278
3279 if (argc < 2)
3280 return -EINVAL;
3281
3282 cxt = mnt_new_context();
3283 if (!cxt)
3284 return -ENOMEM;
3285
3286 if (!strcmp(argv[idx], "-t")) {
3287 mnt_context_set_fstype(cxt, argv[idx + 1]);
3288 idx += 2;
3289 }
3290
3291 if (!strcmp(argv[idx], "-f")) {
3292 mnt_context_enable_force(cxt, TRUE);
3293 idx++;
3294 }
3295
3296 if (!strcmp(argv[idx], "-l")) {
3297 mnt_context_enable_lazy(cxt, TRUE);
3298 idx++;
3299 }
3300
3301 if (!strcmp(argv[idx], "-r")) {
3302 mnt_context_enable_rdonly_umount(cxt, TRUE);
3303 idx++;
3304 }
3305
3306 if (argc == idx + 1) {
3307 /* mount <mountpoint>|<device> */
3308 mnt_context_set_target(cxt, argv[idx++]);
3309 } else {
3310 rc = -EINVAL;
3311 goto err;
3312 }
3313
3314 lock = mnt_context_get_lock(cxt);
3315 if (lock)
3316 atexit(lock_fallback);
3317
3318 rc = mnt_context_umount(cxt);
3319 if (rc)
3320 printf("failed to umount\n");
3321 else
3322 printf("successfully umounted\n");
3323 err:
3324 lock = NULL; /* because we use atexit lock_fallback */
3325 mnt_free_context(cxt);
3326 return rc;
3327 }
3328
3329 static int test_flags(struct libmnt_test *ts, int argc, char *argv[])
3330 {
3331 int idx = 1, rc = 0;
3332 struct libmnt_context *cxt;
3333 const char *opt = NULL;
3334 unsigned long flags = 0;
3335
3336 if (argc < 2)
3337 return -EINVAL;
3338
3339 cxt = mnt_new_context();
3340 if (!cxt)
3341 return -ENOMEM;
3342
3343 if (!strcmp(argv[idx], "-o")) {
3344 mnt_context_set_options(cxt, argv[idx + 1]);
3345 idx += 2;
3346 }
3347
3348 if (argc == idx + 1)
3349 /* mount <mountpoint>|<device> */
3350 mnt_context_set_target(cxt, argv[idx++]);
3351
3352 rc = mnt_context_prepare_mount(cxt);
3353 if (rc)
3354 printf("failed to prepare mount %s\n", strerror(-rc));
3355
3356 opt = mnt_fs_get_options(cxt->fs);
3357 if (opt)
3358 fprintf(stdout, "options: %s\n", opt);
3359
3360 mnt_context_get_mflags(cxt, &flags);
3361 fprintf(stdout, "flags: %08lx\n", flags);
3362
3363 mnt_free_context(cxt);
3364 return rc;
3365 }
3366
3367 static int test_mountall(struct libmnt_test *ts, int argc, char *argv[])
3368 {
3369 struct libmnt_context *cxt;
3370 struct libmnt_iter *itr;
3371 struct libmnt_fs *fs;
3372 int mntrc, ignored, idx = 1;
3373
3374 cxt = mnt_new_context();
3375 itr = mnt_new_iter(MNT_ITER_FORWARD);
3376
3377 if (!cxt || !itr)
3378 return -ENOMEM;
3379
3380 if (argc > 2) {
3381 if (argv[idx] && !strcmp(argv[idx], "-O")) {
3382 mnt_context_set_options_pattern(cxt, argv[idx + 1]);
3383 idx += 2;
3384 }
3385 if (argv[idx] && !strcmp(argv[idx], "-t")) {
3386 mnt_context_set_fstype_pattern(cxt, argv[idx + 1]);
3387 idx += 2;
3388 }
3389 }
3390
3391 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
3392
3393 const char *tgt = mnt_fs_get_target(fs);
3394
3395 if (ignored == 1)
3396 printf("%s: ignored: not match\n", tgt);
3397 else if (ignored == 2)
3398 printf("%s: ignored: already mounted\n", tgt);
3399
3400 else if (!mnt_context_get_status(cxt)) {
3401 if (mntrc > 0) {
3402 errno = mntrc;
3403 warn("%s: mount failed", tgt);
3404 } else
3405 warnx("%s: mount failed", tgt);
3406 } else
3407 printf("%s: successfully mounted\n", tgt);
3408 }
3409
3410 mnt_free_context(cxt);
3411 return 0;
3412 }
3413
3414 int main(int argc, char *argv[])
3415 {
3416 struct libmnt_test tss[] = {
3417 { "--mount", test_mount, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
3418 { "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
3419 { "--mount-all", test_mountall, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
3420 { "--flags", test_flags, "[-o <opts>] <spec>" },
3421 { "--search-helper", test_search_helper, "<fstype>" },
3422 { NULL }};
3423
3424 umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */
3425
3426 return mnt_run_test(tss, argc, argv);
3427 }
3428
3429 #endif /* TEST_PROGRAM */