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