]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
6db71f4e4777f4b072765893aa40c75cae05a9b7
[thirdparty/util-linux.git] / libmount / src / context.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 /*
3 * This file is part of libmount from util-linux project.
4 *
5 * Copyright (C) 2010-2018 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
11 */
12
13 /**
14 * SECTION: context
15 * @title: Library high-level context
16 * @short_description: high-level API to mount/umount devices.
17 *
18 * <informalexample>
19 * <programlisting>
20 * struct libmnt_context *cxt = mnt_new_context();
21 *
22 * mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
23 * mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
24 * mnt_context_set_target(cxt, "/mnt/foo");
25 *
26 * if (!mnt_context_mount(cxt))
27 * printf("successfully mounted\n");
28 * mnt_free_context(cxt);
29 *
30 * </programlisting>
31 * </informalexample>
32 *
33 * This code is similar to:
34 *
35 * mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
36 *
37 */
38
39 #include "mountP.h"
40 #include "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 if (cxt->fs == fs)
915 return 0;
916
917 DBG(CXT, ul_debugobj(cxt, "setting new FS"));
918
919 /* new */
920 if (fs) {
921 struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
922
923 if (!ol)
924 return -ENOMEM;
925
926 mnt_ref_fs(fs);
927
928 mnt_optlist_set_optstr(ol, mnt_fs_get_options(fs), NULL);
929 mnt_fs_follow_optlist(fs, ol);
930 }
931
932 /* old */
933 if (cxt->fs)
934 mnt_fs_follow_optlist(cxt->fs, NULL);
935 mnt_unref_fs(cxt->fs);
936
937 cxt->fs = fs;
938 return 0;
939 }
940
941 /**
942 * mnt_context_get_fs:
943 * @cxt: mount context
944 *
945 * The FS contains the basic description of mountpoint, fs type and so on.
946 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
947 * functions.
948 *
949 * Returns: pointer to FS description or NULL in case of a calloc() error.
950 */
951 struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
952 {
953 if (!cxt)
954 return NULL;
955 if (!cxt->fs) {
956 struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
957
958 if (!ol)
959 return NULL;
960 cxt->fs = mnt_new_fs();
961 if (!cxt->fs)
962 return NULL;
963
964 mnt_fs_follow_optlist(cxt->fs, ol);
965 }
966 return cxt->fs;
967 }
968
969 /**
970 * mnt_context_get_fs_userdata:
971 * @cxt: mount context
972 *
973 * Returns: pointer to userdata or NULL.
974 */
975 void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
976 {
977 return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
978 }
979
980 /**
981 * mnt_context_get_fstab_userdata:
982 * @cxt: mount context
983 *
984 * Returns: pointer to userdata or NULL.
985 */
986 void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
987 {
988 return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
989 }
990
991 /**
992 * mnt_context_get_mtab_userdata:
993 * @cxt: mount context
994 *
995 * The file /etc/mtab is no more used, @context points always to mountinfo
996 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
997 * compatibility only.
998 *
999 * Returns: pointer to userdata or NULL.
1000 */
1001 void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
1002 {
1003 return cxt->mountinfo ? mnt_table_get_userdata(cxt->mountinfo) : NULL;
1004 }
1005
1006 /**
1007 * mnt_context_set_source:
1008 * @cxt: mount context
1009 * @source: mount source (device, directory, UUID, LABEL, ...)
1010 *
1011 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
1012 * mount option. The real return code is always returned, when
1013 * the device does not exist then it's usually MNT_ERR_NOSOURCE
1014 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from mount(2).
1015 *
1016 * Returns: 0 on success, negative number in case of error.
1017 */
1018 int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
1019 {
1020 return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
1021 }
1022
1023 /**
1024 * mnt_context_get_source:
1025 * @cxt: mount context
1026 *
1027 * Returns: returns pointer or NULL in case of error or if not set.
1028 */
1029 const char *mnt_context_get_source(struct libmnt_context *cxt)
1030 {
1031 return mnt_fs_get_source(mnt_context_get_fs(cxt));
1032 }
1033
1034 /**
1035 * mnt_context_set_target:
1036 * @cxt: mount context
1037 * @target: mountpoint
1038 *
1039 * Returns: 0 on success, negative number in case of error.
1040 */
1041 int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
1042 {
1043 return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
1044 }
1045
1046 /**
1047 * mnt_context_get_target:
1048 * @cxt: mount context
1049 *
1050 * Returns: returns pointer or NULL in case of error or if not set.
1051 */
1052 const char *mnt_context_get_target(struct libmnt_context *cxt)
1053 {
1054 return mnt_fs_get_target(mnt_context_get_fs(cxt));
1055 }
1056
1057 /**
1058 * mnt_context_set_target_prefix:
1059 * @cxt: mount context
1060 * @path: mountpoint prefix
1061 *
1062 * Returns: 0 on success, negative number in case of error.
1063 */
1064 int mnt_context_set_target_prefix(struct libmnt_context *cxt, const char *path)
1065 {
1066 char *p = NULL;
1067
1068 if (!cxt)
1069 return -EINVAL;
1070 if (path) {
1071 p = strdup(path);
1072 if (!p)
1073 return -ENOMEM;
1074 }
1075 free(cxt->tgt_prefix);
1076 cxt->tgt_prefix = p;
1077
1078 return 0;
1079 }
1080
1081 /**
1082 * mnt_context_get_target_prefix:
1083 * @cxt: mount context
1084 *
1085 * Returns: returns pointer or NULL in case of error or if not set.
1086 */
1087 const char *mnt_context_get_target_prefix(struct libmnt_context *cxt)
1088 {
1089 return cxt ? cxt->tgt_prefix : NULL;
1090 }
1091
1092
1093 /**
1094 * mnt_context_set_fstype:
1095 * @cxt: mount context
1096 * @fstype: filesystem type
1097 *
1098 * Note that the @fstype has to be a FS type. For patterns with
1099 * comma-separated list of filesystems or for the "nofs" notation, use
1100 * mnt_context_set_fstype_pattern().
1101 *
1102 * Returns: 0 on success, negative number in case of error.
1103 */
1104 int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
1105 {
1106 return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
1107 }
1108
1109 /**
1110 * mnt_context_get_fstype:
1111 * @cxt: mount context
1112 *
1113 * Returns: pointer or NULL in case of error or if not set.
1114 */
1115 const char *mnt_context_get_fstype(struct libmnt_context *cxt)
1116 {
1117 return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
1118 }
1119
1120 struct libmnt_optlist *mnt_context_get_optlist(struct libmnt_context *cxt)
1121 {
1122 if (!cxt)
1123 return NULL;
1124 if (!cxt->optlist) {
1125 cxt->optlist = mnt_new_optlist();
1126 if (!cxt->optlist)
1127 return NULL;
1128 if (mnt_optlist_register_map(cxt->optlist, cxt->map_linux))
1129 goto fail;
1130 if (mnt_optlist_register_map(cxt->optlist, cxt->map_userspace))
1131 goto fail;
1132 }
1133
1134 return cxt->optlist;
1135 fail:
1136 mnt_unref_optlist(cxt->optlist);
1137 return NULL;
1138 }
1139
1140 /**
1141 * mnt_context_set_options:
1142 * @cxt: mount context
1143 * @optstr: comma delimited mount options
1144 *
1145 * Note that MS_MOVE cannot be specified as "string". It's operation that
1146 * is no supported in fstab (etc.)
1147 *
1148 * Returns: 0 on success, negative number in case of error.
1149 */
1150 int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
1151 {
1152 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1153
1154 if (!ls)
1155 return -ENOMEM;
1156 return mnt_optlist_set_optstr(ls, optstr, NULL);
1157 }
1158
1159 /**
1160 * mnt_context_append_options:
1161 * @cxt: mount context
1162 * @optstr: comma delimited mount options
1163 *
1164 * Returns: 0 on success, negative number in case of error.
1165 */
1166 int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
1167 {
1168 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1169
1170 if (!ls)
1171 return -ENOMEM;
1172 return mnt_optlist_append_optstr(ls, optstr, NULL);
1173 }
1174
1175 /**
1176 * mnt_context_get_options:
1177 * @cxt: mount context
1178 *
1179 * This function returns mount options set by mnt_context_set_options(),
1180 * mnt_context_append_options() or mnt_context_set_mflags();
1181 *
1182 * Before v2.39 this function ignored options specified by flags (see
1183 * mnt_context_set_mflags()) before mnt_context_prepare_mount() call. Now this
1184 * function always returns all mount options.
1185 *
1186 * Returns: pointer or NULL
1187 */
1188 const char *mnt_context_get_options(struct libmnt_context *cxt)
1189 {
1190 const char *str = NULL;
1191
1192 if (cxt->optlist && !mnt_optlist_is_empty(cxt->optlist))
1193 mnt_optlist_get_optstr(cxt->optlist, &str, NULL, 0);
1194 return str;
1195 }
1196
1197 /**
1198 * mnt_context_set_fstype_pattern:
1199 * @cxt: mount context
1200 * @pattern: FS name pattern (or NULL to reset the current setting)
1201 *
1202 * See mount(8), option -t.
1203 *
1204 * Returns: 0 on success, negative number in case of error.
1205 */
1206 int mnt_context_set_fstype_pattern(struct libmnt_context *cxt, const char *pattern)
1207 {
1208 char *p = NULL;
1209
1210 if (!cxt)
1211 return -EINVAL;
1212 if (pattern) {
1213 p = strdup(pattern);
1214 if (!p)
1215 return -ENOMEM;
1216 }
1217 free(cxt->fstype_pattern);
1218 cxt->fstype_pattern = p;
1219 return 0;
1220 }
1221
1222 /**
1223 * mnt_context_set_options_pattern:
1224 * @cxt: mount context
1225 * @pattern: options pattern (or NULL to reset the current setting)
1226 *
1227 * See mount(8), option -O.
1228 *
1229 * Returns: 0 on success, negative number in case of error.
1230 */
1231 int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *pattern)
1232 {
1233 char *p = NULL;
1234
1235 if (!cxt)
1236 return -EINVAL;
1237 if (pattern) {
1238 p = strdup(pattern);
1239 if (!p)
1240 return -ENOMEM;
1241 }
1242 free(cxt->optstr_pattern);
1243 cxt->optstr_pattern = p;
1244 return 0;
1245 }
1246
1247 /**
1248 * mnt_context_set_fstab:
1249 * @cxt: mount context
1250 * @tb: fstab
1251 *
1252 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
1253 * This function can be used to overwrite the private fstab with an external
1254 * instance.
1255 *
1256 * This function modify the @tb reference counter. This function does not set
1257 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
1258 * mnt_context_get_cache(cxt));
1259 *
1260 * The fstab is used read-only and is not modified, it should be possible to
1261 * share the fstab between more mount contexts (TODO: test it.)
1262 *
1263 * If the @tb argument is NULL, then the current private fstab instance is
1264 * reset.
1265 *
1266 * Returns: 0 on success, negative number in case of error.
1267 */
1268 int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
1269 {
1270 if (!cxt)
1271 return -EINVAL;
1272
1273 mnt_ref_table(tb); /* new */
1274 mnt_unref_table(cxt->fstab); /* old */
1275
1276 cxt->fstab = tb;
1277 return 0;
1278 }
1279
1280 /**
1281 * mnt_context_get_fstab:
1282 * @cxt: mount context
1283 * @tb: returns fstab
1284 *
1285 * See also mnt_table_parse_fstab() for more details about fstab.
1286 *
1287 * Returns: 0 on success, negative number in case of error.
1288 */
1289 int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
1290 {
1291 struct libmnt_ns *ns_old;
1292
1293 if (!cxt)
1294 return -EINVAL;
1295 if (!cxt->fstab) {
1296 int rc;
1297
1298 cxt->fstab = mnt_new_table();
1299 if (!cxt->fstab)
1300 return -ENOMEM;
1301 if (cxt->table_errcb)
1302 mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
1303
1304 ns_old = mnt_context_switch_target_ns(cxt);
1305 if (!ns_old)
1306 return -MNT_ERR_NAMESPACE;
1307
1308 mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
1309 rc = mnt_table_parse_fstab(cxt->fstab, NULL);
1310
1311 if (!mnt_context_switch_ns(cxt, ns_old))
1312 return -MNT_ERR_NAMESPACE;
1313
1314 if (rc)
1315 return rc;
1316 }
1317
1318 if (tb)
1319 *tb = cxt->fstab;
1320 return 0;
1321 }
1322
1323 int mnt_context_get_mountinfo(struct libmnt_context *cxt, struct libmnt_table **tb)
1324 {
1325 int rc = 0;
1326 struct libmnt_ns *ns_old = NULL;
1327
1328 if (!cxt)
1329 return -EINVAL;
1330 if (!cxt->mountinfo) {
1331 ns_old = mnt_context_switch_target_ns(cxt);
1332 if (!ns_old)
1333 return -MNT_ERR_NAMESPACE;
1334
1335 context_init_paths(cxt, 0);
1336
1337 cxt->mountinfo = mnt_new_table();
1338 if (!cxt->mountinfo) {
1339 rc = -ENOMEM;
1340 goto end;
1341 }
1342
1343 mnt_table_enable_noautofs(cxt->mountinfo, cxt->noautofs);
1344
1345 if (cxt->table_errcb)
1346 mnt_table_set_parser_errcb(cxt->mountinfo, cxt->table_errcb);
1347 if (cxt->table_fltrcb)
1348 mnt_table_set_parser_fltrcb(cxt->mountinfo,
1349 cxt->table_fltrcb,
1350 cxt->table_fltrcb_data);
1351
1352 mnt_table_set_cache(cxt->mountinfo, mnt_context_get_cache(cxt));
1353 }
1354
1355 /* Read the table; it's empty, because this first mnt_context_get_mountinfo()
1356 * call, or because /proc was not accessible in previous calls */
1357 if (mnt_table_is_empty(cxt->mountinfo)) {
1358 if (!ns_old) {
1359 ns_old = mnt_context_switch_target_ns(cxt);
1360 if (!ns_old)
1361 return -MNT_ERR_NAMESPACE;
1362 }
1363
1364 rc = __mnt_table_parse_mountinfo(cxt->mountinfo, NULL, cxt->utab);
1365 if (rc)
1366 goto end;
1367 }
1368
1369 if (tb)
1370 *tb = cxt->mountinfo;
1371
1372 DBG(CXT, ul_debugobj(cxt, "mountinfo requested [nents=%d]",
1373 mnt_table_get_nents(cxt->mountinfo)));
1374
1375 end:
1376 if (ns_old && !mnt_context_switch_ns(cxt, ns_old))
1377 return -MNT_ERR_NAMESPACE;
1378
1379 return rc;
1380 }
1381
1382 /**
1383 * mnt_context_get_mtab:
1384 * @cxt: mount context
1385 * @tb: returns mtab
1386 *
1387 * Parse /proc/self/mountinfo mount table.
1388 *
1389 * The file /etc/mtab is no more used, @context points always to mountinfo
1390 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
1391 * compatibility only.
1392 *
1393 * See also mnt_table_parse_mtab() for more details about mountinfo. The
1394 * result will be deallocated by mnt_free_context(@cxt).
1395 *
1396 * Returns: 0 on success, negative number in case of error.
1397 */
1398 int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
1399 {
1400 return mnt_context_get_mountinfo(cxt, tb);
1401 }
1402
1403 /*
1404 * Called by mountinfo parser to filter out entries, non-zero means that
1405 * an entry has to be filtered out.
1406 */
1407 static int mountinfo_filter(struct libmnt_fs *fs, void *data)
1408 {
1409 if (!fs || !data)
1410 return 0;
1411 if (mnt_fs_streq_target(fs, data))
1412 return 0;
1413 if (mnt_fs_streq_srcpath(fs, data))
1414 return 0;
1415 return 1;
1416 }
1417
1418 /*
1419 * The same like mnt_context_get_mountinfo(), but does not read all mountinfo
1420 * file, but only entries relevant for @tgt.
1421 */
1422 int mnt_context_get_mountinfo_for_target(struct libmnt_context *cxt,
1423 struct libmnt_table **mountinfo,
1424 const char *tgt)
1425 {
1426 struct stat st;
1427 struct libmnt_cache *cache = NULL;
1428 char *cn_tgt = NULL;
1429 int rc;
1430 struct libmnt_ns *ns_old;
1431
1432 ns_old = mnt_context_switch_target_ns(cxt);
1433 if (!ns_old)
1434 return -MNT_ERR_NAMESPACE;
1435
1436 if (mnt_context_is_nocanonicalize(cxt))
1437 mnt_context_set_tabfilter(cxt, mountinfo_filter, (void *) tgt);
1438
1439 else if (mnt_safe_stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
1440 cache = mnt_context_get_cache(cxt);
1441 cn_tgt = mnt_resolve_path(tgt, cache);
1442 if (cn_tgt)
1443 mnt_context_set_tabfilter(cxt, mountinfo_filter, cn_tgt);
1444 }
1445
1446 rc = mnt_context_get_mountinfo(cxt, mountinfo);
1447 mnt_context_set_tabfilter(cxt, NULL, NULL);
1448
1449 if (!mnt_context_switch_ns(cxt, ns_old))
1450 return -MNT_ERR_NAMESPACE;
1451
1452 if (cn_tgt && !cache)
1453 free(cn_tgt);
1454
1455 return rc;
1456 }
1457
1458 /*
1459 * Allows to specify a filter for tab file entries. The filter is called by
1460 * the table parser. Currently used for utab only.
1461 */
1462 int mnt_context_set_tabfilter(struct libmnt_context *cxt,
1463 int (*fltr)(struct libmnt_fs *, void *),
1464 void *data)
1465 {
1466 if (!cxt)
1467 return -EINVAL;
1468
1469 cxt->table_fltrcb = fltr;
1470 cxt->table_fltrcb_data = data;
1471
1472 if (cxt->mountinfo)
1473 mnt_table_set_parser_fltrcb(cxt->mountinfo,
1474 cxt->table_fltrcb,
1475 cxt->table_fltrcb_data);
1476
1477 DBG(CXT, ul_debugobj(cxt, "tabfilter %s", fltr ? "ENABLED!" : "disabled"));
1478 return 0;
1479 }
1480
1481 /**
1482 * mnt_context_get_table:
1483 * @cxt: mount context
1484 * @filename: e.g. /proc/self/mountinfo
1485 * @tb: returns the table
1486 *
1487 * This function allocates a new table and parses the @file. The parser error
1488 * callback and cache for tags and paths is set according to the @cxt setting.
1489 * See also mnt_table_parse_file().
1490 *
1491 * It's strongly recommended to use the mnt_context_get_mtab() and
1492 * mnt_context_get_fstab() functions for mountinfo and fstab files. This function
1493 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1494 * options.
1495 *
1496 * The result will NOT be deallocated by mnt_free_context(@cxt).
1497 *
1498 * Returns: 0 on success, negative number in case of error.
1499 */
1500 int mnt_context_get_table(struct libmnt_context *cxt,
1501 const char *filename, struct libmnt_table **tb)
1502 {
1503 int rc;
1504 struct libmnt_ns *ns_old;
1505
1506 if (!cxt || !tb)
1507 return -EINVAL;
1508
1509 *tb = mnt_new_table();
1510 if (!*tb)
1511 return -ENOMEM;
1512
1513 if (cxt->table_errcb)
1514 mnt_table_set_parser_errcb(*tb, cxt->table_errcb);
1515
1516 ns_old = mnt_context_switch_target_ns(cxt);
1517 if (!ns_old)
1518 return -MNT_ERR_NAMESPACE;
1519
1520 rc = mnt_table_parse_file(*tb, filename);
1521
1522 if (rc) {
1523 mnt_unref_table(*tb);
1524 goto end;
1525 }
1526
1527 mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
1528
1529 end:
1530 if (!mnt_context_switch_ns(cxt, ns_old))
1531 return -MNT_ERR_NAMESPACE;
1532
1533 return rc;
1534 }
1535
1536 /**
1537 * mnt_context_set_tables_errcb
1538 * @cxt: mount context
1539 * @cb: pointer to callback function
1540 *
1541 * The error callback is used for all tab files (e.g. mountinfo, fstab)
1542 * parsed within the context.
1543 *
1544 * See also mnt_context_get_mtab(),
1545 * mnt_context_get_fstab(),
1546 * mnt_table_set_parser_errcb().
1547 *
1548 * Returns: 0 on success, negative number in case of error.
1549 */
1550 int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
1551 int (*cb)(struct libmnt_table *tb, const char *filename, int line))
1552 {
1553 if (!cxt)
1554 return -EINVAL;
1555
1556 if (cxt->mountinfo)
1557 mnt_table_set_parser_errcb(cxt->mountinfo, cb);
1558 if (cxt->fstab)
1559 mnt_table_set_parser_errcb(cxt->fstab, cb);
1560
1561 cxt->table_errcb = cb;
1562 return 0;
1563 }
1564
1565 /**
1566 * mnt_context_set_cache:
1567 * @cxt: mount context
1568 * @cache: cache instance or NULL
1569 *
1570 * The mount context maintains a private struct libmnt_cache by default. This
1571 * function can be used to overwrite the private cache with an external instance.
1572 * This function increments cache reference counter.
1573 *
1574 * If the @cache argument is NULL, then the current cache instance is reset.
1575 * This function apply the cache to fstab and mountinfo instances (if already
1576 * exists).
1577 *
1578 * The old cache instance reference counter is de-incremented.
1579 *
1580 * Returns: 0 on success, negative number in case of error.
1581 */
1582 int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache)
1583 {
1584 if (!cxt)
1585 return -EINVAL;
1586
1587 mnt_ref_cache(cache); /* new */
1588 mnt_unref_cache(cxt->cache); /* old */
1589
1590 cxt->cache = cache;
1591
1592 if (cxt->mountinfo)
1593 mnt_table_set_cache(cxt->mountinfo, cache);
1594 if (cxt->fstab)
1595 mnt_table_set_cache(cxt->fstab, cache);
1596
1597 return 0;
1598 }
1599
1600 /**
1601 * mnt_context_get_cache
1602 * @cxt: mount context
1603 *
1604 * See also mnt_context_set_cache().
1605 *
1606 * Returns: pointer to cache or NULL if canonicalization is disabled.
1607 */
1608 struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
1609 {
1610 if (!cxt || mnt_context_is_nocanonicalize(cxt))
1611 return NULL;
1612
1613 if (!cxt->cache) {
1614 struct libmnt_cache *cache = mnt_new_cache();
1615 mnt_context_set_cache(cxt, cache);
1616 mnt_unref_cache(cache);
1617 }
1618 return cxt->cache;
1619 }
1620
1621 /**
1622 * mnt_context_set_passwd_cb:
1623 * @cxt: mount context
1624 * @get: callback to get password
1625 * @release: callback to release (deallocate) password
1626 *
1627 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1628 * function is deprecated (encrypted loops are no longer supported).
1629 *
1630 * Returns: 0 on success, negative number in case of error.
1631 */
1632 int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
1633 char *(*get)(struct libmnt_context *),
1634 void (*release)(struct libmnt_context *, char *))
1635 {
1636 if (!cxt)
1637 return -EINVAL;
1638 cxt->pwd_get_cb = get;
1639 cxt->pwd_release_cb = release;
1640 return 0;
1641 }
1642
1643 /**
1644 * mnt_context_get_lock:
1645 * @cxt: mount context
1646 *
1647 * The libmount applications don't have to care about utab locking, but with a
1648 * small exception: the application has to be able to remove the lock file when
1649 * interrupted by signal or signals have to be ignored when the lock is locked.
1650 *
1651 * The default behavior is to ignore all signals (except SIGALRM and
1652 * SIGTRAP for utab update) when the lock is locked. If this behavior
1653 * is unacceptable, then use:
1654 *
1655 * lc = mnt_context_get_lock(cxt);
1656 * if (lc)
1657 * mnt_lock_block_signals(lc, FALSE);
1658 *
1659 * and don't forget to call mnt_unlock_file(lc) before exit.
1660 *
1661 * Returns: pointer to lock struct or NULL.
1662 */
1663 struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
1664 {
1665 /*
1666 * DON'T call this function within libmount, it will always allocate
1667 * the lock. The mnt_update_* functions are able to allocate the lock
1668 * only when utab update is really necessary.
1669 */
1670 if (!cxt || mnt_context_is_nomtab(cxt))
1671 return NULL;
1672
1673 if (!cxt->lock) {
1674 cxt->lock = mnt_new_lock(
1675 mnt_context_get_writable_tabpath(cxt), 0);
1676 if (cxt->lock)
1677 mnt_lock_block_signals(cxt->lock, TRUE);
1678 }
1679 return cxt->lock;
1680 }
1681
1682 /**
1683 * mnt_context_set_mflags:
1684 * @cxt: mount context
1685 * @flags: mount(2) flags (MS_* flags)
1686 *
1687 * Sets mount flags (see mount(2) man page).
1688 *
1689 * Note that order of mount options (strings) and flags matter if you mix
1690 * mnt_context_append_options() and mnt_context_set_mflags().
1691 *
1692 * Be careful if use MS_REC flag -- this is flags is generic for
1693 * all mask. In this case is better to use options string where
1694 * mount options are independent and nothign is applied to all options.
1695 *
1696 * Returns: 0 on success, negative number in case of error.
1697 */
1698 int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
1699 {
1700 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1701
1702 if (!ls)
1703 return -ENOMEM;
1704
1705 return mnt_optlist_set_flags(ls, flags, cxt->map_linux);
1706 }
1707
1708 /**
1709 * mnt_context_get_mflags:
1710 * @cxt: mount context
1711 * @flags: returns MS_* mount flags
1712 *
1713 * Converts mount options string to MS_* flags and bitwise-OR the result with
1714 * the already defined flags (see mnt_context_set_mflags()).
1715 *
1716 * Returns: 0 on success, negative number in case of error.
1717 */
1718 int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
1719 {
1720 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1721
1722 if (!ls)
1723 return -ENOMEM;
1724
1725 return mnt_optlist_get_flags(ls, flags, cxt->map_linux, 0);
1726 }
1727
1728 /**
1729 * mnt_context_set_user_mflags:
1730 * @cxt: mount context
1731 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1732 *
1733 * Sets userspace mount flags.
1734 *
1735 * See also notes for mnt_context_set_mflags().
1736 *
1737 * Returns: 0 on success, negative number in case of error.
1738 */
1739 int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
1740 {
1741 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1742
1743 if (!ls)
1744 return -ENOMEM;
1745
1746 return mnt_optlist_set_flags(ls, flags, cxt->map_userspace);
1747 }
1748
1749 /**
1750 * mnt_context_get_user_mflags:
1751 * @cxt: mount context
1752 * @flags: returns mount flags
1753 *
1754 * Converts mount options string to MNT_MS_* flags and bitwise-OR the result
1755 * with the already defined flags (see mnt_context_set_user_mflags()).
1756 *
1757 * Returns: 0 on success, negative number in case of error.
1758 */
1759 int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
1760 {
1761 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1762
1763 if (!ls)
1764 return -ENOMEM;
1765
1766 return mnt_optlist_get_flags(ls, flags, cxt->map_userspace, 0);
1767 }
1768
1769 /**
1770 * mnt_context_set_mountdata:
1771 * @cxt: mount context
1772 * @data: mount(2) data
1773 *
1774 * The mount context generates mountdata from mount options by default. This
1775 * function can be used to overwrite this behavior, and @data will be used instead
1776 * of mount options.
1777 *
1778 * The libmount does not deallocate the data by mnt_free_context(). Note that
1779 * NULL is also valid mount data.
1780 *
1781 * Returns: 0 on success, negative number in case of error.
1782 */
1783 int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
1784 {
1785 if (!cxt)
1786 return -EINVAL;
1787 cxt->mountdata = data;
1788 cxt->flags |= MNT_FL_MOUNTDATA;
1789 return 0;
1790 }
1791
1792 /*
1793 * Translates LABEL/UUID/path to mountable path
1794 */
1795 int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
1796 {
1797 const char *path = NULL;
1798 struct libmnt_cache *cache;
1799 const char *t, *v, *src, *type;
1800 int rc = 0;
1801 struct libmnt_ns *ns_old;
1802 struct libmnt_optlist *ol;
1803
1804 assert(cxt);
1805 assert(cxt->fs);
1806 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1807
1808 DBG(CXT, ul_debugobj(cxt, "--> preparing source path"));
1809
1810 src = mnt_fs_get_source(cxt->fs);
1811
1812 if (!src && mnt_context_propagation_only(cxt))
1813 /* mount --make-{shared,private,...} */
1814 return mnt_fs_set_source(cxt->fs, "none");
1815
1816 /* ignore filesystems without source or filesystems
1817 * where the source is a quasi-path (//foo/bar)
1818 */
1819 if (!src || mnt_fs_is_netfs(cxt->fs))
1820 return 0;
1821
1822 /* ZFS source is always "dataset", not a real path */
1823 type = mnt_fs_get_fstype(cxt->fs);
1824 if (type && strcmp(type, "zfs") == 0)
1825 return 0;
1826
1827 DBG(CXT, ul_debugobj(cxt, "srcpath '%s'", src));
1828
1829 ns_old = mnt_context_switch_target_ns(cxt);
1830 if (!ns_old)
1831 return -MNT_ERR_NAMESPACE;
1832
1833 cache = mnt_context_get_cache(cxt);
1834
1835 if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
1836 /*
1837 * Source is TAG (evaluate)
1838 */
1839 if (cache)
1840 path = mnt_resolve_tag(t, v, cache);
1841
1842 rc = path ? mnt_fs_set_source(cxt->fs, path) : -MNT_ERR_NOSOURCE;
1843
1844 } else if (cache && !mnt_fs_is_pseudofs(cxt->fs)) {
1845 /*
1846 * Source is PATH (canonicalize)
1847 */
1848 path = mnt_resolve_path(src, cache);
1849 if (path && strcmp(path, src) != 0)
1850 rc = mnt_fs_set_source(cxt->fs, path);
1851 }
1852
1853 if (rc) {
1854 DBG(CXT, ul_debugobj(cxt, "failed to prepare srcpath [rc=%d]", rc));
1855 goto end;
1856 }
1857
1858 if (!path)
1859 path = src;
1860
1861 ol = mnt_context_get_optlist(cxt);
1862 if (!ol)
1863 return -ENOMEM;
1864
1865 if (mnt_optlist_is_bind(ol)
1866 || mnt_optlist_is_move(ol)
1867 || mnt_optlist_is_remount(ol)
1868 || mnt_fs_is_pseudofs(cxt->fs)) {
1869 DBG(CXT, ul_debugobj(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
1870 goto end;
1871 }
1872
1873 rc = mnt_context_call_hooks(cxt, MNT_STAGE_PREP_SOURCE);
1874 if (rc)
1875 goto end;
1876
1877 DBG(CXT, ul_debugobj(cxt, "final srcpath '%s'",
1878 mnt_fs_get_source(cxt->fs)));
1879
1880 end:
1881 if (!mnt_context_switch_ns(cxt, ns_old))
1882 return -MNT_ERR_NAMESPACE;
1883 return rc;
1884 }
1885
1886 /* Guess type, but not set to cxt->fs, always use free() for the result. It's
1887 * no error when we're not able to guess a filesystem type. Note that error
1888 * does not mean that result in @type is NULL.
1889 */
1890 int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type)
1891 {
1892 int rc = 0;
1893 struct libmnt_ns *ns_old;
1894 const char *dev;
1895
1896 assert(type);
1897 assert(cxt);
1898
1899 *type = NULL;
1900
1901 dev = mnt_fs_get_srcpath(cxt->fs);
1902 if (!dev)
1903 return 0;
1904
1905 ns_old = mnt_context_switch_target_ns(cxt);
1906 if (!ns_old)
1907 return -MNT_ERR_NAMESPACE;
1908
1909 if (access(dev, F_OK) == 0) {
1910 struct libmnt_cache *cache = mnt_context_get_cache(cxt);
1911 int ambi = 0;
1912
1913 *type = mnt_get_fstype(dev, &ambi, cache);
1914 if (ambi)
1915 rc = -MNT_ERR_AMBIFS;
1916
1917 if (cache && *type) {
1918 *type = strdup(*type);
1919 if (!*type)
1920 rc = -ENOMEM;
1921 }
1922 } else {
1923 DBG(CXT, ul_debugobj(cxt, "access(%s) failed [%m]", dev));
1924 if (strchr(dev, ':') != NULL) {
1925 *type = strdup("nfs");
1926 if (!*type)
1927 rc = -ENOMEM;
1928 } else if (!strncmp(dev, "//", 2)) {
1929 *type = strdup("cifs");
1930 if (!*type)
1931 rc = -ENOMEM;
1932 }
1933 }
1934
1935 if (!mnt_context_switch_ns(cxt, ns_old))
1936 return -MNT_ERR_NAMESPACE;
1937
1938 if (rc == 0 && *type) {
1939 struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
1940 struct libmnt_opt *opt;
1941 const char *allowed;
1942
1943 if (!ol)
1944 return -ENOMEM;
1945
1946 opt = mnt_optlist_get_named(ol,
1947 "X-mount.auto-fstypes", cxt->map_userspace);
1948
1949 if (opt
1950 && (allowed = mnt_opt_get_value(opt))
1951 && !match_fstype(*type, allowed)) {
1952 DBG(CXT, ul_debugobj(cxt, "%s is not allowed by auto-fstypes=%s",
1953 *type, allowed));
1954 free(*type);
1955 *type = NULL;
1956 rc = -MNT_ERR_NOFSTYPE;
1957 }
1958 }
1959
1960 return rc;
1961 }
1962
1963 /*
1964 * It's usually no error when we're not able to detect the filesystem type -- we
1965 * will try to use the types from /{etc,proc}/filesystems.
1966 */
1967 int mnt_context_guess_fstype(struct libmnt_context *cxt)
1968 {
1969 struct libmnt_optlist *ol;
1970 char *type;
1971 int rc = 0;
1972
1973 assert(cxt);
1974 assert(cxt->fs);
1975 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1976
1977 DBG(CXT, ul_debugobj(cxt, "--> preparing fstype"));
1978
1979 ol = mnt_context_get_optlist(cxt);
1980 if (!ol)
1981 return -ENOMEM;
1982
1983 if (mnt_optlist_is_bind(ol)
1984 || mnt_optlist_is_move(ol)
1985 || mnt_context_propagation_only(cxt))
1986 goto none;
1987
1988 type = (char *) mnt_fs_get_fstype(cxt->fs);
1989 if (type && !strcmp(type, "auto")) {
1990 mnt_fs_set_fstype(cxt->fs, NULL);
1991 type = NULL;
1992 }
1993
1994 if (type)
1995 goto done;
1996 if (mnt_optlist_is_remount(ol))
1997 goto none;
1998 if (cxt->fstype_pattern)
1999 goto done;
2000
2001 rc = mnt_context_guess_srcpath_fstype(cxt, &type);
2002 if (rc == 0 && type)
2003 __mnt_fs_set_fstype_ptr(cxt->fs, type);
2004 else
2005 free(type);
2006 done:
2007 DBG(CXT, ul_debugobj(cxt, "FS type: %s [rc=%d]",
2008 mnt_fs_get_fstype(cxt->fs), rc));
2009 return rc;
2010 none:
2011 return mnt_fs_set_fstype(cxt->fs, "none");
2012 }
2013
2014 /*
2015 * The default is to use fstype from cxt->fs, this could be overwritten by
2016 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
2017 *
2018 * Returns: 0 on success or negative number in case of error. Note that success
2019 * does not mean that there is any usable helper, you have to check cxt->helper.
2020 */
2021 int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
2022 const char *type)
2023 {
2024 char search_path[] = FS_SEARCH_PATH; /* from config.h */
2025 char *p = NULL, *path;
2026 struct libmnt_ns *ns_old;
2027 int rc = 0;
2028
2029 assert(cxt);
2030 assert(cxt->fs);
2031 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
2032
2033 DBG(CXT, ul_debugobj(cxt, "checking for helper"));
2034
2035 if (cxt->helper) {
2036 free(cxt->helper);
2037 cxt->helper = NULL;
2038 }
2039
2040 if (!type)
2041 type = mnt_fs_get_fstype(cxt->fs);
2042
2043 if (type && strchr(type, ','))
2044 return 0; /* type is fstype pattern */
2045
2046 if (mnt_context_is_nohelpers(cxt)
2047 || !type
2048 || !strcmp(type, "none")
2049 || strstr(type, "/..") /* don't try to smuggle path */
2050 || mnt_fs_is_swaparea(cxt->fs))
2051 return 0;
2052
2053 ns_old = mnt_context_switch_origin_ns(cxt);
2054 if (!ns_old)
2055 return -MNT_ERR_NAMESPACE;
2056
2057 /* Ignore errors when search in $PATH and do not modify @rc
2058 */
2059 path = strtok_r(search_path, ":", &p);
2060 while (path) {
2061 char helper[PATH_MAX];
2062 int len, found = 0;
2063
2064 len = snprintf(helper, sizeof(helper), "%s/%s.%s",
2065 path, name, type);
2066 path = strtok_r(NULL, ":", &p);
2067
2068 if (len < 0 || (size_t) len >= sizeof(helper))
2069 continue;
2070
2071 found = mnt_is_path(helper);
2072 if (!found && strchr(type, '.')) {
2073 /* If type ends with ".subtype" try without it */
2074 char *hs = strrchr(helper, '.');
2075 if (hs)
2076 *hs = '\0';
2077 found = mnt_is_path(helper);
2078 }
2079
2080 DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
2081 found ? "found" : "not found"));
2082 if (!found)
2083 continue;
2084
2085 /* success */
2086 rc = strdup_to_struct_member(cxt, helper, helper);
2087 break;
2088 }
2089
2090 if (!mnt_context_switch_ns(cxt, ns_old))
2091 rc = -MNT_ERR_NAMESPACE;
2092
2093 /* make sure helper is not set on error */
2094 if (rc) {
2095 free(cxt->helper);
2096 cxt->helper = NULL;
2097 }
2098 return rc;
2099 }
2100
2101 /* stop differentiate between options defined by flags and strings */
2102 int mnt_context_merge_mflags(struct libmnt_context *cxt)
2103 {
2104 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
2105
2106 if (!ls)
2107 return -ENOMEM;
2108
2109 /* TODO: optlist returns always flags as merged, so
2110 * MNT_FL_MOUNTFLAGS_MERGED is unncessary anymore
2111 */
2112 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
2113 return mnt_optlist_merge_opts(ls);
2114 }
2115
2116 /*
2117 * Prepare /run/mount/utab
2118 */
2119 int mnt_context_prepare_update(struct libmnt_context *cxt)
2120 {
2121 int rc;
2122 const char *target, *name;
2123 unsigned long flags = 0;
2124
2125 assert(cxt);
2126 assert(cxt->fs);
2127 assert(cxt->action);
2128 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
2129
2130 DBG(CXT, ul_debugobj(cxt, "--> prepare update"));
2131
2132 if (mnt_context_propagation_only(cxt)) {
2133 DBG(CXT, ul_debugobj(cxt, "skip update: only MS_PROPAGATION"));
2134 return 0;
2135 }
2136
2137 target = mnt_fs_get_target(cxt->fs);
2138
2139 if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/")) {
2140 DBG(CXT, ul_debugobj(cxt, "root umount: setting NOMTAB"));
2141 mnt_context_disable_mtab(cxt, TRUE);
2142 }
2143 if (mnt_context_is_nomtab(cxt)) {
2144 DBG(CXT, ul_debugobj(cxt, "skip update: NOMTAB flag"));
2145 return 0;
2146 }
2147 name = mnt_context_get_writable_tabpath(cxt);
2148 if (!name) {
2149 DBG(CXT, ul_debugobj(cxt, "skip update: no writable destination"));
2150 return 0;
2151 }
2152 /* 0 = success, 1 = not called yet */
2153 if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
2154 DBG(CXT, ul_debugobj(cxt,
2155 "skip update: syscall failed [status=%d]",
2156 cxt->syscall_status));
2157 return 0;
2158 }
2159
2160 if (!cxt->update) {
2161 if (cxt->action == MNT_ACT_UMOUNT && is_file_empty(name)) {
2162 DBG(CXT, ul_debugobj(cxt, "skip update: umount, no table"));
2163 return 0;
2164 }
2165
2166 cxt->update = mnt_new_update();
2167 if (!cxt->update)
2168 return -ENOMEM;
2169
2170 mnt_update_set_filename(cxt->update, name);
2171 }
2172
2173 mnt_context_get_mflags(cxt, &flags);
2174
2175 if (cxt->action == MNT_ACT_UMOUNT)
2176 rc = mnt_update_set_fs(cxt->update, flags,
2177 mnt_context_get_target(cxt), NULL);
2178 else
2179 rc = mnt_update_set_fs(cxt->update, flags,
2180 NULL, cxt->fs);
2181
2182 return rc < 0 ? rc : 0;
2183 }
2184
2185 int mnt_context_update_tabs(struct libmnt_context *cxt)
2186 {
2187 int rc = 0;
2188 struct libmnt_ns *ns_old;
2189
2190 assert(cxt);
2191
2192 if (mnt_context_is_nomtab(cxt)) {
2193 DBG(CXT, ul_debugobj(cxt, "don't update: NOMTAB flag"));
2194 return 0;
2195 }
2196 if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
2197 DBG(CXT, ul_debugobj(cxt, "don't update: no update prepared"));
2198 return 0;
2199 }
2200
2201 ns_old = mnt_context_switch_target_ns(cxt);
2202 if (!ns_old)
2203 return -MNT_ERR_NAMESPACE;
2204
2205 /* check utab update when external helper executed */
2206 if (mnt_context_helper_executed(cxt)
2207 && mnt_context_get_helper_status(cxt) == 0
2208 && mnt_context_utab_writable(cxt)) {
2209
2210 if (mnt_update_already_done(cxt->update, cxt->lock)) {
2211 DBG(CXT, ul_debugobj(cxt, "don't update: error evaluate or already updated"));
2212 goto end;
2213 }
2214 } else if (cxt->helper) {
2215 DBG(CXT, ul_debugobj(cxt, "don't update: external helper"));
2216 goto end;
2217 }
2218
2219 if (cxt->syscall_status != 0
2220 && !(mnt_context_helper_executed(cxt) &&
2221 mnt_context_get_helper_status(cxt) == 0)) {
2222
2223 DBG(CXT, ul_debugobj(cxt, "don't update: syscall/helper failed/not called"));
2224 goto end;
2225 }
2226
2227 rc = mnt_update_table(cxt->update, cxt->lock);
2228
2229 end:
2230 if (!mnt_context_switch_ns(cxt, ns_old))
2231 return -MNT_ERR_NAMESPACE;
2232 return rc;
2233 }
2234
2235 /* apply @fs to @cxt;
2236 *
2237 * @mflags are mount flags as specified on command-line -- used only to save
2238 * MS_RDONLY which is allowed for non-root users.
2239 */
2240 static int apply_fs(struct libmnt_context *cxt, struct libmnt_fs *fs, unsigned long mflags)
2241 {
2242 struct libmnt_optlist *ls;
2243 int rc;
2244
2245
2246
2247 if (!cxt->optsmode) {
2248 if (mnt_context_is_restricted(cxt)) {
2249 DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
2250 cxt->optsmode = MNT_OMODE_USER;
2251 } else {
2252 DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
2253 cxt->optsmode = MNT_OMODE_AUTO;
2254 }
2255
2256 }
2257
2258 if (!mnt_context_get_fs(cxt))
2259 return -ENOMEM;
2260
2261 DBG(CXT, ul_debugobj(cxt, "apply entry:"));
2262 DBG(CXT, mnt_fs_print_debug(fs, stderr));
2263 DBG(CXT, ul_debugobj(cxt, "OPTSMODE (opt-part): ignore=%d, append=%d, prepend=%d, replace=%d",
2264 cxt->optsmode & MNT_OMODE_IGNORE ? 1 : 0,
2265 cxt->optsmode & MNT_OMODE_APPEND ? 1 : 0,
2266 cxt->optsmode & MNT_OMODE_PREPEND ? 1 : 0,
2267 cxt->optsmode & MNT_OMODE_REPLACE ? 1 : 0));
2268
2269 /* copy from fs to our FS description
2270 */
2271 rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
2272 if (!rc)
2273 rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
2274
2275 if (!rc && !mnt_fs_get_fstype(cxt->fs))
2276 rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
2277
2278 if (!rc && !mnt_fs_get_root(cxt->fs) && mnt_fs_get_root(fs))
2279 rc = mnt_fs_set_root(cxt->fs, mnt_fs_get_root(fs));
2280
2281 if (rc)
2282 goto done;
2283
2284 ls = mnt_context_get_optlist(cxt);
2285 if (!ls) {
2286 rc = -ENOMEM;
2287 goto done;
2288 }
2289
2290 if (cxt->optsmode & MNT_OMODE_IGNORE)
2291 ;
2292 else if (cxt->optsmode & MNT_OMODE_REPLACE) {
2293 rc = mnt_optlist_set_optstr(ls, mnt_fs_get_options(fs), NULL);
2294
2295 /* mount --read-only for non-root users is allowed */
2296 if (rc == 0 && (mflags & MS_RDONLY)
2297 && mnt_context_is_restricted(cxt)
2298 && cxt->optsmode == MNT_OMODE_USER)
2299 rc = mnt_optlist_append_optstr(ls, "ro", NULL);
2300 }
2301 else if (cxt->optsmode & MNT_OMODE_APPEND)
2302 rc = mnt_optlist_append_optstr(ls, mnt_fs_get_options(fs), NULL);
2303
2304 else if (cxt->optsmode & MNT_OMODE_PREPEND)
2305 rc = mnt_optlist_prepend_optstr(ls, mnt_fs_get_options(fs), NULL);
2306
2307 if (!rc)
2308 cxt->flags |= MNT_FL_TAB_APPLIED;
2309
2310 done:
2311 DBG(CXT, ul_debugobj(cxt, "final entry [rc=%d]", rc));
2312 DBG(CXT, mnt_fs_print_debug(cxt->fs, stderr));
2313
2314 return rc;
2315 }
2316
2317 static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
2318 int direction, unsigned long mflags)
2319 {
2320 struct libmnt_fs *fs = NULL;
2321 const char *src, *tgt;
2322
2323 assert(cxt);
2324 assert(cxt->fs);
2325
2326 src = mnt_fs_get_source(cxt->fs);
2327 tgt = mnt_fs_get_target(cxt->fs);
2328
2329 if (tgt && src)
2330 fs = mnt_table_find_pair(tb, src, tgt, direction);
2331 else {
2332 if (src)
2333 fs = mnt_table_find_source(tb, src, direction);
2334 else if (tgt)
2335 fs = mnt_table_find_target(tb, tgt, direction);
2336
2337 if (!fs && mnt_context_is_swapmatch(cxt)) {
2338 /* swap source and target (if @src is not LABEL/UUID),
2339 * for example in
2340 *
2341 * mount /foo/bar
2342 *
2343 * the path could be a mountpoint as well as a source (for
2344 * example bind mount, symlink to a device, ...).
2345 */
2346 if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
2347 fs = mnt_table_find_target(tb, src, direction);
2348 if (!fs && tgt)
2349 fs = mnt_table_find_source(tb, tgt, direction);
2350 }
2351 }
2352
2353 if (!fs)
2354 return -MNT_ERR_NOFSTAB; /* not found */
2355
2356 return apply_fs(cxt, fs, mflags);
2357 }
2358
2359 /* apply @fs to @cxt -- use mnt_context_apply_fstab() if not sure
2360 */
2361 int mnt_context_apply_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
2362 {
2363 return apply_fs(cxt, fs, 0);
2364 }
2365
2366 /**
2367 * mnt_context_apply_fstab:
2368 * @cxt: mount context
2369 *
2370 * This function is optional.
2371 *
2372 * Returns: 0 on success, negative number in case of error.
2373 */
2374 int mnt_context_apply_fstab(struct libmnt_context *cxt)
2375 {
2376 int rc = -1, isremount = 0, iscmdbind = 0;
2377 struct libmnt_ns *ns_old;
2378 struct libmnt_table *tab = NULL;
2379 const char *src = NULL, *tgt = NULL;
2380 unsigned long mflags = 0;
2381
2382 if (!cxt || !cxt->fs)
2383 return -EINVAL;
2384
2385 if (mnt_context_tab_applied(cxt)) { /* already applied */
2386 DBG(CXT, ul_debugobj(cxt, "fstab already applied -- skip"));
2387 return 0;
2388 }
2389
2390 if (mnt_context_is_restricted(cxt)) {
2391 DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
2392 cxt->optsmode = MNT_OMODE_USER;
2393 } else if (cxt->optsmode == 0) {
2394 DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
2395 cxt->optsmode = MNT_OMODE_AUTO;
2396 } else if (cxt->optsmode & MNT_OMODE_NOTAB) {
2397 cxt->optsmode &= ~MNT_OMODE_FSTAB;
2398 cxt->optsmode &= ~MNT_OMODE_MTAB;
2399 cxt->optsmode &= ~MNT_OMODE_FORCE;
2400 }
2401
2402 if (mnt_context_get_mflags(cxt, &mflags) == 0) {
2403 isremount = !!(mflags & MS_REMOUNT);
2404 iscmdbind = !!(mflags & MS_BIND);
2405 }
2406
2407 if (cxt->fs) {
2408 src = mnt_fs_get_source(cxt->fs);
2409 tgt = mnt_fs_get_target(cxt->fs);
2410 }
2411
2412 DBG(CXT, ul_debugobj(cxt, "OPTSMODE (file-part): force=%d, fstab=%d, mtab=%d",
2413 cxt->optsmode & MNT_OMODE_FORCE ? 1 : 0,
2414 cxt->optsmode & MNT_OMODE_FSTAB ? 1 : 0,
2415 cxt->optsmode & MNT_OMODE_MTAB ? 1 : 0));
2416
2417 /* fstab is not required if source and target are specified */
2418 if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
2419 DBG(CXT, ul_debugobj(cxt, "fstab not required -- skip"));
2420 return 0;
2421 }
2422
2423 if (!src && tgt
2424 && !(cxt->optsmode & MNT_OMODE_FSTAB)
2425 && !(cxt->optsmode & MNT_OMODE_MTAB)) {
2426 DBG(CXT, ul_debugobj(cxt, "only target; fstab/mtab not required "
2427 "-- skip, probably MS_PROPAGATION"));
2428 return 0;
2429 }
2430
2431 /* let's initialize cxt->fs */
2432 ignore_result( mnt_context_get_fs(cxt) );
2433
2434 ns_old = mnt_context_switch_target_ns(cxt);
2435 if (!ns_old)
2436 return -MNT_ERR_NAMESPACE;
2437
2438 /* try fstab */
2439 if (cxt->optsmode & MNT_OMODE_FSTAB) {
2440 DBG(CXT, ul_debugobj(cxt, "trying to apply fstab (src=%s, target=%s)", src, tgt));
2441 rc = mnt_context_get_fstab(cxt, &tab);
2442 if (!rc)
2443 rc = apply_table(cxt, tab, MNT_ITER_FORWARD, mflags);
2444 }
2445
2446 /* try mountinfo */
2447 if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)
2448 && (isremount || cxt->action == MNT_ACT_UMOUNT)) {
2449 DBG(CXT, ul_debugobj(cxt, "trying to apply mountinfo (src=%s, target=%s)", src, tgt));
2450 if (tgt)
2451 rc = mnt_context_get_mountinfo_for_target(cxt, &tab, tgt);
2452 else
2453 rc = mnt_context_get_mountinfo(cxt, &tab);
2454 if (!rc)
2455 rc = apply_table(cxt, tab, MNT_ITER_BACKWARD, mflags);
2456 }
2457
2458 if (!mnt_context_switch_ns(cxt, ns_old))
2459 return -MNT_ERR_NAMESPACE;
2460
2461 if (rc) {
2462 if (!mnt_context_is_restricted(cxt)
2463 && tgt && !src
2464 && isremount) {
2465 DBG(CXT, ul_debugobj(cxt, "only target; ignore missing mountinfo entry on remount"));
2466 return 0;
2467 }
2468
2469 DBG(CXT, ul_debugobj(cxt, "failed to find entry in fstab/mountinfo [rc=%d]: %m", rc));
2470
2471 /* force to "not found in fstab/mountinfo" error, the details why
2472 * not found are not so important and may be misinterpreted by
2473 * applications... */
2474 rc = -MNT_ERR_NOFSTAB;
2475
2476
2477 } else if (isremount && !iscmdbind && cxt->optlist) {
2478
2479 /* ignore "bind" on remount when the flag is read from fstab */
2480 mnt_optlist_remove_named(cxt->optlist, "bind", NULL);
2481 }
2482 return rc;
2483 }
2484
2485 /**
2486 * mnt_context_tab_applied:
2487 * @cxt: mount context
2488 *
2489 * Returns: 1 if fstab (or mountinfo) has been applied to the context, or 0.
2490 */
2491 int mnt_context_tab_applied(struct libmnt_context *cxt)
2492 {
2493 return cxt->flags & MNT_FL_TAB_APPLIED;
2494 }
2495
2496 /*
2497 * This is not a public function!
2498 *
2499 * Returns 1 if *only propagation flags* change is requested.
2500 */
2501 int mnt_context_propagation_only(struct libmnt_context *cxt)
2502 {
2503 struct libmnt_optlist *ls;
2504
2505 if (cxt->action != MNT_ACT_MOUNT)
2506 return 0;
2507 if (cxt->mountdata || cxt->fs == NULL)
2508 return 0;
2509 if (cxt->fs->fstype && strcmp(cxt->fs->fstype, "none") != 0)
2510 return 0;
2511 if (cxt->fs->source && strcmp(cxt->fs->source, "none") != 0)
2512 return 0;
2513
2514 ls = mnt_context_get_optlist(cxt);
2515 return ls ? mnt_optlist_is_propagation_only(ls) : 0;
2516 }
2517
2518 /**
2519 * mnt_context_get_status:
2520 * @cxt: mount context
2521 *
2522 * Global libmount status.
2523 *
2524 * The real exit code of the mount.type helper has to be tested by
2525 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2526 * that exec() has been successful.
2527 *
2528 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2529 */
2530 int mnt_context_get_status(struct libmnt_context *cxt)
2531 {
2532 return !cxt->syscall_status || !cxt->helper_exec_status;
2533 }
2534
2535 /**
2536 * mnt_context_helper_executed:
2537 * @cxt: mount context
2538 *
2539 * Returns: 1 if mount.type helper has been executed, or 0.
2540 */
2541 int mnt_context_helper_executed(struct libmnt_context *cxt)
2542 {
2543 return cxt->helper_exec_status != 1;
2544 }
2545
2546 /**
2547 * mnt_context_get_helper_status:
2548 * @cxt: mount context
2549 *
2550 * Return: mount.type helper exit status, result is reliable only if
2551 * mnt_context_helper_executed() returns 1.
2552 */
2553 int mnt_context_get_helper_status(struct libmnt_context *cxt)
2554 {
2555 return cxt->helper_status;
2556 }
2557
2558 /**
2559 * mnt_context_syscall_called:
2560 * @cxt: mount context
2561 *
2562 * Returns: 1 if mount(2) syscall has been called, or 0.
2563 */
2564 int mnt_context_syscall_called(struct libmnt_context *cxt)
2565 {
2566 return cxt->syscall_status != 1;
2567 }
2568
2569 /**
2570 * mnt_context_get_syscall_errno:
2571 * @cxt: mount context
2572 *
2573 * The result from this function is reliable only if
2574 * mnt_context_syscall_called() returns 1.
2575 *
2576 * Returns: mount(2) errno if the syscall failed or 0.
2577 */
2578 int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
2579 {
2580 if (cxt->syscall_status < 0)
2581 return -cxt->syscall_status;
2582 return 0;
2583 }
2584
2585 /**
2586 * mnt_context_set_syscall_status:
2587 * @cxt: mount context
2588 * @status: mount(2) status
2589 *
2590 * The @status should be 0 on success, or negative number on error (-errno).
2591 *
2592 * This function should only be used if the [u]mount(2) syscall is NOT called by
2593 * libmount code.
2594 *
2595 * Returns: 0 or negative number in case of error.
2596 */
2597 int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
2598 {
2599 if (!cxt)
2600 return -EINVAL;
2601
2602 DBG(CXT, ul_debugobj(cxt, "syscall status set to: %d", status));
2603 cxt->syscall_status = status;
2604 return 0;
2605 }
2606
2607 /**
2608 * mnt_context_strerror
2609 * @cxt: context
2610 * @buf: buffer
2611 * @bufsiz: size of the buffer
2612 *
2613 * Not implemented, deprecated in favor or mnt_context_get_excode().
2614 *
2615 * Returns: 0 or negative number in case of error.
2616 */
2617 int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
2618 char *buf __attribute__((__unused__)),
2619 size_t bufsiz __attribute__((__unused__)))
2620 {
2621 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2622 return 0;
2623 }
2624
2625 /**
2626 * mnt_context_enable_noautofs:
2627 * @cxt: context
2628 * @ignore: ignore or don't ignore
2629 *
2630 * Enable/disable ignore autofs mount table entries on reading the
2631 * mount table. Only effective if the "ignore" mount option is being
2632 * used for autofs mounts (such as if automount(8) has been configured
2633 * to do so).
2634 */
2635 int mnt_context_enable_noautofs(struct libmnt_context *cxt, int ignore)
2636 {
2637 if (!cxt)
2638 return -EINVAL;
2639 cxt->noautofs = ignore ? 1 : 0;
2640 return 0;
2641 }
2642
2643 int mnt_context_get_generic_excode(int rc, char *buf, size_t bufsz, const char *fmt, ...)
2644 {
2645 va_list va;
2646
2647 if (rc == 0)
2648 return MNT_EX_SUCCESS;
2649
2650 va_start(va, fmt);
2651
2652 /* we need to support "%m" */
2653 errno = rc < 0 ? -rc : rc;
2654
2655 if (buf && bufsz && vsnprintf(buf, bufsz, fmt, va) < 0)
2656 *buf = '\0';
2657
2658 switch (errno) {
2659 case EINVAL:
2660 case EPERM:
2661 rc = MNT_EX_USAGE;
2662 break;
2663 case ENOMEM:
2664 rc = MNT_EX_SYSERR;
2665 break;
2666 default:
2667 rc = MNT_EX_FAIL;
2668 break;
2669 }
2670 va_end(va);
2671 return rc;
2672 }
2673
2674 /**
2675 * mnt_context_get_excode:
2676 * @cxt: context
2677 * @rc: return code of the previous operation
2678 * @buf: buffer to print error message (optional)
2679 * @bufsz: size of the buffer
2680 *
2681 * This function analyzes context, [u]mount syscall and external helper status
2682 * and @mntrc and generates unified return code (see MNT_EX_*) as expected
2683 * from mount(8) or umount(8).
2684 *
2685 * If the external helper (e.g. /sbin/mount.type) has been executed than it
2686 * returns status from wait() of the helper. It's not libmount fail if helper
2687 * returns some crazy undocumented codes... See mnt_context_helper_executed()
2688 * and mnt_context_get_helper_status(). Note that mount(8) and umount(8) utils
2689 * always return code from helper without extra care about it.
2690 *
2691 * The current implementation does not read error message from external
2692 * helper into @buf.
2693 *
2694 * If the argument @buf is not NULL then error message is generated (if
2695 * anything failed).
2696 *
2697 * The @mntrc is usually return code from mnt_context_mount(),
2698 * mnt_context_umount(), or 'mntrc' as returned by mnt_context_next_mount().
2699 *
2700 * Since: 2.30
2701 *
2702 * Returns: MNT_EX_* codes.
2703 */
2704 int mnt_context_get_excode(
2705 struct libmnt_context *cxt,
2706 int rc,
2707 char *buf,
2708 size_t bufsz)
2709 {
2710 if (buf) {
2711 *buf = '\0'; /* for sure */
2712
2713 if (!cxt->enabled_textdomain) {
2714 bindtextdomain(LIBMOUNT_TEXTDOMAIN, LOCALEDIR);
2715 cxt->enabled_textdomain = 1;
2716 }
2717 }
2718
2719 switch (cxt->action) {
2720 case MNT_ACT_MOUNT:
2721 rc = mnt_context_get_mount_excode(cxt, rc, buf, bufsz);
2722 break;
2723 case MNT_ACT_UMOUNT:
2724 rc = mnt_context_get_umount_excode(cxt, rc, buf, bufsz);
2725 break;
2726 default:
2727 if (rc)
2728 rc = mnt_context_get_generic_excode(rc, buf, bufsz,
2729 _("operation failed: %m"));
2730 else
2731 rc = MNT_EX_SUCCESS;
2732 break;
2733 }
2734
2735 DBG(CXT, ul_debugobj(cxt, "excode: rc=%d message=\"%s\"", rc,
2736 buf ? buf : "<no-message>"));
2737 return rc;
2738 }
2739
2740
2741 /**
2742 * mnt_context_init_helper
2743 * @cxt: mount context
2744 * @action: MNT_ACT_{UMOUNT,MOUNT}
2745 * @flags: not used now
2746 *
2747 * This function informs libmount that used from [u]mount.type helper.
2748 *
2749 * The function also calls mnt_context_disable_helpers() to avoid recursive
2750 * mount.type helpers calling. It you really want to call another
2751 * mount.type helper from your helper, then you have to explicitly enable this
2752 * feature by:
2753 *
2754 * mnt_context_disable_helpers(cxt, FALSE);
2755 *
2756 * Returns: 0 on success, negative number in case of error.
2757 */
2758 int mnt_context_init_helper(struct libmnt_context *cxt, int action,
2759 int flags __attribute__((__unused__)))
2760 {
2761 int rc;
2762
2763 if (!cxt)
2764 return -EINVAL;
2765
2766 rc = mnt_context_disable_helpers(cxt, TRUE);
2767 if (!rc)
2768 rc = set_flag(cxt, MNT_FL_HELPER, 1);
2769 if (!rc)
2770 cxt->action = action;
2771
2772 DBG(CXT, ul_debugobj(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
2773 return rc;
2774 }
2775
2776 /**
2777 * mnt_context_helper_setopt:
2778 * @cxt: context
2779 * @c: getopt() result
2780 * @arg: getopt() optarg
2781 *
2782 * This function applies the [u]mount.type command line option (for example parsed
2783 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2784 * then 1 is returned.
2785 *
2786 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2787 */
2788 int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
2789 {
2790 if (cxt) {
2791 switch(cxt->action) {
2792 case MNT_ACT_MOUNT:
2793 return mnt_context_mount_setopt(cxt, c, arg);
2794 case MNT_ACT_UMOUNT:
2795 return mnt_context_umount_setopt(cxt, c, arg);
2796 }
2797 }
2798 return -EINVAL;
2799 }
2800
2801 /**
2802 * mnt_context_is_fs_mounted:
2803 * @cxt: context
2804 * @fs: filesystem
2805 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2806 *
2807 * Please, read the mnt_table_is_fs_mounted() description!
2808 *
2809 * Returns: 0 on success and negative number in case of error.
2810 */
2811 int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
2812 struct libmnt_fs *fs, int *mounted)
2813 {
2814 struct libmnt_table *mountinfo, *orig;
2815 int rc = 0;
2816 struct libmnt_ns *ns_old;
2817
2818 if (!cxt || !fs || !mounted)
2819 return -EINVAL;
2820
2821 ns_old = mnt_context_switch_target_ns(cxt);
2822 if (!ns_old)
2823 return -MNT_ERR_NAMESPACE;
2824
2825 orig = cxt->mountinfo;
2826 rc = mnt_context_get_mountinfo(cxt, &mountinfo);
2827 if (rc == -ENOENT && mnt_fs_streq_target(fs, "/proc")) {
2828 if (!orig) {
2829 mnt_unref_table(cxt->mountinfo);
2830 cxt->mountinfo = NULL;
2831 }
2832 *mounted = 0;
2833 rc = 0; /* /proc not mounted */
2834
2835 } else if (rc == 0) {
2836 *mounted = __mnt_table_is_fs_mounted(mountinfo, fs,
2837 mnt_context_get_target_prefix(cxt));
2838
2839 }
2840
2841 if (!mnt_context_switch_ns(cxt, ns_old))
2842 return -MNT_ERR_NAMESPACE;
2843 return rc;
2844 }
2845
2846 static int mnt_context_add_child(struct libmnt_context *cxt, pid_t pid)
2847 {
2848 pid_t *pids;
2849
2850 if (!cxt)
2851 return -EINVAL;
2852
2853 pids = reallocarray(cxt->children, cxt->nchildren + 1, sizeof(pid_t));
2854 if (!pids)
2855 return -ENOMEM;
2856
2857 DBG(CXT, ul_debugobj(cxt, "add new child %d", pid));
2858 cxt->children = pids;
2859 cxt->children[cxt->nchildren++] = pid;
2860
2861 return 0;
2862 }
2863
2864 int mnt_fork_context(struct libmnt_context *cxt)
2865 {
2866 int rc = 0;
2867 pid_t pid;
2868
2869 assert(cxt);
2870 if (!mnt_context_is_parent(cxt))
2871 return -EINVAL;
2872
2873 DBG(CXT, ul_debugobj(cxt, "forking context"));
2874
2875 DBG_FLUSH;
2876
2877 pid = fork();
2878
2879 switch (pid) {
2880 case -1: /* error */
2881 DBG(CXT, ul_debugobj(cxt, "fork failed %m"));
2882 return -errno;
2883
2884 case 0: /* child */
2885 cxt->pid = getpid();
2886 mnt_context_enable_fork(cxt, FALSE);
2887 DBG(CXT, ul_debugobj(cxt, "child created"));
2888 break;
2889
2890 default:
2891 rc = mnt_context_add_child(cxt, pid);
2892 break;
2893 }
2894
2895 return rc;
2896 }
2897
2898 int mnt_context_wait_for_children(struct libmnt_context *cxt,
2899 int *nchildren, int *nerrs)
2900 {
2901 int i;
2902
2903 if (!cxt)
2904 return -EINVAL;
2905
2906 assert(mnt_context_is_parent(cxt));
2907
2908 for (i = 0; i < cxt->nchildren; i++) {
2909 pid_t pid = cxt->children[i];
2910 int rc = 0, ret = 0;
2911
2912 if (!pid)
2913 continue;
2914 do {
2915 DBG(CXT, ul_debugobj(cxt,
2916 "waiting for child (%d/%d): %d",
2917 i + 1, cxt->nchildren, pid));
2918 errno = 0;
2919 rc = waitpid(pid, &ret, 0);
2920
2921 } while (rc == -1 && errno == EINTR);
2922
2923 if (nchildren)
2924 (*nchildren)++;
2925
2926 if (rc != -1 && nerrs) {
2927 if (WIFEXITED(ret))
2928 (*nerrs) += WEXITSTATUS(ret) == 0 ? 0 : 1;
2929 else
2930 (*nerrs)++;
2931 }
2932 cxt->children[i] = 0;
2933 }
2934
2935 cxt->nchildren = 0;
2936 free(cxt->children);
2937 cxt->children = NULL;
2938 return 0;
2939 }
2940
2941 static void close_ns(struct libmnt_ns *ns)
2942 {
2943 if (ns->fd == -1)
2944 return;
2945
2946 close(ns->fd);
2947 ns->fd = -1;
2948
2949 mnt_unref_cache(ns->cache);
2950 ns->cache = NULL;
2951 }
2952
2953 /**
2954 * mnt_context_set_target_ns:
2955 * @cxt: mount context
2956 * @path: path to target namespace or NULL
2957 *
2958 * Sets target namespace to namespace represented by @path. If @path is NULL,
2959 * target namespace is cleared.
2960 *
2961 * This function sets errno to ENOSYS and returns error if libmount is
2962 * compiled without namespaces support.
2963 *
2964 * Returns: 0 on success, negative number in case of error.
2965 *
2966 * Since: 2.33
2967 */
2968 int mnt_context_set_target_ns(struct libmnt_context *cxt, const char *path)
2969 {
2970 if (!cxt)
2971 return -EINVAL;
2972
2973 DBG(CXT, ul_debugobj(cxt, "Setting %s as target namespace", path));
2974
2975 /* cleanup only */
2976 if (!path) {
2977 close_ns(&cxt->ns_orig);
2978 close_ns(&cxt->ns_tgt);
2979 return 0;
2980 }
2981
2982 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
2983 int errsv = 0;
2984 int tmp;
2985
2986 errno = 0;
2987
2988 /* open original namespace */
2989 if (cxt->ns_orig.fd == -1) {
2990 cxt->ns_orig.fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
2991 if (cxt->ns_orig.fd == -1)
2992 return -errno;
2993 cxt->ns_orig.cache = NULL;
2994 }
2995
2996 /* open target (wanted) namespace */
2997 tmp = open(path, O_RDONLY | O_CLOEXEC);
2998 if (tmp == -1)
2999 return -errno;
3000
3001 /* test whether namespace switching works */
3002 DBG(CXT, ul_debugobj(cxt, "Trying whether namespace is valid"));
3003 if (setns(tmp, CLONE_NEWNS)
3004 || setns(cxt->ns_orig.fd, CLONE_NEWNS)) {
3005 errsv = errno;
3006 DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
3007 goto err;
3008 }
3009
3010 close_ns(&cxt->ns_tgt);
3011
3012 cxt->ns_tgt.fd = tmp;
3013 cxt->ns_tgt.cache = NULL;
3014
3015 return 0;
3016 err:
3017 close(tmp);
3018 errno = errsv;
3019
3020 #else /* ! USE_LIBMOUNT_SUPPORT_NAMESPACES */
3021 errno = ENOSYS;
3022 #endif
3023 return -errno;
3024 }
3025
3026 /**
3027 * mnt_context_get_target_ns:
3028 * @cxt: mount context
3029 *
3030 * Returns: pointer to target namespace
3031 *
3032 * Since: 2.33
3033 */
3034 struct libmnt_ns *mnt_context_get_target_ns(struct libmnt_context *cxt)
3035 {
3036 return &cxt->ns_tgt;
3037 }
3038
3039 /**
3040 * mnt_context_get_origin_ns:
3041 * @cxt: mount context
3042 *
3043 * Returns: pointer to original namespace
3044 *
3045 * Since: 2.33
3046 */
3047 struct libmnt_ns *mnt_context_get_origin_ns(struct libmnt_context *cxt)
3048 {
3049 return &cxt->ns_orig;
3050 }
3051
3052
3053 /**
3054 * mnt_context_switch_ns:
3055 * @cxt: mount context
3056 * @ns: namespace to switch to
3057 *
3058 * Switch to namespace specified by ns
3059 *
3060 * Typical usage:
3061 * <informalexample>
3062 * <programlisting>
3063 * struct libmnt_ns *ns_old;
3064 * ns_old = mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3065 * ... code ...
3066 * mnt_context_switch_ns(cxt, ns_old);
3067 * </programlisting>
3068 * </informalexample>
3069 *
3070 * Returns: pointer to previous namespace or NULL on error
3071 *
3072 * Since: 2.33
3073 */
3074 struct libmnt_ns *mnt_context_switch_ns(struct libmnt_context *cxt, struct libmnt_ns *ns)
3075 {
3076 struct libmnt_ns *old = NULL;
3077
3078 if (!cxt || !ns)
3079 return NULL;
3080
3081 /*
3082 * If mnt_context_set_target_ns() has never been used than @ns file
3083 * descriptor is -1 and this function is noop.
3084 */
3085 old = cxt->ns_cur;
3086 if (ns == old || ns->fd == -1)
3087 return old;
3088
3089 #ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3090 /* remember the current cache */
3091 if (old->cache != cxt->cache) {
3092 mnt_unref_cache(old->cache);
3093 old->cache = cxt->cache;
3094 mnt_ref_cache(old->cache);
3095 }
3096
3097 /* switch */
3098 DBG(CXT, ul_debugobj(cxt, "Switching to %s namespace",
3099 ns == mnt_context_get_target_ns(cxt) ? "target" :
3100 ns == mnt_context_get_origin_ns(cxt) ? "original" : "other"));
3101
3102 if (setns(ns->fd, CLONE_NEWNS)) {
3103 int errsv = errno;
3104
3105 DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
3106 errno = errsv;
3107 return NULL;
3108 }
3109
3110 /* update pointer to the current namespace */
3111 cxt->ns_cur = ns;
3112
3113 /* update pointer to the cache */
3114 mnt_unref_cache(cxt->cache);
3115 cxt->cache = ns->cache;
3116 mnt_ref_cache(cxt->cache);
3117 #endif /* USE_LIBMOUNT_SUPPORT_NAMESPACES */
3118
3119 return old;
3120 }
3121
3122 /**
3123 * mnt_context_switch_origin_ns:
3124 * @cxt: mount context
3125 *
3126 * Switch to original namespace
3127 *
3128 * This is shorthand for
3129 * <informalexample>
3130 * <programlisting>
3131 * mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3132 * </programlisting>
3133 * </informalexample>
3134 *
3135 * Returns: pointer to previous namespace or NULL on error
3136 *
3137 * Since: 2.33
3138 */
3139 struct libmnt_ns *mnt_context_switch_origin_ns(struct libmnt_context *cxt)
3140 {
3141 return mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3142 }
3143
3144 /**
3145 * mnt_context_switch_target_ns:
3146 * @cxt: mount context
3147 *
3148 * Switch to target namespace
3149 *
3150 * This is shorthand for
3151 * <informalexample>
3152 * <programlisting>
3153 * mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3154 * </programlisting>
3155 * </informalexample>
3156 *
3157 * Returns: pointer to previous namespace or NULL on error
3158 *
3159 * Since: 2.33
3160 */
3161 struct libmnt_ns *mnt_context_switch_target_ns(struct libmnt_context *cxt)
3162 {
3163 return mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3164 }
3165
3166
3167 #ifdef TEST_PROGRAM
3168
3169 static int test_search_helper(struct libmnt_test *ts __attribute__((unused)),
3170 int argc, char *argv[])
3171 {
3172 struct libmnt_context *cxt;
3173 const char *type;
3174 int rc;
3175
3176 if (argc < 2)
3177 return -EINVAL;
3178
3179 cxt = mnt_new_context();
3180 if (!cxt)
3181 return -ENOMEM;
3182
3183 type = argv[1];
3184
3185 mnt_context_get_fs(cxt); /* just to fill cxt->fs */
3186 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED; /* fake */
3187
3188 rc = mnt_context_prepare_helper(cxt, "mount", type);
3189 printf("helper is: %s\n", cxt->helper ? cxt->helper : "not found");
3190
3191 mnt_free_context(cxt);
3192 return rc;
3193 }
3194
3195
3196 static struct libmnt_lock *lock;
3197
3198 static void lock_fallback(void)
3199 {
3200 if (lock)
3201 mnt_unlock_file(lock);
3202 }
3203
3204 static int test_mount(struct libmnt_test *ts __attribute__((unused)),
3205 int argc, char *argv[])
3206 {
3207 int idx = 1, rc = 0;
3208 struct libmnt_context *cxt;
3209
3210 if (argc < 2)
3211 return -EINVAL;
3212
3213 cxt = mnt_new_context();
3214 if (!cxt)
3215 return -ENOMEM;
3216
3217 if (!strcmp(argv[idx], "-o")) {
3218 mnt_context_set_options(cxt, argv[idx + 1]);
3219 idx += 2;
3220 }
3221 if (!strcmp(argv[idx], "-t")) {
3222 /* TODO: use mnt_context_set_fstype_pattern() */
3223 mnt_context_set_fstype(cxt, argv[idx + 1]);
3224 idx += 2;
3225 }
3226
3227 if (argc == idx + 1)
3228 /* mount <mountpoint>|<device> */
3229 mnt_context_set_target(cxt, argv[idx++]);
3230
3231 else if (argc == idx + 2) {
3232 /* mount <device> <mountpoint> */
3233 mnt_context_set_source(cxt, argv[idx++]);
3234 mnt_context_set_target(cxt, argv[idx++]);
3235 }
3236
3237 /* this is unnecessary! -- libmount is able to internally
3238 * create and manage the lock
3239 */
3240 lock = mnt_context_get_lock(cxt);
3241 if (lock)
3242 atexit(lock_fallback);
3243
3244 rc = mnt_context_mount(cxt);
3245 if (rc)
3246 warn("failed to mount");
3247 else
3248 printf("successfully mounted\n");
3249
3250 lock = NULL; /* because we use atexit lock_fallback */
3251 mnt_free_context(cxt);
3252 return rc;
3253 }
3254
3255 static int test_umount(struct libmnt_test *ts __attribute__((unused)),
3256 int argc, char *argv[])
3257 {
3258 int idx = 1, rc = 0;
3259 struct libmnt_context *cxt;
3260
3261 if (argc < 2)
3262 return -EINVAL;
3263
3264 cxt = mnt_new_context();
3265 if (!cxt)
3266 return -ENOMEM;
3267
3268 if (!strcmp(argv[idx], "-t")) {
3269 mnt_context_set_fstype(cxt, argv[idx + 1]);
3270 idx += 2;
3271 }
3272
3273 if (!strcmp(argv[idx], "-f")) {
3274 mnt_context_enable_force(cxt, TRUE);
3275 idx++;
3276 }
3277
3278 if (!strcmp(argv[idx], "-l")) {
3279 mnt_context_enable_lazy(cxt, TRUE);
3280 idx++;
3281 }
3282
3283 if (!strcmp(argv[idx], "-r")) {
3284 mnt_context_enable_rdonly_umount(cxt, TRUE);
3285 idx++;
3286 }
3287
3288 if (argc == idx + 1) {
3289 /* mount <mountpoint>|<device> */
3290 mnt_context_set_target(cxt, argv[idx++]);
3291 } else {
3292 rc = -EINVAL;
3293 goto err;
3294 }
3295
3296 lock = mnt_context_get_lock(cxt);
3297 if (lock)
3298 atexit(lock_fallback);
3299
3300 rc = mnt_context_umount(cxt);
3301 if (rc)
3302 printf("failed to umount\n");
3303 else
3304 printf("successfully umounted\n");
3305 err:
3306 lock = NULL; /* because we use atexit lock_fallback */
3307 mnt_free_context(cxt);
3308 return rc;
3309 }
3310
3311 static int test_flags(struct libmnt_test *ts __attribute__((unused)),
3312 int argc, char *argv[])
3313 {
3314 int idx = 1, rc = 0;
3315 struct libmnt_context *cxt;
3316 const char *opt = NULL;
3317 unsigned long flags = 0;
3318
3319 if (argc < 2)
3320 return -EINVAL;
3321
3322 cxt = mnt_new_context();
3323 if (!cxt)
3324 return -ENOMEM;
3325
3326 if (!strcmp(argv[idx], "-o")) {
3327 mnt_context_set_options(cxt, argv[idx + 1]);
3328 idx += 2;
3329 }
3330
3331 if (argc == idx + 1)
3332 /* mount <mountpoint>|<device> */
3333 mnt_context_set_target(cxt, argv[idx++]);
3334
3335 rc = mnt_context_prepare_mount(cxt);
3336 if (rc)
3337 printf("failed to prepare mount %s\n", strerror(-rc));
3338
3339 opt = mnt_fs_get_options(cxt->fs);
3340 if (opt)
3341 fprintf(stdout, "options: %s\n", opt);
3342
3343 mnt_context_get_mflags(cxt, &flags);
3344 fprintf(stdout, "flags: %08lx\n", flags);
3345
3346 mnt_free_context(cxt);
3347 return rc;
3348 }
3349
3350 static int test_cxtsync(struct libmnt_test *ts __attribute__((unused)),
3351 int argc, char *argv[])
3352 {
3353 struct libmnt_context *cxt;
3354 struct libmnt_fs *fs;
3355 unsigned long flags = 0;
3356 int rc;
3357
3358 if (argc != 4)
3359 return -EINVAL;
3360
3361 fs = mnt_new_fs();
3362 if (!fs)
3363 return -ENOMEM;
3364
3365 rc = mnt_fs_set_options(fs, argv[1]);
3366 if (rc)
3367 return rc;
3368
3369 cxt = mnt_new_context();
3370 if (!cxt)
3371 return -ENOMEM;
3372
3373 rc = mnt_context_set_fs(cxt, fs);
3374 if (rc)
3375 return rc;
3376
3377 rc = mnt_context_append_options(cxt, argv[2]);
3378 if (rc)
3379 return rc;
3380
3381 rc = mnt_fs_append_options(fs, argv[3]);
3382 if (rc)
3383 return rc;
3384
3385 mnt_context_get_mflags(cxt, &flags);
3386
3387 printf(" fs options: %s\n", mnt_fs_get_options(fs));
3388 printf("context options: %s\n", mnt_context_get_options(cxt));
3389 printf(" context mflags: %08lx\n", flags);
3390
3391 mnt_free_context(cxt);
3392 return 0;
3393 }
3394
3395 static int test_mountall(struct libmnt_test *ts __attribute__((unused)),
3396 int argc, char *argv[])
3397 {
3398 struct libmnt_context *cxt;
3399 struct libmnt_iter *itr;
3400 struct libmnt_fs *fs;
3401 int mntrc, ignored, idx = 1;
3402
3403 cxt = mnt_new_context();
3404 itr = mnt_new_iter(MNT_ITER_FORWARD);
3405
3406 if (!cxt || !itr)
3407 return -ENOMEM;
3408
3409 if (argc > 2) {
3410 if (argv[idx] && !strcmp(argv[idx], "-O")) {
3411 mnt_context_set_options_pattern(cxt, argv[idx + 1]);
3412 idx += 2;
3413 }
3414 if (argv[idx] && !strcmp(argv[idx], "-t"))
3415 mnt_context_set_fstype_pattern(cxt, argv[idx + 1]);
3416 }
3417
3418 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
3419
3420 const char *tgt = mnt_fs_get_target(fs);
3421
3422 if (ignored == 1)
3423 printf("%s: ignored: not match\n", tgt);
3424 else if (ignored == 2)
3425 printf("%s: ignored: already mounted\n", tgt);
3426
3427 else if (!mnt_context_get_status(cxt)) {
3428 if (mntrc > 0) {
3429 errno = mntrc;
3430 warn("%s: mount failed", tgt);
3431 } else
3432 warnx("%s: mount failed", tgt);
3433 } else
3434 printf("%s: successfully mounted\n", tgt);
3435 }
3436
3437 mnt_free_context(cxt);
3438 return 0;
3439 }
3440
3441
3442
3443 int main(int argc, char *argv[])
3444 {
3445 struct libmnt_test tss[] = {
3446 { "--mount", test_mount, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
3447 { "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
3448 { "--mount-all", test_mountall, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
3449 { "--flags", test_flags, "[-o <opts>] <spec>" },
3450 { "--cxtsync", test_cxtsync, "<fsopts> <cxtopts> <fsopts>" },
3451 { "--search-helper", test_search_helper, "<fstype>" },
3452 { NULL }};
3453
3454 umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */
3455
3456 return mnt_run_test(tss, argc, argv);
3457 }
3458
3459 #endif /* TEST_PROGRAM */