]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
libmount: special treatment for auto in fstype pattern
[thirdparty/util-linux.git] / libmount / src / context.c
1 /*
2 * Copyright (C) 2010,2011,2012 Karel Zak <kzak@redhat.com>
3 *
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
6 */
7
8 /**
9 * SECTION: context
10 * @title: Library high-level context
11 * @short_description: high-level API to mount/umount devices.
12 *
13 * <informalexample>
14 * <programlisting>
15 * struct libmnt_context *cxt = mnt_new_context();
16 *
17 * mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
18 * mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
19 * mnt_context_set_target(cxt, "/mnt/foo");
20 *
21 * if (!mnt_context_mount(cxt))
22 * printf("successfully mounted\n");
23 * mnt_free_context(cxt);
24 *
25 * </programlisting>
26 * </informalexample>
27 *
28 * This code is similar to:
29 *
30 * mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
31 *
32 */
33
34 #include "mountP.h"
35 #include "fileutils.h"
36
37 #include <sys/wait.h>
38
39 /**
40 * mnt_new_context:
41 *
42 * Returns: newly allocated mount context
43 */
44 struct libmnt_context *mnt_new_context(void)
45 {
46 struct libmnt_context *cxt;
47 uid_t ruid, euid;
48
49 cxt = calloc(1, sizeof(*cxt));
50 if (!cxt)
51 return NULL;
52
53 INIT_LIST_HEAD(&cxt->addmounts);
54
55 ruid = getuid();
56 euid = geteuid();
57
58 mnt_context_reset_status(cxt);
59
60 cxt->loopdev_fd = -1;
61
62 /* if we're really root and aren't running setuid */
63 cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
64
65 DBG(CXT, ul_debugobj(cxt, "----> allocate %s",
66 cxt->restricted ? "[RESTRICTED]" : ""));
67
68
69 return cxt;
70 }
71
72 /**
73 * mnt_free_context:
74 * @cxt: mount context
75 *
76 * Deallocates context struct.
77 */
78 void mnt_free_context(struct libmnt_context *cxt)
79 {
80 if (!cxt)
81 return;
82
83 mnt_reset_context(cxt);
84
85 free(cxt->fstype_pattern);
86 free(cxt->optstr_pattern);
87
88 mnt_unref_table(cxt->fstab);
89 mnt_unref_cache(cxt->cache);
90
91 mnt_context_clear_loopdev(cxt);
92 mnt_free_lock(cxt->lock);
93 mnt_free_update(cxt->update);
94
95 free(cxt->children);
96
97 DBG(CXT, ul_debugobj(cxt, "<---- free"));
98 free(cxt);
99 }
100
101 /**
102 * mnt_reset_context:
103 * @cxt: mount context
104 *
105 * Resets all information in the context that is directly related to
106 * the latest mount (spec, source, target, mount options, ...).
107 *
108 * The match patterns, cached fstab, cached canonicalized paths and tags and
109 * [e]uid are not reset. You have to use
110 *
111 * mnt_context_set_fstab(cxt, NULL);
112 * mnt_context_set_cache(cxt, NULL);
113 * mnt_context_set_fstype_pattern(cxt, NULL);
114 * mnt_context_set_options_pattern(cxt, NULL);
115 *
116 *
117 * to reset this stuff.
118 *
119 * Returns: 0 on success, negative number in case of error.
120 */
121 int mnt_reset_context(struct libmnt_context *cxt)
122 {
123 int fl;
124
125 if (!cxt)
126 return -EINVAL;
127
128 DBG(CXT, ul_debugobj(cxt, "<---- reset [status=%d] ---->",
129 mnt_context_get_status(cxt)));
130
131 fl = cxt->flags;
132
133 mnt_unref_fs(cxt->fs);
134 mnt_unref_table(cxt->mtab);
135 mnt_unref_table(cxt->utab);
136
137 free(cxt->helper);
138 free(cxt->orig_user);
139
140 cxt->fs = NULL;
141 cxt->mtab = NULL;
142 cxt->utab = NULL;
143 cxt->helper = NULL;
144 cxt->orig_user = NULL;
145 cxt->mountflags = 0;
146 cxt->user_mountflags = 0;
147 cxt->mountdata = NULL;
148 cxt->flags = MNT_FL_DEFAULT;
149
150 /* free additional mounts list */
151 while (!list_empty(&cxt->addmounts)) {
152 struct libmnt_addmount *ad = list_entry(cxt->addmounts.next,
153 struct libmnt_addmount,
154 mounts);
155 mnt_free_addmount(ad);
156 }
157
158 mnt_context_reset_status(cxt);
159
160 if (cxt->table_fltrcb)
161 mnt_context_set_tabfilter(cxt, NULL, NULL);
162
163 /* restore non-resettable flags */
164 cxt->flags |= (fl & MNT_FL_NOMTAB);
165 cxt->flags |= (fl & MNT_FL_FAKE);
166 cxt->flags |= (fl & MNT_FL_SLOPPY);
167 cxt->flags |= (fl & MNT_FL_VERBOSE);
168 cxt->flags |= (fl & MNT_FL_NOHELPERS);
169 cxt->flags |= (fl & MNT_FL_LOOPDEL);
170 cxt->flags |= (fl & MNT_FL_LAZY);
171 cxt->flags |= (fl & MNT_FL_FORK);
172 cxt->flags |= (fl & MNT_FL_FORCE);
173 cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
174 cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
175 cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
176 cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
177 return 0;
178 }
179
180 /**
181 * mnt_context_reset_status:
182 * @cxt: context
183 *
184 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
185 * mnt_context_do_umount() could be again called with the same settings.
186 *
187 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
188 * options, evaluate permissions or apply stuff from fstab.
189 *
190 * Returns: 0 on success, negative number in case of error.
191 */
192 int mnt_context_reset_status(struct libmnt_context *cxt)
193 {
194 assert(cxt);
195 if (!cxt)
196 return -EINVAL;
197
198 cxt->syscall_status = 1; /* means not called yet */
199 cxt->helper_exec_status = 1;
200 cxt->helper_status = 0;
201 return 0;
202 }
203
204 static int context_init_paths(struct libmnt_context *cxt, int writable)
205 {
206 assert(cxt);
207
208 if (!cxt->mtab_path)
209 cxt->mtab_path = mnt_get_mtab_path();
210 if (!cxt->utab_path)
211 cxt->utab_path = mnt_get_utab_path();
212
213 if (!writable)
214 return 0; /* only paths wanted */
215 if (mnt_context_is_nomtab(cxt))
216 return 0; /* write mode overrided by mount -n */
217 if (cxt->flags & MNT_FL_TABPATHS_CHECKED)
218 return 0;
219
220 DBG(CXT, ul_debugobj(cxt, "checking for writable tab files"));
221
222 mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
223
224 if (!cxt->mtab_writable)
225 /* use /run/mount/utab if /etc/mtab is useless */
226 mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
227
228 cxt->flags |= MNT_FL_TABPATHS_CHECKED;
229 return 0;
230 }
231
232 int mnt_context_mtab_writable(struct libmnt_context *cxt)
233 {
234 assert(cxt);
235
236 context_init_paths(cxt, 1);
237 return cxt->mtab_writable == 1;
238 }
239
240 int mnt_context_utab_writable(struct libmnt_context *cxt)
241 {
242 assert(cxt);
243
244 context_init_paths(cxt, 1);
245 return cxt->utab_writable == 1;
246 }
247
248 const char *mnt_context_get_writable_tabpath(struct libmnt_context *cxt)
249 {
250 assert(cxt);
251
252 context_init_paths(cxt, 1);
253 return cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path;
254 }
255
256
257 static int set_flag(struct libmnt_context *cxt, int flag, int enable)
258 {
259 assert(cxt);
260 if (!cxt)
261 return -EINVAL;
262 if (enable) {
263 DBG(CXT, ul_debugobj(cxt, "enabling flag %04x", flag));
264 cxt->flags |= flag;
265 } else {
266 DBG(CXT, ul_debugobj(cxt, "disabling flag %04x", flag));
267 cxt->flags &= ~flag;
268 }
269 return 0;
270 }
271
272 /**
273 * mnt_context_is_restricted:
274 * @cxt: mount context
275 *
276 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
277 */
278 int mnt_context_is_restricted(struct libmnt_context *cxt)
279 {
280 return cxt->restricted;
281 }
282
283 /**
284 * mnt_context_set_optsmode
285 * @cxt: mount context
286 * @mode: MNT_OMODE_* flags
287 *
288 * Controls how to use mount optionssource and target paths from fstab/mtab.
289 *
290 * @MNT_OMODE_IGNORE: ignore mtab/fstab options
291 *
292 * @MNT_OMODE_APPEND: append mtab/fstab options to existing options
293 *
294 * @MNT_OMODE_PREPEND: prepend mtab/fstab options to existing options
295 *
296 * @MNT_OMODE_REPLACE: replace existing options with options from mtab/fstab
297 *
298 * @MNT_OMODE_FORCE: always read mtab/fstab (although source and target are defined)
299 *
300 * @MNT_OMODE_FSTAB: read from fstab
301 *
302 * @MNT_OMODE_MTAB: read from mtab if fstab not enabled or failed
303 *
304 * @MNT_OMODE_NOTAB: do not read fstab/mtab at all
305 *
306 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
307 *
308 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
309 *
310 * Notes:
311 *
312 * - MNT_OMODE_USER is always used if mount context is in restricted mode
313 * - MNT_OMODE_AUTO is used if nothing else is defined
314 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
315 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mtab
316 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPAND,REPLACE}
317 *
318 * Returns: 0 on success, negative number in case of error.
319 */
320 int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
321 {
322 assert(cxt);
323 if (!cxt)
324 return -EINVAL;
325 cxt->optsmode = mode;
326 return 0;
327 }
328
329 /**
330 * mnt_context_get_optsmode
331 * @cxt: mount context
332 *
333 * Returns: MNT_OMODE_* mask or zero.
334 */
335
336 int mnt_context_get_optsmode(struct libmnt_context *cxt)
337 {
338 assert(cxt);
339 return cxt->optsmode;
340 }
341
342 /**
343 * mnt_context_disable_canonicalize:
344 * @cxt: mount context
345 * @disable: TRUE or FALSE
346 *
347 * Enable/disable paths canonicalization and tags evaluation. The libmount context
348 * canonicalizes paths when searching in fstab and when preparing source and target paths
349 * for mount(2) syscall.
350 *
351 * This fuction has an effect on the private (within context) fstab instance only
352 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
353 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
354 * NULL).
355 *
356 * Returns: 0 on success, negative number in case of error.
357 */
358 int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
359 {
360 return set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
361 }
362
363 /**
364 * mnt_context_is_nocanonicalize:
365 * @cxt: mount context
366 *
367 * Returns: 1 if no-canonicalize mode is enabled or 0.
368 */
369 int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
370 {
371 return cxt && (cxt->flags & MNT_FL_NOCANONICALIZE) ? 1 : 0;
372 }
373
374 /**
375 * mnt_context_enable_lazy:
376 * @cxt: mount context
377 * @enable: TRUE or FALSE
378 *
379 * Enable/disable lazy umount (see umount(8) man page, option -l).
380 *
381 * Returns: 0 on success, negative number in case of error.
382 */
383 int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
384 {
385 return set_flag(cxt, MNT_FL_LAZY, enable);
386 }
387
388 /**
389 * mnt_context_is_lazy:
390 * @cxt: mount context
391 *
392 * Returns: 1 if lazy umount is enabled or 0
393 */
394 int mnt_context_is_lazy(struct libmnt_context *cxt)
395 {
396 return cxt->flags & MNT_FL_LAZY ? 1 : 0;
397 }
398
399 /**
400 * mnt_context_enable_fork:
401 * @cxt: mount context
402 * @enable: TRUE or FALSE
403 *
404 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
405 * page, option -F).
406 *
407 * Returns: 0 on success, negative number in case of error.
408 */
409 int mnt_context_enable_fork(struct libmnt_context *cxt, int enable)
410 {
411 return set_flag(cxt, MNT_FL_FORK, enable);
412 }
413
414 /**
415 * mnt_context_is_fork:
416 * @cxt: mount context
417 *
418 * Returns: 1 if fork (mount -F) is enabled or 0
419 */
420 int mnt_context_is_fork(struct libmnt_context *cxt)
421 {
422 return cxt->flags & MNT_FL_FORK ? 1 : 0;
423 }
424
425 /**
426 * mnt_context_is_parent:
427 * @cxt: mount context
428 *
429 * Return: 1 if mount -F enabled and the current context is parent, or 0
430 */
431 int mnt_context_is_parent(struct libmnt_context *cxt)
432 {
433 return mnt_context_is_fork(cxt) && cxt->pid == 0;
434 }
435
436 /**
437 * mnt_context_is_child:
438 * @cxt: mount context
439 *
440 * Return: 1 f the current context is child, or 0
441 */
442 int mnt_context_is_child(struct libmnt_context *cxt)
443 {
444 /* See mnt_fork_context(), the for fork flag is always disabled
445 * for children to avoid recursive forking.
446 */
447 return !mnt_context_is_fork(cxt) && cxt->pid;
448 }
449
450 /**
451 * mnt_context_enable_rdonly_umount:
452 * @cxt: mount context
453 * @enable: TRUE or FALSE
454 *
455 * Enable/disable read-only remount on failed umount(2)
456 * (see umount(8) man page, option -r).
457 *
458 * Returns: 0 on success, negative number in case of error.
459 */
460 int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
461 {
462 return set_flag(cxt, MNT_FL_RDONLY_UMOUNT, enable);
463 }
464
465 /**
466 * mnt_context_is_rdonly_umount
467 * @cxt: mount context
468 *
469 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
470 * option -r.
471 *
472 * Returns: 1 if read-only remount failed umount(2) is enables or 0
473 */
474 int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
475 {
476 return cxt->flags & MNT_FL_RDONLY_UMOUNT ? 1 : 0;
477 }
478
479 /**
480 * mnt_context_disable_helpers:
481 * @cxt: mount context
482 * @disable: TRUE or FALSE
483 *
484 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
485 *
486 * Returns: 0 on success, negative number in case of error.
487 */
488 int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable)
489 {
490 return set_flag(cxt, MNT_FL_NOHELPERS, disable);
491 }
492
493 /**
494 * mnt_context_is_nohelpers
495 * @cxt: mount context
496 *
497 * Returns: 1 if helpers are disabled (mount -i) or 0
498 */
499 int mnt_context_is_nohelpers(struct libmnt_context *cxt)
500 {
501 return cxt->flags & MNT_FL_NOHELPERS ? 1 : 0;
502 }
503
504
505 /**
506 * mnt_context_enable_sloppy:
507 * @cxt: mount context
508 * @enable: TRUE or FALSE
509 *
510 * Set/unset sloppy mounting (see mount(8) man page, option -s).
511 *
512 * Returns: 0 on success, negative number in case of error.
513 */
514 int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable)
515 {
516 return set_flag(cxt, MNT_FL_SLOPPY, enable);
517 }
518
519 /**
520 * mnt_context_is_sloppy:
521 * @cxt: mount context
522 *
523 * Returns: 1 if sloppy flag is enabled or 0
524 */
525 int mnt_context_is_sloppy(struct libmnt_context *cxt)
526 {
527 return cxt->flags & MNT_FL_SLOPPY ? 1 : 0;
528 }
529
530 /**
531 * mnt_context_enable_fake:
532 * @cxt: mount context
533 * @enable: TRUE or FALSE
534 *
535 * Enable/disable fake mounting (see mount(8) man page, option -f).
536 *
537 * Returns: 0 on success, negative number in case of error.
538 */
539 int mnt_context_enable_fake(struct libmnt_context *cxt, int enable)
540 {
541 return set_flag(cxt, MNT_FL_FAKE, enable);
542 }
543
544 /**
545 * mnt_context_is_fake:
546 * @cxt: mount context
547 *
548 * Returns: 1 if fake flag is enabled or 0
549 */
550 int mnt_context_is_fake(struct libmnt_context *cxt)
551 {
552 return cxt->flags & MNT_FL_FAKE ? 1 : 0;
553 }
554
555 /**
556 * mnt_context_disable_mtab:
557 * @cxt: mount context
558 * @disable: TRUE or FALSE
559 *
560 * Disable/enable mtab update (see mount(8) man page, option -n).
561 *
562 * Returns: 0 on success, negative number in case of error.
563 */
564 int mnt_context_disable_mtab(struct libmnt_context *cxt, int disable)
565 {
566 return set_flag(cxt, MNT_FL_NOMTAB, disable);
567 }
568
569 /**
570 * mnt_context_is_nomtab:
571 * @cxt: mount context
572 *
573 * Returns: 1 if no-mtab is enabled or 0
574 */
575 int mnt_context_is_nomtab(struct libmnt_context *cxt)
576 {
577 return cxt->flags & MNT_FL_NOMTAB ? 1 : 0;
578 }
579
580 /**
581 * mnt_context_disable_swapmatch:
582 * @cxt: mount context
583 * @disable: TRUE or FALSE
584 *
585 * Disable/enable swap between source and target for mount(8) if only one path
586 * is specified.
587 *
588 * Returns: 0 on success, negative number in case of error.
589 */
590 int mnt_context_disable_swapmatch(struct libmnt_context *cxt, int disable)
591 {
592 return set_flag(cxt, MNT_FL_NOSWAPMATCH, disable);
593 }
594
595 /**
596 * mnt_context_is_swapmatch:
597 * @cxt: mount context
598 *
599 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
600 */
601 int mnt_context_is_swapmatch(struct libmnt_context *cxt)
602 {
603 return cxt->flags & MNT_FL_NOSWAPMATCH ? 0 : 1;
604 }
605
606 /**
607 * mnt_context_enable_force:
608 * @cxt: mount context
609 * @enable: TRUE or FALSE
610 *
611 * Enable/disable force umounting (see umount(8) man page, option -f).
612 *
613 * Returns: 0 on success, negative number in case of error.
614 */
615 int mnt_context_enable_force(struct libmnt_context *cxt, int enable)
616 {
617 return set_flag(cxt, MNT_FL_FORCE, enable);
618 }
619
620 /**
621 * mnt_context_is_force
622 * @cxt: mount context
623 *
624 * Returns: 1 if force umounting flag is enabled or 0
625 */
626 int mnt_context_is_force(struct libmnt_context *cxt)
627 {
628 return cxt->flags & MNT_FL_FORCE ? 1 : 0;
629 }
630
631 /**
632 * mnt_context_enable_verbose:
633 * @cxt: mount context
634 * @enable: TRUE or FALSE
635 *
636 * Enable/disable verbose output (TODO: not implemented yet)
637 *
638 * Returns: 0 on success, negative number in case of error.
639 */
640 int mnt_context_enable_verbose(struct libmnt_context *cxt, int enable)
641 {
642 return set_flag(cxt, MNT_FL_VERBOSE, enable);
643 }
644
645 /**
646 * mnt_context_is_verbose
647 * @cxt: mount context
648 *
649 * Returns: 1 if verbose flag is enabled or 0
650 */
651 int mnt_context_is_verbose(struct libmnt_context *cxt)
652 {
653 return cxt->flags & MNT_FL_VERBOSE ? 1 : 0;
654 }
655
656 /**
657 * mnt_context_enable_loopdel:
658 * @cxt: mount context
659 * @enable: TRUE or FALSE
660 *
661 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
662 *
663 * Returns: 0 on success, negative number in case of error.
664 */
665 int mnt_context_enable_loopdel(struct libmnt_context *cxt, int enable)
666 {
667 return set_flag(cxt, MNT_FL_LOOPDEL, enable);
668 }
669
670 /**
671 * mnt_context_is_loopdel:
672 * @cxt: mount context
673 *
674 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
675 */
676 int mnt_context_is_loopdel(struct libmnt_context *cxt)
677 {
678 return cxt->flags & MNT_FL_LOOPDEL ? 1 : 0;
679 }
680
681 /**
682 * mnt_context_set_fs:
683 * @cxt: mount context
684 * @fs: filesystem description
685 *
686 * The mount context uses private @fs by default. This function allows to
687 * overwrite the private @fs with an external instance. This function
688 * increments @fs reference counter (and deincrement reference counter of the
689 * old fs).
690 *
691 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
692 * functions, If the @fs is NULL, then all current FS specific settings (source,
693 * target, etc., exclude spec) are reset.
694 *
695 * Returns: 0 on success, negative number in case of error.
696 */
697 int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
698 {
699 if (!cxt)
700 return -EINVAL;
701
702 mnt_ref_fs(fs); /* new */
703 mnt_unref_fs(cxt->fs); /* old */
704 cxt->fs = fs;
705 return 0;
706 }
707
708 /**
709 * mnt_context_get_fs:
710 * @cxt: mount context
711 *
712 * The FS contains the basic description of mountpoint, fs type and so on.
713 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
714 * functions.
715 *
716 * Returns: pointer to FS description or NULL in case of a calloc() error.
717 */
718 struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
719 {
720 assert(cxt);
721 if (!cxt)
722 return NULL;
723 if (!cxt->fs)
724 cxt->fs = mnt_new_fs();
725 return cxt->fs;
726 }
727
728 /**
729 * mnt_context_get_fs_userdata:
730 * @cxt: mount context
731 *
732 * Returns: pointer to userdata or NULL.
733 */
734 void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
735 {
736 assert(cxt);
737 return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
738 }
739
740 /**
741 * mnt_context_get_fstab_userdata:
742 * @cxt: mount context
743 *
744 * Returns: pointer to userdata or NULL.
745 */
746 void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
747 {
748 assert(cxt);
749 return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
750 }
751
752 /**
753 * mnt_context_get_mtab_userdata:
754 * @cxt: mount context
755 *
756 * Returns: pointer to userdata or NULL.
757 */
758 void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
759 {
760 assert(cxt);
761 return cxt->mtab ? mnt_table_get_userdata(cxt->mtab) : NULL;
762 }
763
764 /**
765 * mnt_context_set_source:
766 * @cxt: mount context
767 * @source: mount source (device, directory, UUID, LABEL, ...)
768 *
769 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
770 * mount option. The real return code is always returned, when
771 * the device does not exist then it's usually MNT_ERR_NOSOURCE
772 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from moun(2).
773 *
774 * Returns: 0 on success, negative number in case of error.
775 */
776 int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
777 {
778 assert(cxt);
779 return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
780 }
781
782 /**
783 * mnt_context_get_source:
784 * @cxt: mount context
785 *
786 * Returns: returns pointer or NULL in case of error or if not set.
787 */
788 const char *mnt_context_get_source(struct libmnt_context *cxt)
789 {
790 assert(cxt);
791 return mnt_fs_get_source(mnt_context_get_fs(cxt));
792 }
793
794 /**
795 * mnt_context_set_target:
796 * @cxt: mount context
797 * @target: mountpoint
798 *
799 * Returns: 0 on success, negative number in case of error.
800 */
801 int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
802 {
803 assert(cxt);
804 return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
805 }
806
807 /**
808 * mnt_context_get_target:
809 * @cxt: mount context
810 *
811 * Returns: returns pointer or NULL in case of error or if not set.
812 */
813 const char *mnt_context_get_target(struct libmnt_context *cxt)
814 {
815 assert(cxt);
816 return mnt_fs_get_target(mnt_context_get_fs(cxt));
817 }
818
819 /**
820 * mnt_context_set_fstype:
821 * @cxt: mount context
822 * @fstype: filesystem type
823 *
824 * Note that the @fstype has to be a FS type. For patterns with
825 * comma-separated list of filesystems or for the "nofs" notation, use
826 * mnt_context_set_fstype_pattern().
827 *
828 * Returns: 0 on success, negative number in case of error.
829 */
830 int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
831 {
832 assert(cxt);
833 return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
834 }
835
836 /**
837 * mnt_context_get_fstype:
838 * @cxt: mount context
839 *
840 * Returns: pointer or NULL in case of error or if not set.
841 */
842 const char *mnt_context_get_fstype(struct libmnt_context *cxt)
843 {
844 assert(cxt);
845 return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
846 }
847
848 /**
849 * mnt_context_set_options:
850 * @cxt: mount context
851 * @optstr: comma delimited mount options
852 *
853 * Returns: 0 on success, negative number in case of error.
854 */
855 int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
856 {
857 assert(cxt);
858 return mnt_fs_set_options(mnt_context_get_fs(cxt), optstr);
859 }
860
861 /**
862 * mnt_context_append_options:
863 * @cxt: mount context
864 * @optstr: comma delimited mount options
865 *
866 * Returns: 0 on success, negative number in case of error.
867 */
868 int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
869 {
870 assert(cxt);
871 return mnt_fs_append_options(mnt_context_get_fs(cxt), optstr);
872 }
873
874 /**
875 * mnt_context_get_options:
876 * @cxt: mount context
877 *
878 * This function returns mount options set by mnt_context_set_options() or
879 * mnt_context_append_options().
880 *
881 * Note that *after* mnt_context_prepare_mount(), the mount options string
882 * may also include options set by mnt_context_set_mflags() or other options
883 * generated by this library.
884 *
885 * Returns: pointer or NULL
886 */
887 const char *mnt_context_get_options(struct libmnt_context *cxt)
888 {
889 assert(cxt);
890 return mnt_fs_get_options(mnt_context_get_fs(cxt));
891 }
892
893 /**
894 * mnt_context_set_fstype_pattern:
895 * @cxt: mount context
896 * @pattern: FS name pattern (or NULL to reset the current setting)
897 *
898 * See mount(8), option -t.
899 *
900 * Returns: 0 on success, negative number in case of error.
901 */
902 int mnt_context_set_fstype_pattern(struct libmnt_context *cxt, const char *pattern)
903 {
904 char *p = NULL;
905
906 assert(cxt);
907 if (!cxt)
908 return -EINVAL;
909 if (pattern) {
910 p = strdup(pattern);
911 if (!p)
912 return -ENOMEM;
913 }
914 free(cxt->fstype_pattern);
915 cxt->fstype_pattern = p;
916 return 0;
917 }
918
919 /**
920 * mnt_context_set_options_pattern:
921 * @cxt: mount context
922 * @pattern: options pattern (or NULL to reset the current setting)
923 *
924 * See mount(8), option -O.
925 *
926 * Returns: 0 on success, negative number in case of error.
927 */
928 int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *pattern)
929 {
930 char *p = NULL;
931
932 assert(cxt);
933 if (!cxt)
934 return -EINVAL;
935 if (pattern) {
936 p = strdup(pattern);
937 if (!p)
938 return -ENOMEM;
939 }
940 free(cxt->optstr_pattern);
941 cxt->optstr_pattern = p;
942 return 0;
943 }
944
945 /**
946 * mnt_context_set_fstab:
947 * @cxt: mount context
948 * @tb: fstab
949 *
950 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
951 * This function allows to overwrite the private fstab with an external
952 * instance.
953 *
954 * This function modify the @tb reference counter. This function does not set
955 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
956 * mnt_context_get_cache(cxt));
957 *
958 * The fstab is used read-only and is not modified, it should be possible to
959 * share the fstab between more mount contexts (TODO: test it.)
960 *
961 * If the @tb argument is NULL, then the current private fstab instance is
962 * reset.
963 *
964 * Returns: 0 on success, negative number in case of error.
965 */
966 int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
967 {
968 assert(cxt);
969 if (!cxt)
970 return -EINVAL;
971
972 mnt_ref_table(tb); /* new */
973 mnt_unref_table(cxt->fstab); /* old */
974
975 cxt->fstab = tb;
976 return 0;
977 }
978
979 /**
980 * mnt_context_get_fstab:
981 * @cxt: mount context
982 * @tb: returns fstab
983 *
984 * See also mnt_table_parse_fstab() for more details about fstab.
985 *
986 * Returns: 0 on success, negative number in case of error.
987 */
988 int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
989 {
990 assert(cxt);
991 if (!cxt)
992 return -EINVAL;
993 if (!cxt->fstab) {
994 int rc;
995
996 cxt->fstab = mnt_new_table();
997 if (!cxt->fstab)
998 return -ENOMEM;
999 if (cxt->table_errcb)
1000 mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
1001 mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
1002 rc = mnt_table_parse_fstab(cxt->fstab, NULL);
1003 if (rc)
1004 return rc;
1005 }
1006
1007 if (tb)
1008 *tb = cxt->fstab;
1009 return 0;
1010 }
1011
1012 /**
1013 * mnt_context_get_mtab:
1014 * @cxt: mount context
1015 * @tb: returns mtab
1016 *
1017 * See also mnt_table_parse_mtab() for more details about mtab/mountinfo. The
1018 * result will be deallocated by mnt_free_context(@cxt).
1019 *
1020 * Returns: 0 on success, negative number in case of error.
1021 */
1022 int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
1023 {
1024 assert(cxt);
1025 if (!cxt)
1026 return -EINVAL;
1027 if (!cxt->mtab) {
1028 int rc;
1029
1030 context_init_paths(cxt, 0);
1031
1032 cxt->mtab = mnt_new_table();
1033 if (!cxt->mtab)
1034 return -ENOMEM;
1035
1036 if (cxt->table_errcb)
1037 mnt_table_set_parser_errcb(cxt->mtab, cxt->table_errcb);
1038 if (cxt->table_fltrcb)
1039 mnt_table_set_parser_fltrcb(cxt->mtab,
1040 cxt->table_fltrcb,
1041 cxt->table_fltrcb_data);
1042
1043 mnt_table_set_cache(cxt->mtab, mnt_context_get_cache(cxt));
1044 if (cxt->utab)
1045 /* utab already parsed, don't parse it again */
1046 rc = __mnt_table_parse_mtab(cxt->mtab,
1047 cxt->mtab_path, cxt->utab);
1048 else
1049 rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
1050 if (rc)
1051 return rc;
1052 }
1053
1054 if (tb)
1055 *tb = cxt->mtab;
1056
1057 DBG(CXT, ul_debugobj(cxt, "mtab requested [nents=%d]",
1058 mnt_table_get_nents(cxt->mtab)));
1059 return 0;
1060 }
1061
1062 /*
1063 * Allows to specify a filter for tab file entries. The filter is called by
1064 * the table parser. Currently used for mtab and utab only.
1065 */
1066 int mnt_context_set_tabfilter(struct libmnt_context *cxt,
1067 int (*fltr)(struct libmnt_fs *, void *),
1068 void *data)
1069 {
1070 assert(cxt);
1071 if (!cxt)
1072 return -EINVAL;
1073
1074 cxt->table_fltrcb = fltr;
1075 cxt->table_fltrcb_data = data;
1076
1077 if (cxt->mtab)
1078 mnt_table_set_parser_fltrcb(cxt->mtab,
1079 cxt->table_fltrcb,
1080 cxt->table_fltrcb_data);
1081
1082 DBG(CXT, ul_debugobj(cxt, "tabfilter %s", fltr ? "ENABLED!" : "disabled"));
1083 return 0;
1084 }
1085
1086 /**
1087 * mnt_context_get_table:
1088 * @cxt: mount context
1089 * @filename: e.g. /proc/self/mountinfo
1090 * @tb: returns the table
1091 *
1092 * This function allocates a new table and parses the @file. The parser error
1093 * callback and cache for tags and paths is set according to the @cxt setting.
1094 * See also mnt_table_parse_file().
1095 *
1096 * It's strongly recommended to use the mnt_context_get_mtab() and
1097 * mnt_context_get_fstab() functions for mtab and fstab files. This function
1098 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1099 * options.
1100 *
1101 * The result will NOT be deallocated by mnt_free_context(@cxt).
1102 *
1103 * Returns: 0 on success, negative number in case of error.
1104 */
1105 int mnt_context_get_table(struct libmnt_context *cxt,
1106 const char *filename, struct libmnt_table **tb)
1107 {
1108 int rc;
1109
1110 assert(cxt);
1111 assert(tb);
1112 if (!cxt || !tb)
1113 return -EINVAL;
1114
1115 *tb = mnt_new_table();
1116 if (!*tb)
1117 return -ENOMEM;
1118
1119 if (cxt->table_errcb)
1120 mnt_table_set_parser_errcb(*tb, cxt->table_errcb);
1121
1122 rc = mnt_table_parse_file(*tb, filename);
1123 if (rc) {
1124 mnt_unref_table(*tb);
1125 return rc;
1126 }
1127
1128 mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
1129 return 0;
1130 }
1131
1132 /**
1133 * mnt_context_set_tables_errcb
1134 * @cxt: mount context
1135 * @cb: pointer to callback function
1136 *
1137 * The error callback is used for all tab files (e.g. mtab, fstab)
1138 * parsed within the context.
1139 *
1140 * See also mnt_context_get_mtab(),
1141 * mnt_context_get_fstab(),
1142 * mnt_table_set_parser_errcb().
1143 *
1144 * Returns: 0 on success, negative number in case of error.
1145 */
1146 int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
1147 int (*cb)(struct libmnt_table *tb, const char *filename, int line))
1148 {
1149 assert(cxt);
1150 if (!cxt)
1151 return -EINVAL;
1152
1153 if (cxt->mtab)
1154 mnt_table_set_parser_errcb(cxt->mtab, cb);
1155 if (cxt->fstab)
1156 mnt_table_set_parser_errcb(cxt->fstab, cb);
1157
1158 cxt->table_errcb = cb;
1159 return 0;
1160 }
1161
1162 /**
1163 * mnt_context_set_cache:
1164 * @cxt: mount context
1165 * @cache: cache instance or nULL
1166 *
1167 * The mount context maintains a private struct libmnt_cache by default. This
1168 * function allows to overwrite the private cache with an external instance.
1169 * This function increments cache reference counter.
1170 *
1171 * If the @cache argument is NULL, then the current cache instance is reset.
1172 * This function apply the cache to fstab and mtab instances (if already
1173 * exists).
1174 *
1175 * The old cache instance reference counter is de-incremented.
1176 *
1177 * Returns: 0 on success, negative number in case of error.
1178 */
1179 int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache)
1180 {
1181 if (!cxt)
1182 return -EINVAL;
1183
1184 mnt_ref_cache(cache); /* new */
1185 mnt_unref_cache(cxt->cache); /* old */
1186
1187 cxt->cache = cache;
1188
1189 if (cxt->mtab)
1190 mnt_table_set_cache(cxt->mtab, cache);
1191 if (cxt->fstab)
1192 mnt_table_set_cache(cxt->fstab, cache);
1193
1194 return 0;
1195 }
1196
1197 /**
1198 * mnt_context_get_cache
1199 * @cxt: mount context
1200 *
1201 * See also mnt_context_set_cache().
1202 *
1203 * Returns: pointer to cache or NULL if canonicalization is disabled.
1204 */
1205 struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
1206 {
1207 assert(cxt);
1208 if (!cxt || mnt_context_is_nocanonicalize(cxt))
1209 return NULL;
1210
1211 if (!cxt->cache) {
1212 struct libmnt_cache *cache = mnt_new_cache();
1213 mnt_context_set_cache(cxt, cache);
1214 mnt_unref_cache(cache);
1215 }
1216 return cxt->cache;
1217 }
1218
1219 /**
1220 * mnt_context_set_passwd_cb:
1221 * @cxt: mount context
1222 * @get: callback to get password
1223 * @release: callback to release (delallocate) password
1224 *
1225 * Sets callbacks for encryption password (e.g encrypted loopdev). This
1226 * function is deprecated (encrypted loops are no longer supported).
1227 *
1228 * Returns: 0 on success, negative number in case of error.
1229 */
1230 int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
1231 char *(*get)(struct libmnt_context *),
1232 void (*release)(struct libmnt_context *, char *))
1233 {
1234 assert(cxt);
1235 if (!cxt)
1236 return -EINVAL;
1237 cxt->pwd_get_cb = get;
1238 cxt->pwd_release_cb = release;
1239 return 0;
1240 }
1241
1242 /**
1243 * mnt_context_get_lock:
1244 * @cxt: mount context
1245 *
1246 * The libmount applications don't have to care about mtab locking, but with a
1247 * small exception: the application has to be able to remove the lock file when
1248 * interrupted by signal or signals have to be ignored when the lock is locked.
1249 *
1250 * The default behavior is to ignore all signals (except SIGALRM and
1251 * SIGTRAP for mtab udate) when the lock is locked. If this behavior
1252 * is unacceptable, then use:
1253 *
1254 * lc = mnt_context_get_lock(cxt);
1255 * if (lc)
1256 * mnt_lock_block_signals(lc, FALSE);
1257 *
1258 * and don't forget to call mnt_unlock_file(lc) before exit.
1259 *
1260 * Returns: pointer to lock struct or NULL.
1261 */
1262 struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
1263 {
1264 assert(cxt);
1265 /*
1266 * DON'T call this function within libmount, it will always allocate
1267 * the lock. The mnt_update_* functions are able to allocate the lock
1268 * only when mtab/utab update is really necessary.
1269 */
1270 if (!cxt || mnt_context_is_nomtab(cxt))
1271 return NULL;
1272
1273 if (!cxt->lock) {
1274 cxt->lock = mnt_new_lock(
1275 mnt_context_get_writable_tabpath(cxt), 0);
1276 if (cxt->lock)
1277 mnt_lock_block_signals(cxt->lock, TRUE);
1278 }
1279 return cxt->lock;
1280 }
1281
1282 /**
1283 * mnt_context_set_mflags:
1284 * @cxt: mount context
1285 * @flags: mount(2) flags (MS_* flags)
1286 *
1287 * Sets mount flags (see mount(2) man page).
1288 *
1289 * Note that mount context allows to define mount options by mount flags. It
1290 * means you can for example use
1291 *
1292 * mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
1293 *
1294 * rather than
1295 *
1296 * mnt_context_set_options(cxt, "noexec,nosuid");
1297 *
1298 * both of these calls have the same effect.
1299 *
1300 * Returns: 0 on success, negative number in case of error.
1301 */
1302 int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
1303 {
1304 assert(cxt);
1305 if (!cxt)
1306 return -EINVAL;
1307
1308 cxt->mountflags = flags;
1309
1310 if ((cxt->flags & MNT_FL_MOUNTOPTS_FIXED) && cxt->fs)
1311 /*
1312 * the final mount options are already generated, refresh...
1313 */
1314 return mnt_optstr_apply_flags(
1315 &cxt->fs->vfs_optstr,
1316 cxt->mountflags,
1317 mnt_get_builtin_optmap(MNT_LINUX_MAP));
1318
1319 return 0;
1320 }
1321
1322 /**
1323 * mnt_context_get_mflags:
1324 * @cxt: mount context
1325 * @flags: returns MS_* mount flags
1326 *
1327 * Converts mount options string to MS_* flags and bitewise-OR the result with
1328 * the already defined flags (see mnt_context_set_mflags()).
1329 *
1330 * Returns: 0 on success, negative number in case of error.
1331 */
1332 int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
1333 {
1334 int rc = 0;
1335 struct list_head *p;
1336
1337 assert(cxt);
1338 assert(flags);
1339 if (!cxt || !flags)
1340 return -EINVAL;
1341
1342 *flags = 0;
1343 if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1344 const char *o = mnt_fs_get_options(cxt->fs);
1345 if (o)
1346 rc = mnt_optstr_get_flags(o, flags,
1347 mnt_get_builtin_optmap(MNT_LINUX_MAP));
1348 }
1349
1350 list_for_each(p, &cxt->addmounts) {
1351 struct libmnt_addmount *ad =
1352 list_entry(p, struct libmnt_addmount, mounts);
1353
1354 *flags |= ad->mountflags;
1355 }
1356
1357 if (!rc)
1358 *flags |= cxt->mountflags;
1359 return rc;
1360 }
1361
1362 /**
1363 * mnt_context_set_user_mflags:
1364 * @cxt: mount context
1365 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1366 *
1367 * Sets userspace mount flags.
1368 *
1369 * See also notes for mnt_context_set_mflags().
1370 *
1371 * Returns: 0 on success, negative number in case of error.
1372 */
1373 int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
1374 {
1375 assert(cxt);
1376 if (!cxt)
1377 return -EINVAL;
1378 cxt->user_mountflags = flags;
1379 return 0;
1380 }
1381
1382 /**
1383 * mnt_context_get_user_mflags:
1384 * @cxt: mount context
1385 * @flags: returns mount flags
1386 *
1387 * Converts mount options string to MNT_MS_* flags and bitewise-OR the result
1388 * with the already defined flags (see mnt_context_set_user_mflags()).
1389 *
1390 * Returns: 0 on success, negative number in case of error.
1391 */
1392 int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
1393 {
1394 int rc = 0;
1395
1396 assert(cxt);
1397 assert(flags);
1398 if (!cxt || !flags)
1399 return -EINVAL;
1400
1401 *flags = 0;
1402 if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1403 const char *o = mnt_fs_get_user_options(cxt->fs);
1404 if (o)
1405 rc = mnt_optstr_get_flags(o, flags,
1406 mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
1407 }
1408 if (!rc)
1409 *flags |= cxt->user_mountflags;
1410 return rc;
1411 }
1412
1413 /**
1414 * mnt_context_set_mountdata:
1415 * @cxt: mount context
1416 * @data: mount(2) data
1417 *
1418 * The mount context generates mountdata from mount options by default. This
1419 * function allows to overwrite this behavior, and @data will be used instead
1420 * of mount options.
1421 *
1422 * The libmount does not deallocate the data by mnt_free_context(). Note that
1423 * NULL is also valid mount data.
1424 *
1425 * Returns: 0 on success, negative number in case of error.
1426 */
1427 int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
1428 {
1429 assert(cxt);
1430 if (!cxt)
1431 return -EINVAL;
1432 cxt->mountdata = data;
1433 cxt->flags |= MNT_FL_MOUNTDATA;
1434 return 0;
1435 }
1436
1437 /*
1438 * Translates LABEL/UUID/path to mountable path
1439 */
1440 int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
1441 {
1442 const char *path = NULL;
1443 struct libmnt_cache *cache;
1444 const char *t, *v, *src;
1445 int rc = 0;
1446
1447 assert(cxt);
1448 assert(cxt->fs);
1449 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1450
1451 if (!cxt || !cxt->fs)
1452 return -EINVAL;
1453
1454 DBG(CXT, ul_debugobj(cxt, "preparing source path"));
1455
1456 src = mnt_fs_get_source(cxt->fs);
1457
1458 if (!src && mnt_context_propagation_only(cxt))
1459 /* mount --make-{shared,private,...} */
1460 return mnt_fs_set_source(cxt->fs, "none");
1461
1462 /* ignore filesystems without source or filesystems
1463 * where the source is a quasi-path (//foo/bar)
1464 */
1465 if (!src || mnt_fs_is_netfs(cxt->fs))
1466 return 0;
1467
1468 DBG(CXT, ul_debugobj(cxt, "srcpath '%s'", src));
1469
1470 cache = mnt_context_get_cache(cxt);
1471
1472 if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
1473 /*
1474 * Source is TAG (evaluate)
1475 */
1476 if (cache)
1477 path = mnt_resolve_tag(t, v, cache);
1478
1479 rc = path ? mnt_fs_set_source(cxt->fs, path) : -MNT_ERR_NOSOURCE;
1480
1481 } else if (cache && !mnt_fs_is_pseudofs(cxt->fs)) {
1482 /*
1483 * Source is PATH (canonicalize)
1484 */
1485 path = mnt_resolve_path(src, cache);
1486 if (path && strcmp(path, src))
1487 rc = mnt_fs_set_source(cxt->fs, path);
1488 }
1489
1490 if (rc) {
1491 DBG(CXT, ul_debugobj(cxt, "failed to prepare srcpath [rc=%d]", rc));
1492 return rc;
1493 }
1494
1495 if (!path)
1496 path = src;
1497
1498 if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_REMOUNT))
1499 || mnt_fs_is_pseudofs(cxt->fs)) {
1500 DBG(CXT, ul_debugobj(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
1501 return rc;
1502 }
1503
1504 /*
1505 * Initialize loop device
1506 */
1507 if (mnt_context_is_loopdev(cxt)) {
1508 rc = mnt_context_setup_loopdev(cxt);
1509 if (rc)
1510 return rc;
1511 }
1512
1513 DBG(CXT, ul_debugobj(cxt, "final srcpath '%s'",
1514 mnt_fs_get_source(cxt->fs)));
1515 return 0;
1516 }
1517
1518 /* create a mountpoint if x-mount.mkdir[=<mode>] specified */
1519 static int mkdir_target(const char *tgt, struct libmnt_fs *fs)
1520 {
1521 char *mstr = NULL;
1522 size_t mstr_sz = 0;
1523 mode_t mode = 0;
1524 struct stat st;
1525 int rc;
1526
1527 assert(tgt);
1528 assert(fs);
1529
1530 if (mnt_optstr_get_option(fs->user_optstr, "x-mount.mkdir", &mstr, &mstr_sz) != 0)
1531 return 0;
1532 if (stat(tgt, &st) == 0)
1533 return 0;
1534
1535 if (mstr && mstr_sz) {
1536 char *end = NULL;
1537
1538 errno = 0;
1539 mode = strtol(mstr, &end, 8);
1540
1541 if (errno || !end || mstr + mstr_sz != end) {
1542 DBG(CXT, ul_debug("failed to parse mkdir mode '%s'", mstr));
1543 return -MNT_ERR_MOUNTOPT;
1544 }
1545 }
1546
1547 if (!mode)
1548 mode = S_IRWXU | /* 0755 */
1549 S_IRGRP | S_IXGRP |
1550 S_IROTH | S_IXOTH;
1551
1552 rc = mkdir_p(tgt, mode);
1553 if (rc)
1554 DBG(CXT, ul_debug("mkdir %s failed: %m", tgt));
1555
1556 return rc;
1557 }
1558
1559 int mnt_context_prepare_target(struct libmnt_context *cxt)
1560 {
1561 const char *tgt;
1562 struct libmnt_cache *cache;
1563 int rc = 0;
1564
1565 assert(cxt);
1566 assert(cxt->fs);
1567 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1568
1569 if (!cxt || !cxt->fs)
1570 return -EINVAL;
1571
1572 DBG(CXT, ul_debugobj(cxt, "preparing target path"));
1573
1574 tgt = mnt_fs_get_target(cxt->fs);
1575 if (!tgt)
1576 return 0;
1577
1578 /* mkdir target */
1579 if (cxt->action == MNT_ACT_MOUNT
1580 && !mnt_context_is_restricted(cxt)
1581 && cxt->user_mountflags & MNT_MS_XCOMMENT) {
1582
1583 rc = mkdir_target(tgt, cxt->fs);
1584 if (rc)
1585 return rc; /* mkdir or parse error */
1586 }
1587
1588 /* canonicalize the path */
1589 cache = mnt_context_get_cache(cxt);
1590 if (cache) {
1591 char *path = mnt_resolve_path(tgt, cache);
1592 if (path && strcmp(path, tgt) != 0)
1593 rc = mnt_fs_set_target(cxt->fs, path);
1594 }
1595
1596 if (rc)
1597 DBG(CXT, ul_debugobj(cxt, "failed to prepare target '%s'", tgt));
1598 else
1599 DBG(CXT, ul_debugobj(cxt, "final target '%s'",
1600 mnt_fs_get_target(cxt->fs)));
1601 return 0;
1602 }
1603
1604 /* Guess type, but not set to cxt->fs, use free() for the result. It's no error
1605 * when we're not able to guess a filesystem type.
1606 */
1607 int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type)
1608 {
1609 int rc = 0;
1610 const char *dev = mnt_fs_get_srcpath(cxt->fs);
1611
1612 *type = NULL;
1613
1614 if (!dev)
1615 goto done;
1616
1617 if (access(dev, F_OK) == 0) {
1618 struct libmnt_cache *cache = mnt_context_get_cache(cxt);
1619 int ambi = 0;
1620
1621 *type = mnt_get_fstype(dev, &ambi, cache);
1622 if (cache && *type)
1623 *type = strdup(*type);
1624 if (ambi)
1625 rc = -MNT_ERR_AMBIFS;
1626 } else {
1627 DBG(CXT, ul_debugobj(cxt, "access(%s) failed [%m]", dev));
1628 if (strchr(dev, ':') != NULL)
1629 *type = strdup("nfs");
1630 else if (!strncmp(dev, "//", 2))
1631 *type = strdup("cifs");
1632 }
1633
1634 done:
1635 return rc;
1636 }
1637
1638 /*
1639 * It's usually no error when we're not able to detect the filesystem type -- we
1640 * will try to use the types from /{etc,proc}/filesystems.
1641 */
1642 int mnt_context_guess_fstype(struct libmnt_context *cxt)
1643 {
1644 char *type;
1645 int rc = 0;
1646
1647 assert(cxt);
1648 assert(cxt->fs);
1649 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1650
1651 if (!cxt || !cxt->fs)
1652 return -EINVAL;
1653
1654 if ((cxt->mountflags & (MS_BIND | MS_MOVE))
1655 || mnt_context_propagation_only(cxt))
1656 goto none;
1657
1658 type = (char *) mnt_fs_get_fstype(cxt->fs);
1659 if (type && !strcmp(type, "auto")) {
1660 mnt_fs_set_fstype(cxt->fs, NULL);
1661 type = NULL;
1662 }
1663
1664 if (type)
1665 goto done;
1666 if (cxt->flags & MS_REMOUNT)
1667 goto none;
1668 if (cxt->fstype_pattern)
1669 goto done;
1670
1671 rc = mnt_context_guess_srcpath_fstype(cxt, &type);
1672 if (rc == 0 && type)
1673 __mnt_fs_set_fstype_ptr(cxt->fs, type);
1674 else
1675 free(type);
1676 done:
1677 DBG(CXT, ul_debugobj(cxt, "FS type: %s [rc=%d]",
1678 mnt_fs_get_fstype(cxt->fs), rc));
1679 return rc;
1680 none:
1681 return mnt_fs_set_fstype(cxt->fs, "none");
1682 }
1683
1684 /*
1685 * The default is to use fstype from cxt->fs, this could be overwritten by
1686 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
1687 *
1688 * Returns: 0 on success or negative number in case of error. Note that success
1689 * does not mean that there is any usable helper, you have to check cxt->helper.
1690 */
1691 int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
1692 const char *type)
1693 {
1694 char search_path[] = FS_SEARCH_PATH; /* from config.h */
1695 char *p = NULL, *path;
1696
1697 assert(cxt);
1698 assert(cxt->fs);
1699 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1700
1701 if (!type)
1702 type = mnt_fs_get_fstype(cxt->fs);
1703
1704 if (type && strchr(type, ','))
1705 return 0; /* type is fstype pattern */
1706
1707 if (mnt_context_is_nohelpers(cxt)
1708 || !type
1709 || !strcmp(type, "none")
1710 || strstr(type, "/..") /* don't try to smuggle path */
1711 || mnt_fs_is_swaparea(cxt->fs))
1712 return 0;
1713
1714 path = strtok_r(search_path, ":", &p);
1715 while (path) {
1716 char helper[PATH_MAX];
1717 struct stat st;
1718 int rc;
1719
1720 rc = snprintf(helper, sizeof(helper), "%s/%s.%s",
1721 path, name, type);
1722 path = strtok_r(NULL, ":", &p);
1723
1724 if (rc < 0 || (size_t) rc >= sizeof(helper))
1725 continue;
1726
1727 rc = stat(helper, &st);
1728 if (rc == -1 && errno == ENOENT && strchr(type, '.')) {
1729 /* If type ends with ".subtype" try without it */
1730 char *hs = strrchr(helper, '.');
1731 if (hs)
1732 *hs = '\0';
1733 rc = stat(helper, &st);
1734 }
1735
1736 DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
1737 rc ? "not found" : "found"));
1738 if (rc)
1739 continue;
1740
1741 free(cxt->helper);
1742 cxt->helper = strdup(helper);
1743 if (!cxt->helper)
1744 return -ENOMEM;
1745 return 0;
1746 }
1747
1748 return 0;
1749 }
1750
1751 int mnt_context_merge_mflags(struct libmnt_context *cxt)
1752 {
1753 unsigned long fl = 0;
1754 int rc;
1755
1756 assert(cxt);
1757
1758 DBG(CXT, ul_debugobj(cxt, "merging mount flags"));
1759
1760 rc = mnt_context_get_mflags(cxt, &fl);
1761 if (rc)
1762 return rc;
1763 cxt->mountflags = fl;
1764
1765 fl = 0;
1766 rc = mnt_context_get_user_mflags(cxt, &fl);
1767 if (rc)
1768 return rc;
1769 cxt->user_mountflags = fl;
1770
1771 DBG(CXT, ul_debugobj(cxt, "final flags: VFS=%08lx user=%08lx",
1772 cxt->mountflags, cxt->user_mountflags));
1773
1774 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
1775 return 0;
1776 }
1777
1778 /*
1779 * Prepare /etc/mtab or /run/mount/utab
1780 */
1781 int mnt_context_prepare_update(struct libmnt_context *cxt)
1782 {
1783 int rc;
1784 const char *target;
1785
1786 assert(cxt);
1787 assert(cxt->fs);
1788 assert(cxt->action);
1789 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1790
1791 DBG(CXT, ul_debugobj(cxt, "prepare update"));
1792
1793 if (mnt_context_propagation_only(cxt)) {
1794 DBG(CXT, ul_debugobj(cxt, "skip update: only MS_PROPAGATION"));
1795 return 0;
1796 }
1797
1798 target = mnt_fs_get_target(cxt->fs);
1799
1800 if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/"))
1801 /* Don't try to touch mtab if umounting root FS */
1802 mnt_context_disable_mtab(cxt, TRUE);
1803
1804 if (mnt_context_is_nomtab(cxt)) {
1805 DBG(CXT, ul_debugobj(cxt, "skip update: NOMTAB flag"));
1806 return 0;
1807 }
1808 if (!mnt_context_get_writable_tabpath(cxt)) {
1809 DBG(CXT, ul_debugobj(cxt, "skip update: no writable destination"));
1810 return 0;
1811 }
1812 /* 0 = success, 1 = not called yet */
1813 if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
1814 DBG(CXT, ul_debugobj(cxt,
1815 "skip update: syscall failed [status=%d]",
1816 cxt->syscall_status));
1817 return 0;
1818 }
1819
1820 if (!cxt->update) {
1821 const char *name = mnt_context_get_writable_tabpath(cxt);
1822
1823 if (cxt->action == MNT_ACT_UMOUNT && is_file_empty(name)) {
1824 DBG(CXT, ul_debugobj(cxt,
1825 "skip update: umount, no table"));
1826 return 0;
1827 }
1828
1829 cxt->update = mnt_new_update();
1830 if (!cxt->update)
1831 return -ENOMEM;
1832
1833 mnt_update_set_filename(cxt->update, name,
1834 !mnt_context_mtab_writable(cxt));
1835 }
1836
1837 if (cxt->action == MNT_ACT_UMOUNT)
1838 rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1839 mnt_context_get_target(cxt), NULL);
1840 else
1841 rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1842 NULL, cxt->fs);
1843
1844 return rc < 0 ? rc : 0;
1845 }
1846
1847 int mnt_context_update_tabs(struct libmnt_context *cxt)
1848 {
1849 unsigned long fl;
1850
1851 assert(cxt);
1852
1853 if (mnt_context_is_nomtab(cxt)) {
1854 DBG(CXT, ul_debugobj(cxt, "don't update: NOMTAB flag"));
1855 return 0;
1856 }
1857 if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
1858 DBG(CXT, ul_debugobj(cxt, "don't update: no update prepared"));
1859 return 0;
1860 }
1861
1862 /* check utab update when external helper executed */
1863 if (mnt_context_helper_executed(cxt)
1864 && mnt_context_get_helper_status(cxt) == 0
1865 && mnt_context_utab_writable(cxt)) {
1866
1867 if (mnt_update_already_done(cxt->update, cxt->lock)) {
1868 DBG(CXT, ul_debugobj(cxt, "don't update: error evaluate or already updated"));
1869 return 0;
1870 }
1871 } else if (cxt->helper) {
1872 DBG(CXT, ul_debugobj(cxt, "don't update: external helper"));
1873 return 0;
1874 }
1875
1876 if (cxt->syscall_status != 0
1877 && !(mnt_context_helper_executed(cxt) &&
1878 mnt_context_get_helper_status(cxt) == 0)) {
1879
1880 DBG(CXT, ul_debugobj(cxt, "don't update: syscall/helper failed/not called"));
1881 return 0;
1882 }
1883
1884 fl = mnt_update_get_mflags(cxt->update);
1885 if ((cxt->mountflags & MS_RDONLY) != (fl & MS_RDONLY))
1886 /*
1887 * fix MS_RDONLY in options
1888 */
1889 mnt_update_force_rdonly(cxt->update,
1890 cxt->mountflags & MS_RDONLY);
1891
1892 return mnt_update_table(cxt->update, cxt->lock);
1893 }
1894
1895 static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
1896 int direction)
1897 {
1898 struct libmnt_fs *fs = NULL;
1899 const char *src = NULL, *tgt = NULL;
1900 int rc;
1901
1902 assert(cxt);
1903 assert(cxt->fs);
1904
1905 if (!cxt->fs)
1906 return -EINVAL;
1907
1908 src = mnt_fs_get_source(cxt->fs);
1909 tgt = mnt_fs_get_target(cxt->fs);
1910
1911 if (tgt && src)
1912 fs = mnt_table_find_pair(tb, src, tgt, direction);
1913 else {
1914 if (src)
1915 fs = mnt_table_find_source(tb, src, direction);
1916 else if (tgt)
1917 fs = mnt_table_find_target(tb, tgt, direction);
1918
1919 if (!fs && mnt_context_is_swapmatch(cxt)) {
1920 /* swap source and target (if @src is not LABEL/UUID),
1921 * for example in
1922 *
1923 * mount /foo/bar
1924 *
1925 * the path could be a mountpoint as well as a source (for
1926 * example bind mount, symlink to a device, ...).
1927 */
1928 if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
1929 fs = mnt_table_find_target(tb, src, direction);
1930 if (!fs && tgt)
1931 fs = mnt_table_find_source(tb, tgt, direction);
1932 }
1933 }
1934
1935 if (!fs)
1936 return -MNT_ERR_NOFSTAB; /* not found */
1937
1938 DBG(CXT, ul_debugobj(cxt, "apply entry:"));
1939 DBG(CXT, mnt_fs_print_debug(fs, stderr));
1940
1941 /* copy from tab to our FS description
1942 */
1943 rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
1944 if (!rc)
1945 rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
1946
1947 if (!rc && !mnt_fs_get_fstype(cxt->fs))
1948 rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
1949
1950 if (rc)
1951 return rc;
1952
1953 if (cxt->optsmode & MNT_OMODE_IGNORE)
1954 ;
1955 else if (cxt->optsmode & MNT_OMODE_REPLACE)
1956 rc = mnt_fs_set_options(cxt->fs, mnt_fs_get_options(fs));
1957
1958 else if (cxt->optsmode & MNT_OMODE_APPEND)
1959 rc = mnt_fs_append_options(cxt->fs, mnt_fs_get_options(fs));
1960
1961 else if (cxt->optsmode & MNT_OMODE_PREPEND)
1962 rc = mnt_fs_prepend_options(cxt->fs, mnt_fs_get_options(fs));
1963
1964 if (!rc)
1965 cxt->flags |= MNT_FL_TAB_APPLIED;
1966 return rc;
1967 }
1968
1969 /**
1970 * mnt_context_apply_fstab:
1971 * @cxt: mount context
1972 *
1973 * This function is optional.
1974 *
1975 * Returns: 0 on success, negative number in case of error.
1976 */
1977 int mnt_context_apply_fstab(struct libmnt_context *cxt)
1978 {
1979 int rc = -1;
1980 struct libmnt_table *tab = NULL;
1981 const char *src = NULL, *tgt = NULL;
1982
1983 assert(cxt);
1984 assert(cxt->fs);
1985
1986 if (!cxt)
1987 return -EINVAL;
1988
1989 if (mnt_context_tab_applied(cxt)) /* already applied */
1990 return 0;
1991
1992 if (mnt_context_is_restricted(cxt)) {
1993 DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
1994 cxt->optsmode = MNT_OMODE_USER;
1995 } else if (cxt->optsmode == 0) {
1996 DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
1997 cxt->optsmode = MNT_OMODE_AUTO;
1998 } else if (cxt->optsmode & MNT_OMODE_NOTAB) {
1999 cxt->optsmode &= ~MNT_OMODE_FSTAB;
2000 cxt->optsmode &= ~MNT_OMODE_MTAB;
2001 cxt->optsmode &= ~MNT_OMODE_FORCE;
2002 }
2003
2004 if (cxt->fs) {
2005 src = mnt_fs_get_source(cxt->fs);
2006 tgt = mnt_fs_get_target(cxt->fs);
2007 }
2008
2009 DBG(CXT, ul_debugobj(cxt, "OPTSMODE: ignore=%d, append=%d, prepend=%d, "
2010 "replace=%d, force=%d, fstab=%d, mtab=%d",
2011 cxt->optsmode & MNT_OMODE_IGNORE ? 1 : 0,
2012 cxt->optsmode & MNT_OMODE_APPEND ? 1 : 0,
2013 cxt->optsmode & MNT_OMODE_PREPEND ? 1 : 0,
2014 cxt->optsmode & MNT_OMODE_REPLACE ? 1 : 0,
2015 cxt->optsmode & MNT_OMODE_FORCE ? 1 : 0,
2016 cxt->optsmode & MNT_OMODE_FSTAB ? 1 : 0,
2017 cxt->optsmode & MNT_OMODE_MTAB ? 1 : 0));
2018
2019 /* fstab is not required if source and target are specified */
2020 if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
2021 DBG(CXT, ul_debugobj(cxt, "fstab not required -- skip"));
2022 return 0;
2023 }
2024
2025 if (!src && tgt
2026 && !(cxt->optsmode & MNT_OMODE_FSTAB)
2027 && !(cxt->optsmode & MNT_OMODE_MTAB)) {
2028 DBG(CXT, ul_debugobj(cxt, "only target; fstab/mtab not required "
2029 "-- skip, probably MS_PROPAGATION"));
2030 return 0;
2031 }
2032
2033 DBG(CXT, ul_debugobj(cxt,
2034 "trying to apply fstab (src=%s, target=%s)", src, tgt));
2035
2036 /* let's initialize cxt->fs */
2037 ignore_result( mnt_context_get_fs(cxt) );
2038
2039 /* try fstab */
2040 if (cxt->optsmode & MNT_OMODE_FSTAB) {
2041 rc = mnt_context_get_fstab(cxt, &tab);
2042 if (!rc)
2043 rc = apply_table(cxt, tab, MNT_ITER_FORWARD);
2044 }
2045
2046 /* try mtab */
2047 if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)) {
2048 DBG(CXT, ul_debugobj(cxt, "trying to apply from mtab"));
2049 rc = mnt_context_get_mtab(cxt, &tab);
2050 if (!rc)
2051 rc = apply_table(cxt, tab, MNT_ITER_BACKWARD);
2052 }
2053 if (rc)
2054 DBG(CXT, ul_debugobj(cxt, "failed to find entry in fstab/mtab"));
2055 return rc;
2056 }
2057
2058 /**
2059 * mnt_context_tab_applied:
2060 * @cxt: mount context
2061 *
2062 * Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
2063 */
2064 int mnt_context_tab_applied(struct libmnt_context *cxt)
2065 {
2066 assert(cxt);
2067 return cxt->flags & MNT_FL_TAB_APPLIED;
2068 }
2069
2070 /*
2071 * This is not a public function!
2072 *
2073 * Returns 1 if *only propagation flags* change is requested.
2074 */
2075 int mnt_context_propagation_only(struct libmnt_context *cxt)
2076 {
2077 assert(cxt);
2078 assert(cxt->fs);
2079
2080 if (cxt->action != MNT_ACT_MOUNT)
2081 return 0;
2082
2083 /* has to be called after context_mount.c: fix_opts() */
2084 assert((cxt->flags & MNT_FL_MOUNTOPTS_FIXED));
2085
2086 /* all propagation mounts are in cxt->addmount */
2087 return !list_empty(&cxt->addmounts)
2088 && (cxt->mountflags == 0 || cxt->mountflags == MS_SILENT)
2089 && cxt->fs
2090 && (!cxt->fs->fstype || strcmp(cxt->fs->fstype, "none") == 0)
2091 && (!cxt->fs->source || strcmp(cxt->fs->source, "none") == 0);
2092 }
2093
2094 /**
2095 * mnt_context_get_status:
2096 * @cxt: mount context
2097 *
2098 * Global libmount status.
2099 *
2100 * The real exit code of the mount.type helper has to be tested by
2101 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
2102 * that exec() has been successful.
2103 *
2104 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
2105 */
2106 int mnt_context_get_status(struct libmnt_context *cxt)
2107 {
2108 assert(cxt);
2109 return !cxt->syscall_status || !cxt->helper_exec_status;
2110 }
2111
2112 /**
2113 * mnt_context_helper_executed:
2114 * @cxt: mount context
2115 *
2116 * Returns: 1 if mount.type helper has been executed, or 0.
2117 */
2118 int mnt_context_helper_executed(struct libmnt_context *cxt)
2119 {
2120 assert(cxt);
2121 return cxt->helper_exec_status != 1;
2122 }
2123
2124 /**
2125 * mnt_context_get_helper_status:
2126 * @cxt: mount context
2127 *
2128 * Return: mount.type helper exit status, result is reliable only if
2129 * mnt_context_helper_executed() returns 1.
2130 */
2131 int mnt_context_get_helper_status(struct libmnt_context *cxt)
2132 {
2133 assert(cxt);
2134 return cxt->helper_status;
2135 }
2136
2137 /**
2138 * mnt_context_syscall_called:
2139 * @cxt: mount context
2140 *
2141 * Returns: 1 if mount(2) syscall has been called, or 0.
2142 */
2143 int mnt_context_syscall_called(struct libmnt_context *cxt)
2144 {
2145 assert(cxt);
2146 return cxt->syscall_status != 1;
2147 }
2148
2149 /**
2150 * mnt_context_get_syscall_errno:
2151 * @cxt: mount context
2152 *
2153 * The result from this function is reliable only if
2154 * mnt_context_syscall_called() returns 1.
2155 *
2156 * Returns: mount(2) errno if the syscall failed or 0.
2157 */
2158 int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
2159 {
2160 assert(cxt);
2161 if (cxt->syscall_status < 0)
2162 return -cxt->syscall_status;
2163 return 0;
2164 }
2165
2166 /**
2167 * mnt_context_set_syscall_status:
2168 * @cxt: mount context
2169 * @status: mount(2) status
2170 *
2171 * The @status should be 0 on success, or negative number on error (-errno).
2172 *
2173 * This function should only be used if the [u]mount(2) syscall is NOT called by
2174 * libmount code.
2175 *
2176 * Returns: 0 or negative number in case of error.
2177 */
2178 int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
2179 {
2180 assert(cxt);
2181 if (!cxt)
2182 return -EINVAL;
2183
2184 DBG(CXT, ul_debugobj(cxt, "syscall status set to: %d", status));
2185 cxt->syscall_status = status;
2186 return 0;
2187 }
2188
2189 /**
2190 * mnt_context_strerror
2191 * @cxt: context
2192 * @buf: buffer
2193 * @bufsiz: size of the buffer
2194 *
2195 * Not implemented yet.
2196 *
2197 * Returns: 0 or negative number in case of error.
2198 */
2199 int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
2200 char *buf __attribute__((__unused__)),
2201 size_t bufsiz __attribute__((__unused__)))
2202 {
2203 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2204 return 0;
2205 }
2206
2207 /**
2208 * mnt_context_init_helper
2209 * @cxt: mount context
2210 * @action: MNT_ACT_{UMOUNT,MOUNT}
2211 * @flags: not used now
2212 *
2213 * This function informs libmount that used from [u]mount.type helper.
2214 *
2215 * The function also calls mnt_context_disable_helpers() to avoid recursive
2216 * mount.type helpers calling. It you really want to call another
2217 * mount.type helper from your helper, then you have to explicitly enable this
2218 * feature by:
2219 *
2220 * mnt_context_disable_helpers(cxt, FALSE);
2221 *
2222 * Returns: 0 on success, negative number in case of error.
2223 */
2224 int mnt_context_init_helper(struct libmnt_context *cxt, int action,
2225 int flags __attribute__((__unused__)))
2226 {
2227 int rc;
2228
2229 assert(cxt);
2230
2231 rc = mnt_context_disable_helpers(cxt, TRUE);
2232 if (!rc)
2233 rc = set_flag(cxt, MNT_FL_HELPER, 1);
2234 if (!rc)
2235 cxt->action = action;
2236
2237 DBG(CXT, ul_debugobj(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
2238 return rc;
2239 }
2240
2241 /**
2242 * mnt_context_helper_setopt:
2243 * @cxt: context
2244 * @c: getopt() result
2245 * @arg: getopt() optarg
2246 *
2247 * This function applies the [u]mount.type command line option (for example parsed
2248 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
2249 * then 1 is returned.
2250 *
2251 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
2252 */
2253 int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
2254 {
2255 if (cxt) {
2256 switch(cxt->action) {
2257 case MNT_ACT_MOUNT:
2258 return mnt_context_mount_setopt(cxt, c, arg);
2259 case MNT_ACT_UMOUNT:
2260 return mnt_context_umount_setopt(cxt, c, arg);
2261 }
2262 }
2263 return -EINVAL;
2264 }
2265
2266 /**
2267 * mnt_context_is_fs_mounted:
2268 * @cxt: context
2269 * @fs: filesystem
2270 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2271 *
2272 * Please, read the mnt_table_is_fs_mounted() description!
2273 *
2274 * Returns: 0 on success and negative number in case of error.
2275 */
2276 int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
2277 struct libmnt_fs *fs, int *mounted)
2278 {
2279 struct libmnt_table *mtab;
2280 int rc;
2281
2282 assert(cxt);
2283 if (!cxt || !fs || !mounted)
2284 return -EINVAL;
2285
2286 rc = mnt_context_get_mtab(cxt, &mtab);
2287 if (rc)
2288 return rc;
2289
2290 *mounted = mnt_table_is_fs_mounted(mtab, fs);
2291 return 0;
2292 }
2293
2294 static int mnt_context_add_child(struct libmnt_context *cxt, pid_t pid)
2295 {
2296 pid_t *pids;
2297
2298 assert(cxt);
2299 if (!cxt)
2300 return -EINVAL;
2301
2302 pids = realloc(cxt->children, sizeof(pid_t) * cxt->nchildren + 1);
2303 if (!pids)
2304 return -ENOMEM;
2305
2306 DBG(CXT, ul_debugobj(cxt, "add new child %d", pid));
2307 cxt->children = pids;
2308 cxt->children[cxt->nchildren++] = pid;
2309
2310 return 0;
2311 }
2312
2313 int mnt_fork_context(struct libmnt_context *cxt)
2314 {
2315 int rc = 0;
2316 pid_t pid;
2317
2318 assert(cxt);
2319 if (!mnt_context_is_parent(cxt))
2320 return -EINVAL;
2321
2322 DBG(CXT, ul_debugobj(cxt, "forking context"));
2323
2324 DBG_FLUSH;
2325
2326 pid = fork();
2327
2328 switch (pid) {
2329 case -1: /* error */
2330 DBG(CXT, ul_debugobj(cxt, "fork failed %m"));
2331 return -errno;
2332
2333 case 0: /* child */
2334 cxt->pid = getpid();
2335 mnt_context_enable_fork(cxt, FALSE);
2336 DBG(CXT, ul_debugobj(cxt, "child created"));
2337 break;
2338
2339 default:
2340 rc = mnt_context_add_child(cxt, pid);
2341 break;
2342 }
2343
2344 return rc;
2345 }
2346
2347 int mnt_context_wait_for_children(struct libmnt_context *cxt,
2348 int *nchildren, int *nerrs)
2349 {
2350 int i;
2351
2352 assert(cxt);
2353 if (!cxt)
2354 return -EINVAL;
2355
2356 assert(mnt_context_is_parent(cxt));
2357
2358 for (i = 0; i < cxt->nchildren; i++) {
2359 pid_t pid = cxt->children[i];
2360 int rc = 0, ret = 0;
2361
2362 if (!pid)
2363 continue;
2364 do {
2365 DBG(CXT, ul_debugobj(cxt,
2366 "waiting for child (%d/%d): %d",
2367 i + 1, cxt->nchildren, pid));
2368 errno = 0;
2369 rc = waitpid(pid, &ret, 0);
2370
2371 } while (rc == -1 && errno == EINTR);
2372
2373 if (nchildren)
2374 (*nchildren)++;
2375
2376 if (rc != -1 && nerrs) {
2377 if (WIFEXITED(ret))
2378 (*nerrs) += WEXITSTATUS(ret) == 0 ? 0 : 1;
2379 else
2380 (*nerrs)++;
2381 }
2382 cxt->children[i] = 0;
2383 }
2384
2385 cxt->nchildren = 0;
2386 free(cxt->children);
2387 cxt->children = NULL;
2388 return 0;
2389 }
2390
2391
2392
2393 #ifdef TEST_PROGRAM
2394
2395 struct libmnt_lock *lock;
2396
2397 static void lock_fallback(void)
2398 {
2399 if (lock)
2400 mnt_unlock_file(lock);
2401 }
2402
2403 int test_mount(struct libmnt_test *ts, int argc, char *argv[])
2404 {
2405 int idx = 1, rc = 0;
2406 struct libmnt_context *cxt;
2407
2408 if (argc < 2)
2409 return -EINVAL;
2410
2411 cxt = mnt_new_context();
2412 if (!cxt)
2413 return -ENOMEM;
2414
2415 if (!strcmp(argv[idx], "-o")) {
2416 mnt_context_set_options(cxt, argv[idx + 1]);
2417 idx += 2;
2418 }
2419 if (!strcmp(argv[idx], "-t")) {
2420 /* TODO: use mnt_context_set_fstype_pattern() */
2421 mnt_context_set_fstype(cxt, argv[idx + 1]);
2422 idx += 2;
2423 }
2424
2425 if (argc == idx + 1)
2426 /* mount <mountpont>|<device> */
2427 mnt_context_set_target(cxt, argv[idx++]);
2428
2429 else if (argc == idx + 2) {
2430 /* mount <device> <mountpoint> */
2431 mnt_context_set_source(cxt, argv[idx++]);
2432 mnt_context_set_target(cxt, argv[idx++]);
2433 }
2434
2435 /* this is unnecessary! -- libmount is able to internally
2436 * create and manage the lock
2437 */
2438 lock = mnt_context_get_lock(cxt);
2439 if (lock)
2440 atexit(lock_fallback);
2441
2442 rc = mnt_context_mount(cxt);
2443 if (rc)
2444 warn("failed to mount");
2445 else
2446 printf("successfully mounted\n");
2447
2448 lock = NULL; /* because we use atexit lock_fallback */
2449 mnt_free_context(cxt);
2450 return rc;
2451 }
2452
2453 int test_umount(struct libmnt_test *ts, int argc, char *argv[])
2454 {
2455 int idx = 1, rc = 0;
2456 struct libmnt_context *cxt;
2457
2458 if (argc < 2)
2459 return -EINVAL;
2460
2461 cxt = mnt_new_context();
2462 if (!cxt)
2463 return -ENOMEM;
2464
2465 if (!strcmp(argv[idx], "-t")) {
2466 mnt_context_set_fstype(cxt, argv[idx + 1]);
2467 idx += 2;
2468 }
2469
2470 if (!strcmp(argv[idx], "-f")) {
2471 mnt_context_enable_force(cxt, TRUE);
2472 idx++;
2473 }
2474
2475 if (!strcmp(argv[idx], "-l")) {
2476 mnt_context_enable_lazy(cxt, TRUE);
2477 idx++;
2478 }
2479
2480 if (!strcmp(argv[idx], "-r")) {
2481 mnt_context_enable_rdonly_umount(cxt, TRUE);
2482 idx++;
2483 }
2484
2485 if (argc == idx + 1) {
2486 /* mount <mountpont>|<device> */
2487 mnt_context_set_target(cxt, argv[idx++]);
2488 } else {
2489 rc = -EINVAL;
2490 goto err;
2491 }
2492
2493 lock = mnt_context_get_lock(cxt);
2494 if (lock)
2495 atexit(lock_fallback);
2496
2497 rc = mnt_context_umount(cxt);
2498 if (rc)
2499 printf("failed to umount\n");
2500 else
2501 printf("successfully umounted\n");
2502 err:
2503 lock = NULL; /* because we use atexit lock_fallback */
2504 mnt_free_context(cxt);
2505 return rc;
2506 }
2507
2508 int test_flags(struct libmnt_test *ts, int argc, char *argv[])
2509 {
2510 int idx = 1, rc = 0;
2511 struct libmnt_context *cxt;
2512 const char *opt = NULL;
2513 unsigned long flags = 0;
2514
2515 if (argc < 2)
2516 return -EINVAL;
2517
2518 cxt = mnt_new_context();
2519 if (!cxt)
2520 return -ENOMEM;
2521
2522 if (!strcmp(argv[idx], "-o")) {
2523 mnt_context_set_options(cxt, argv[idx + 1]);
2524 idx += 2;
2525 }
2526
2527 if (argc == idx + 1)
2528 /* mount <mountpont>|<device> */
2529 mnt_context_set_target(cxt, argv[idx++]);
2530
2531 rc = mnt_context_prepare_mount(cxt);
2532 if (rc)
2533 printf("failed to prepare mount %s\n", strerror(-rc));
2534
2535 opt = mnt_fs_get_options(cxt->fs);
2536 if (opt)
2537 fprintf(stdout, "options: %s\n", opt);
2538
2539 mnt_context_get_mflags(cxt, &flags);
2540 fprintf(stdout, "flags: %08lx\n", flags);
2541
2542 mnt_free_context(cxt);
2543 return rc;
2544 }
2545
2546 int test_mountall(struct libmnt_test *ts, int argc, char *argv[])
2547 {
2548 struct libmnt_context *cxt;
2549 struct libmnt_iter *itr;
2550 struct libmnt_fs *fs;
2551 int mntrc, ignored, idx = 1;
2552
2553 cxt = mnt_new_context();
2554 itr = mnt_new_iter(MNT_ITER_FORWARD);
2555
2556 if (!cxt || !itr)
2557 return -ENOMEM;
2558
2559 if (argc > 2) {
2560 if (argv[idx] && !strcmp(argv[idx], "-O")) {
2561 mnt_context_set_options_pattern(cxt, argv[idx + 1]);
2562 idx += 2;
2563 }
2564 if (argv[idx] && !strcmp(argv[idx], "-t")) {
2565 mnt_context_set_fstype_pattern(cxt, argv[idx + 1]);
2566 idx += 2;
2567 }
2568 }
2569
2570 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
2571
2572 const char *tgt = mnt_fs_get_target(fs);
2573
2574 if (ignored == 1)
2575 printf("%s: ignored: not match\n", tgt);
2576 else if (ignored == 2)
2577 printf("%s: ignored: already mounted\n", tgt);
2578
2579 else if (!mnt_context_get_status(cxt)) {
2580 if (mntrc > 0) {
2581 errno = mntrc;
2582 warn("%s: mount failed", tgt);
2583 } else
2584 warnx("%s: mount failed", tgt);
2585 } else
2586 printf("%s: successfully mounted\n", tgt);
2587 }
2588
2589 mnt_free_context(cxt);
2590 return 0;
2591 }
2592
2593 int main(int argc, char *argv[])
2594 {
2595 struct libmnt_test tss[] = {
2596 { "--mount", test_mount, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
2597 { "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
2598 { "--mount-all", test_mountall, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
2599 { "--flags", test_flags, "[-o <opts>] <spec>" },
2600 { NULL }};
2601
2602 umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */
2603
2604 return mnt_run_test(tss, argc, argv);
2605 }
2606
2607 #endif /* TEST_PROGRAM */