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