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