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