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