2
* Copyright (C) 2010 Karel Zak <kzak@redhat.com>
4
* This file may be redistributed under the terms of the
5
* GNU Lesser General Public License.
10
* @title: Mount/umount context
11
* @short_description: high-level API to mount/umount devices.
15
* struct libmnt_context *cxt = mnt_new_context();
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");
21
* if (!mnt_context_mount(cxt))
22
* printf("successfully mounted\n");
23
* mnt_free_context(cxt);
28
* This code is similar to:
30
* mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
36
#include <sys/types.h>
48
* Returns: newly allocated mount context
50
struct libmnt_context *mnt_new_context(void)
52
struct libmnt_context *cxt;
55
cxt = calloc(1, sizeof(*cxt));
62
cxt->syscall_status = 1; /* not called yet */
63
cxt->helper_exec_status = 1;
65
/* if we're really root and aren't running setuid */
66
cxt->restricted = (uid_t) 0 == ruid && ruid == euid ? 0 : 1;
68
DBG(CXT, mnt_debug_h(cxt, "allocate %s",
69
cxt->restricted ? "[RESTRICTED]" : ""));
71
mnt_has_regular_mtab(&cxt->mtab_path, &cxt->mtab_writable);
73
if (!cxt->mtab_writable)
74
/* use /run/mount/utab if /etc/mtab is useless */
75
mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
84
* Deallocates context struct.
86
void mnt_free_context(struct libmnt_context *cxt)
91
mnt_reset_context(cxt);
93
DBG(CXT, mnt_debug_h(cxt, "free"));
95
free(cxt->fstype_pattern);
96
free(cxt->optstr_pattern);
98
if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
99
mnt_free_table(cxt->fstab);
100
if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
101
mnt_free_cache(cxt->cache);
103
mnt_free_lock(cxt->lock);
104
mnt_free_update(cxt->update);
111
* @cxt: mount context
113
* Resets all information in the context that are directly related to
114
* the latest mount (spec, source, target, mount options, ....)
116
* The match patters, cached fstab, cached canonicalized paths and tags and
117
* [e]uid are not reseted. You have to use
119
* mnt_context_set_fstab(cxt, NULL);
120
* mnt_context_set_cache(cxt, NULL);
121
* mnt_context_set_fstype_pattern(cxt, NULL);
122
* mnt_context_set_options_pattern(cxt, NULL);
125
* to reset these stuff.
127
* Returns: 0 on success, negative number in case of error.
129
int mnt_reset_context(struct libmnt_context *cxt)
138
if (!(cxt->flags & MNT_FL_EXTERN_FS))
139
mnt_free_fs(cxt->fs);
141
mnt_free_table(cxt->mtab);
144
free(cxt->orig_user);
150
cxt->orig_user = NULL;
152
cxt->user_mountflags = 0;
153
cxt->mountdata = NULL;
154
cxt->flags = MNT_FL_DEFAULT;
155
cxt->syscall_status = 1;
156
cxt->helper_exec_status = 1;
157
cxt->helper_status = 0;
159
/* restore non-resetable flags */
160
cxt->flags |= (fl & MNT_FL_EXTERN_FSTAB);
161
cxt->flags |= (fl & MNT_FL_EXTERN_CACHE);
166
static int set_flag(struct libmnt_context *cxt, int flag, int enable)
178
* mnt_context_is_restricted:
179
* @cxt: mount context
181
* Returns: 0 for unrestricted mount (user is root), or 1 for non-root mounts
183
int mnt_context_is_restricted(struct libmnt_context *cxt)
186
return cxt->restricted;
190
* mnt_context_set_optsmode
191
* @cxt: mount context
192
* @mode: mask, see MNT_OMASK_* flags in libmount mount.h
194
* Controls how to use mount options from fstab/mtab.
196
* Returns: 0 on success, negative number in case of error.
198
int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
202
cxt->optsmode = mode;
207
* mnt_context_get_optsmode
208
* @cxt: mount context
210
* Returns: MNT_OMASK_* mask or zero.
213
int mnt_context_get_optsmode(struct libmnt_context *cxt)
215
return cxt ? cxt->optsmode : 0;
219
* mnt_context_disable_canonicalize:
220
* @cxt: mount context
221
* @disable: TRUE or FALSE
223
* Enable/disable paths canonicalization and tags evaluation. The libmount context
224
* canonicalies paths when search in fstab and when prepare source and target paths
225
* for mount(2) syscall.
227
* This fuction has effect to the private fstab instance only (see
228
* mnt_context_set_fstab()). If you want to use an external fstab then you need
229
* manage your private struct libmnt_cache (see mnt_table_set_cache(fstab, NULL).
231
* Returns: 0 on success, negative number in case of error.
233
int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
235
return set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
239
* mnt_context_enable_lazy:
240
* @cxt: mount context
241
* @enable: TRUE or FALSE
243
* Enable/disable lazy umount (see umount(8) man page, option -l).
245
* Returns: 0 on success, negative number in case of error.
247
int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
249
return set_flag(cxt, MNT_FL_LAZY, enable);
253
* mnt_context_is_lazy:
254
* @cxt: mount context
256
* Returns: 1 if lazy umount is enabled or 0
258
int mnt_context_is_lazy(struct libmnt_context *cxt)
260
return cxt && (cxt->flags & MNT_FL_LAZY) ? 1 : 0;
265
* mnt_context_enable_rdonly_umount:
266
* @cxt: mount context
267
* @enable: TRUE or FALSE
269
* Enable/disable read-only remount on failed umount(2)
270
* (see umount(8) man page, option -r).
272
* Returns: 0 on success, negative number in case of error.
274
int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
276
return set_flag(cxt, MNT_FL_RDONLY_UMOUNT, enable);
280
* mnt_context_is_rdonly_umount
281
* @cxt: mount context
283
* See also mnt_context_enable_rdonly_umount() and see umount(8) man page,
286
* Returns: 1 if read-only remount failed umount(2) is enables or 0
288
int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
290
return cxt && (cxt->flags & MNT_FL_RDONLY_UMOUNT) ? 1 : 0;
294
* mnt_context_disable_helpers:
295
* @cxt: mount context
296
* @disable: TRUE or FALSE
298
* Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
300
* Returns: 0 on success, negative number in case of error.
302
int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable)
304
return set_flag(cxt, MNT_FL_NOHELPERS, disable);
308
* mnt_context_enable_sloppy:
309
* @cxt: mount context
310
* @enable: TRUE or FALSE
312
* Set/unset sloppy mounting (see mount(8) man page, option -s).
314
* Returns: 0 on success, negative number in case of error.
316
int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable)
318
return set_flag(cxt, MNT_FL_SLOPPY, enable);
322
* mnt_context_is_sloppy:
323
* @cxt: mount context
325
* Returns: 1 if sloppy flag is enabled or 0
327
int mnt_context_is_sloppy(struct libmnt_context *cxt)
329
return cxt && (cxt->flags & MNT_FL_SLOPPY) ? 1 : 0;
333
* mnt_context_enable_fake:
334
* @cxt: mount context
335
* @enable: TRUE or FALSE
337
* Enable/disable fake mounting (see mount(8) man page, option -f).
339
* Returns: 0 on success, negative number in case of error.
341
int mnt_context_enable_fake(struct libmnt_context *cxt, int enable)
343
return set_flag(cxt, MNT_FL_FAKE, enable);
347
* mnt_context_is_fake:
348
* @cxt: mount context
350
* Returns: 1 if fake flag is enabled or 0
352
int mnt_context_is_fake(struct libmnt_context *cxt)
354
return cxt && (cxt->flags & MNT_FL_FAKE) ? 1 : 0;
358
* mnt_context_disable_mtab:
359
* @cxt: mount context
360
* @disable: TRUE or FALSE
362
* Disable/enable mtab update (see mount(8) man page, option -n).
364
* Returns: 0 on success, negative number in case of error.
366
int mnt_context_disable_mtab(struct libmnt_context *cxt, int disable)
368
return set_flag(cxt, MNT_FL_NOMTAB, disable);
372
* mnt_context_is_nomtab
373
* @cxt: mount context
375
* Returns: 1 if no-mtab is enabled or 0
377
int mnt_context_is_nomtab(struct libmnt_context *cxt)
379
return cxt && (cxt->flags & MNT_FL_NOMTAB) ? 1 : 0;
383
* mnt_context_enable_force:
384
* @cxt: mount context
385
* @enable: TRUE or FALSE
387
* Enable/disable force umounting (see umount(8) man page, option -f).
389
* Returns: 0 on success, negative number in case of error.
391
int mnt_context_enable_force(struct libmnt_context *cxt, int enable)
393
return set_flag(cxt, MNT_FL_FORCE, enable);
397
* mnt_context_is_force
398
* @cxt: mount context
400
* Returns: 1 if force umounting flag is enabled or 0
402
int mnt_context_is_force(struct libmnt_context *cxt)
404
return cxt && (cxt->flags & MNT_FL_FORCE) ? 1 : 0;
408
* mnt_context_enable_verbose:
409
* @cxt: mount context
410
* @enable: TRUE or FALSE
412
* Enable/disable verbose output (TODO: not implemented yet)
414
* Returns: 0 on success, negative number in case of error.
416
int mnt_context_enable_verbose(struct libmnt_context *cxt, int enable)
418
return set_flag(cxt, MNT_FL_VERBOSE, enable);
422
* mnt_context_is_verbose
423
* @cxt: mount context
425
* Returns: 1 if verbose flag is enabled or 0
427
int mnt_context_is_verbose(struct libmnt_context *cxt)
429
return cxt && (cxt->flags & MNT_FL_VERBOSE) ? 1 : 0;
433
* mnt_context_enable_loopdel:
434
* @cxt: mount context
435
* @enable: TRUE or FALSE
437
* Enable/disable loop delete (destroy) after umount (see umount(8), option -d)
439
* Returns: 0 on success, negative number in case of error.
441
int mnt_context_enable_loopdel(struct libmnt_context *cxt, int enable)
443
return set_flag(cxt, MNT_FL_LOOPDEL, enable);
447
* mnt_context_set_fs:
448
* @cxt: mount context
449
* @fs: filesystem description
451
* The mount context uses private @fs by default. This function allows to
452
* overwrite the private @fs with an external instance. Note that the external
453
* @fs instance is not deallocated by mnt_free_context() or mnt_reset_context().
455
* The @fs will be modified by mnt_context_set_{source,target,options,fstype}
456
* functions, If the @fs is NULL then all current FS specific setting (source,
457
* target, etc., exclude spec) is reseted.
459
* Returns: 0 on success, negative number in case of error.
461
int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
465
if (!(cxt->flags & MNT_FL_EXTERN_FS))
466
mnt_free_fs(cxt->fs);
468
set_flag(cxt, MNT_FL_EXTERN_FS, fs != NULL);
474
* mnt_context_get_fs:
475
* @cxt: mount context
477
* The FS contains the basic description of mountpoint, fs type and so on.
478
* Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
481
* Returns: pointer to FS description or NULL in case of calloc() errrr.
483
struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
488
cxt->fs = mnt_new_fs();
489
cxt->flags &= ~MNT_FL_EXTERN_FS;
495
* mnt_context_set_source:
496
* @cxt: mount context
497
* @source: mount source (device, directory, UUID, LABEL, ...)
499
* Returns: 0 on success, negative number in case of error.
501
int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
503
return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
507
* mnt_context_get_source:
508
* @cxt: mount context
510
* Returns: returns pointer or NULL in case of error pr if not set.
512
const char *mnt_context_get_source(struct libmnt_context *cxt)
514
return mnt_fs_get_source(mnt_context_get_fs(cxt));
518
* mnt_context_set_target:
519
* @cxt: mount context
520
* @target: mountpoint
522
* Returns: 0 on success, negative number in case of error.
524
int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
526
return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
530
* mnt_context_get_target:
531
* @cxt: mount context
533
* Returns: returns pointer or NULL in case of error pr if not set.
535
const char *mnt_context_get_target(struct libmnt_context *cxt)
537
return mnt_fs_get_target(mnt_context_get_fs(cxt));
541
* mnt_context_set_fstype:
542
* @cxt: mount context
543
* @fstype: filesystem type
545
* Note that the @fstype has to be the real FS type. For comma-separated list of
546
* filesystems or for "nofs" notation use mnt_context_set_fstype_pattern().
548
* Returns: 0 on success, negative number in case of error.
550
int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
552
if (fstype && strchr(fstype, ','))
554
return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
558
* mnt_context_get_fstype:
559
* @cxt: mount context
561
* Returns: returns pointer or NULL in case of error pr if not set.
563
const char *mnt_context_get_fstype(struct libmnt_context *cxt)
565
return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
569
* mnt_context_set_options:
570
* @cxt: mount context
571
* @optstr: comma delimited mount options
573
* Returns: 0 on success, negative number in case of error.
575
int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
577
return mnt_fs_set_options(mnt_context_get_fs(cxt), optstr);
581
* mnt_context_append_options:
582
* @cxt: mount context
583
* @optstr: comma delimited mount options
585
* Returns: 0 on success, negative number in case of error.
587
int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
589
return mnt_fs_append_options(mnt_context_get_fs(cxt), optstr);
593
* mnt_context_set_fstype_pattern:
594
* @cxt: mount context
595
* @pattern: FS name pattern (or NULL to reset the current setting)
597
* See mount(8), option -t.
599
* Returns: 0 on success, negative number in case of error.
601
int mnt_context_set_fstype_pattern(struct libmnt_context *cxt, const char *pattern)
612
free(cxt->fstype_pattern);
613
cxt->fstype_pattern = p;
618
* mnt_context_set_options_pattern:
619
* @cxt: mount context
620
* @pattern: options pattern (or NULL to reset the current setting)
622
* See mount(8), option -O.
624
* Returns: 0 on success, negative number in case of error.
626
int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *pattern)
637
free(cxt->optstr_pattern);
638
cxt->optstr_pattern = p;
643
* mnt_context_set_fstab:
644
* @cxt: mount context
647
* The mount context reads /etc/fstab to the the private struct libmnt_table by default.
648
* This function allows to overwrite the private fstab with an external
649
* instance. Note that the external instance is not deallocated by mnt_free_context().
651
* The fstab is used read-only and is not modified, it should be possible to
652
* share the fstab between more mount contexts (TODO: tests it.)
654
* If the @tb argument is NULL then the current private fstab instance is
657
* Returns: 0 on success, negative number in case of error.
659
int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
663
if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
664
mnt_free_table(cxt->fstab);
666
set_flag(cxt, MNT_FL_EXTERN_FSTAB, tb != NULL);
672
* mnt_context_get_fstab:
673
* @cxt: mount context
676
* See also mnt_table_parse_fstab() for more details about fstab.
678
* Returns: 0 on success, negative number in case of error.
680
int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
682
struct libmnt_cache *cache;
690
cxt->fstab = mnt_new_table();
693
cxt->flags &= ~MNT_FL_EXTERN_FSTAB;
694
rc = mnt_table_parse_fstab(cxt->fstab, NULL);
699
cache = mnt_context_get_cache(cxt);
701
/* never touch an external fstab */
702
if (!(cxt->flags & MNT_FL_EXTERN_FSTAB))
703
mnt_table_set_cache(cxt->fstab, cache);
711
* mnt_context_get_mtab:
712
* @cxt: mount context
715
* See also mnt_table_parse_mtab() for more details about mtab/mountinfo.
717
* Returns: 0 on success, negative number in case of error.
719
int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
721
struct libmnt_cache *cache;
729
cxt->mtab = mnt_new_table();
732
rc = mnt_table_parse_mtab(cxt->mtab, cxt->mtab_path);
737
cache = mnt_context_get_cache(cxt);
738
mnt_table_set_cache(cxt->mtab, cache);
746
* mnt_context_set_cache:
747
* @cxt: mount context
748
* @cache: cache instance or nULL
750
* The mount context maintains a private struct libmnt_cache by default. This function
751
* allows to overwrite the private cache with an external instance. Note that
752
* the external instance is not deallocated by mnt_free_context().
754
* If the @cache argument is NULL then the current private cache instance is
757
* Returns: 0 on success, negative number in case of error.
759
int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache)
763
if (!(cxt->flags & MNT_FL_EXTERN_CACHE))
764
mnt_free_cache(cxt->cache);
766
set_flag(cxt, MNT_FL_EXTERN_CACHE, cache != NULL);
772
* mnt_context_get_cache
773
* @cxt: mount context
775
* See also mnt_context_set_cache().
777
* Returns: pointer to cache or NULL if canonicalization is disabled.
779
struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
781
if (!cxt || (cxt->flags & MNT_FL_NOCANONICALIZE))
785
cxt->cache = mnt_new_cache();
788
cxt->flags &= ~MNT_FL_EXTERN_CACHE;
794
* mnt_context_get_lock:
795
* @cxt: mount context
797
* The libmount applications don't have to care about mtab locking, but with a
798
* small exception: the application has to be able to remove the lock file when
799
* interrupted by signal or signals have to be ignored when the lock is locked.
801
* The default behavior is to ignore all signals (except SIGALRM and SIGTRAP)
802
* when the lock is locked. If this behavior is unacceptable then use:
804
* lc = mnt_context_get_lock(cxt);
806
* mnt_lock_block_signals(lc, FALSE);
808
* and don't forget to call mnt_unlock_file(lc) before exit.
810
* This function returns NULL if the lock is unnecessary (mtab file is not writable
811
* or /etc/mtab is symlink to /proc/mounts).
813
* Returns: pointer to lock struct or NULL.
815
struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
817
if (!cxt || (cxt->flags & MNT_FL_NOMTAB) || !cxt->mtab_writable)
820
if (!cxt->lock && cxt->mtab_path) {
821
cxt->lock = mnt_new_lock(cxt->mtab_path, 0);
823
mnt_lock_block_signals(cxt->lock, TRUE);
829
* mnt_context_set_mflags:
830
* @cxt: mount context
831
* @flags: mount(2) flags (MS_* flags)
833
* Sets mount flags (see mount(2) man page).
835
* Note that mount context allows to define mount options by mount flags. It
836
* means you can for example use
838
* mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
842
* mnt_context_set_options(cxt, "noexec,nosuid");
844
* these both calls have the same effect.
846
* Returns: 0 on success, negative number in case of error.
848
int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
852
cxt->mountflags = flags;
857
* mnt_context_get_mflags:
858
* @cxt: mount context
859
* @flags: returns MS_* mount flags
861
* Converts mount options string to MS_* flags and bitewise-OR the result with
862
* already defined flags (see mnt_context_set_mflags()).
864
* Returns: 0 on success, negative number in case of error.
866
int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
873
if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
874
const char *o = mnt_fs_get_vfs_options(cxt->fs);
876
rc = mnt_optstr_get_flags(o, flags,
877
mnt_get_builtin_optmap(MNT_LINUX_MAP));
880
*flags |= cxt->mountflags;
885
* mnt_context_set_user_mflags:
886
* @cxt: mount context
887
* @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
889
* Sets userspace mount flags.
891
* See also notest for mnt_context_set_mflags().
893
* Returns: 0 on success, negative number in case of error.
895
int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
899
cxt->user_mountflags = flags;
904
* mnt_context_get_user_mflags:
905
* @cxt: mount context
906
* @flags: returns mount flags
908
* Converts mount options string to MNT_MS_* flags and bitewise-OR the result
909
* with already defined flags (see mnt_context_set_user_mflags()).
911
* Returns: 0 on success, negative number in case of error.
913
int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
920
if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
921
const char *o = mnt_fs_get_user_options(cxt->fs);
923
rc = mnt_optstr_get_flags(o, flags,
924
mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
927
*flags |= cxt->user_mountflags;
931
static int is_loop(struct libmnt_context *cxt)
933
unsigned long fl = 0;
935
if (cxt->user_mountflags & MNT_MS_LOOP)
937
if (!mnt_context_get_mflags(cxt, &fl) && (fl & MNT_MS_LOOP))
941
* - support MNT_MS_{OFFSET,SIZELIMIT,ENCRYPTION}
947
* mnt_context_set_mountdata:
948
* @cxt: mount context
949
* @data: mount(2) data
951
* The mount context generates mountdata from mount options by default. This
952
* function allows to overwrite this behavior, and @data will be used instead
955
* The libmount does not deallocated the data by mnt_free_context(). Note that
956
* NULL is also valid mount data.
958
* Returns: 0 on success, negative number in case of error.
960
int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
964
cxt->mountdata = data;
965
cxt->flags |= MNT_FL_MOUNTDATA;
970
* Translates LABEL/UUID/path to mountable path
972
int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
974
const char *path = NULL;
975
struct libmnt_cache *cache;
976
const char *t, *v, *src;
981
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
983
if (!cxt || !cxt->fs)
986
DBG(CXT, mnt_debug_h(cxt, "preparing source path"));
988
src = mnt_fs_get_source(cxt->fs);
990
/* ignore filesystems without source or filesystems
991
* where the source is quasi-path (//foo/bar)
993
if (!src || (cxt->fs->flags & MNT_FS_NET))
996
DBG(CXT, mnt_debug_h(cxt, "srcpath '%s'", src));
998
cache = mnt_context_get_cache(cxt);
1000
if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
1002
* Source is TAG (evaluate)
1005
path = mnt_resolve_tag(t, v, cache);
1007
rc = path ? mnt_fs_set_source(cxt->fs, path) : -EINVAL;
1011
* Source is PATH (canonicalize)
1013
path = mnt_resolve_path(src, cache);
1014
if (path && strcmp(path, src))
1015
rc = mnt_fs_set_source(cxt->fs, path);
1019
DBG(CXT, mnt_debug_h(cxt, "failed to prepare srcpath [rc=%d]", rc));
1026
if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION)) ||
1027
(cxt->fs->flags & MNT_FS_PSEUDO)) {
1028
DBG(CXT, mnt_debug_h(cxt, "PROPAGATION/pseudo FS source: %s", path));
1033
* Initialize loop device
1039
DBG(CXT, mnt_debug_h(cxt, "final srcpath '%s'", path));
1043
int mnt_context_prepare_target(struct libmnt_context *cxt)
1046
struct libmnt_cache *cache;
1051
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1053
if (!cxt || !cxt->fs)
1056
DBG(CXT, mnt_debug_h(cxt, "preparing target path"));
1058
tgt = mnt_fs_get_target(cxt->fs);
1062
cache = mnt_context_get_cache(cxt);
1064
char *path = mnt_resolve_path(tgt, cache);
1065
if (strcmp(path, tgt))
1066
rc = mnt_fs_set_target(cxt->fs, path);
1070
DBG(CXT, mnt_debug_h(cxt, "failed to prepare target"));
1072
DBG(CXT, mnt_debug_h(cxt, "final target '%s'",
1073
mnt_fs_get_target(cxt->fs)));
1077
int mnt_context_guess_fstype(struct libmnt_context *cxt)
1085
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1087
if (!cxt || !cxt->fs)
1090
if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
1093
type = (char *) mnt_fs_get_fstype(cxt->fs);
1094
if (type && !strcmp(type, "auto")) {
1095
mnt_fs_set_fstype(cxt->fs, NULL);
1101
if (cxt->flags & MS_REMOUNT)
1103
if (cxt->fstype_pattern)
1106
dev = mnt_fs_get_srcpath(cxt->fs);
1110
if (access(dev, F_OK) == 0) {
1111
struct libmnt_cache *cache = mnt_context_get_cache(cxt);
1113
type = mnt_get_fstype(dev, &cxt->ambi, cache);
1115
rc = mnt_fs_set_fstype(cxt->fs, type);
1117
free(type); /* type is not cached */
1120
if (strchr(dev, ':') != NULL)
1121
rc = mnt_fs_set_fstype(cxt->fs, "nfs");
1122
else if (!strncmp(dev, "//", 2))
1123
rc = mnt_fs_set_fstype(cxt->fs, "cifs");
1128
DBG(CXT, mnt_debug_h(cxt, "FS type: %s",
1129
mnt_fs_get_fstype(cxt->fs)));
1132
return mnt_fs_set_fstype(cxt->fs, "none");
1134
DBG(CXT, mnt_debug_h(cxt, "failed to detect FS type"));
1139
* The default is to use fstype from cxt->fs, this could be overwritten by
1140
* @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
1142
* Returns: 0 on success or negative number in case of error. Note that success
1143
* does not mean that there is any usable helper, you have to check cxt->helper.
1145
int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
1148
char search_path[] = FS_SEARCH_PATH; /* from config.h */
1149
char *p = NULL, *path;
1153
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1156
type = mnt_fs_get_fstype(cxt->fs);
1158
if ((cxt->flags & MNT_FL_NOHELPERS) || !type ||
1159
!strcmp(type, "none") || (cxt->fs->flags & MNT_FS_SWAP))
1162
path = strtok_r(search_path, ":", &p);
1164
char helper[PATH_MAX];
1168
rc = snprintf(helper, sizeof(helper), "%s/%s.%s",
1170
path = strtok_r(NULL, ":", &p);
1172
if (rc >= sizeof(helper) || rc < 0)
1175
rc = stat(helper, &st);
1176
if (rc == -1 && errno == ENOENT && strchr(type, '.')) {
1177
/* If type ends with ".subtype" try without it */
1178
*strrchr(helper, '.') = '\0';
1179
rc = stat(helper, &st);
1182
DBG(CXT, mnt_debug_h(cxt, "%-25s ... %s", helper,
1183
rc ? "not found" : "found"));
1189
cxt->helper = strdup(helper);
1198
int mnt_context_merge_mflags(struct libmnt_context *cxt)
1200
unsigned long fl = 0;
1205
DBG(CXT, mnt_debug_h(cxt, "merging mount flags"));
1207
rc = mnt_context_get_mflags(cxt, &fl);
1210
cxt->mountflags = fl;
1212
/* TODO: if cxt->fs->fs_optstr contains 'ro' then set the MS_RDONLY to
1213
* mount flags, it's possible that superblock is read-only, but VFS is
1218
rc = mnt_context_get_user_mflags(cxt, &fl);
1221
cxt->user_mountflags = fl;
1223
DBG(CXT, mnt_debug_h(cxt, "final flags: VFS=%08lx user=%08lx",
1224
cxt->mountflags, cxt->user_mountflags));
1226
cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
1231
* Prepare /etc/mtab or /run/mount/utab
1233
int mnt_context_prepare_update(struct libmnt_context *cxt)
1240
assert(cxt->action);
1241
assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1243
DBG(CXT, mnt_debug_h(cxt, "prepare update"));
1245
if (cxt->mountflags & MS_PROPAGATION) {
1246
DBG(CXT, mnt_debug_h(cxt, "skip update: MS_PROPAGATION"));
1250
target = mnt_fs_get_target(cxt->fs);
1252
if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/"))
1253
/* Don't try to touch mtab if umounting root FS */
1254
cxt->flags |= MNT_FL_NOMTAB;
1256
if (cxt->flags & MNT_FL_NOMTAB) {
1257
DBG(CXT, mnt_debug_h(cxt, "skip update: NOMTAB flag"));
1261
DBG(CXT, mnt_debug_h(cxt, "skip update: external helper"));
1264
if (!cxt->mtab_writable && !cxt->utab_writable) {
1265
DBG(CXT, mnt_debug_h(cxt, "skip update: no writable destination"));
1268
/* 0 = success, 1 = not called yet */
1269
if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
1270
DBG(CXT, mnt_debug_h(cxt,
1271
"skip update: syscall failed [status=%d]",
1272
cxt->syscall_status));
1276
cxt->update = mnt_new_update();
1280
mnt_update_set_filename(cxt->update,
1281
cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path,
1282
!cxt->mtab_writable);
1285
if (cxt->action == MNT_ACT_UMOUNT)
1286
rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1287
mnt_fs_get_target(cxt->fs), NULL);
1289
rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1292
return rc < 0 ? rc : 0;
1295
int mnt_context_update_tabs(struct libmnt_context *cxt)
1301
if (cxt->flags & MNT_FL_NOMTAB) {
1302
DBG(CXT, mnt_debug_h(cxt, "don't update: NOMTAB flag"));
1306
DBG(CXT, mnt_debug_h(cxt, "don't update: external helper"));
1309
if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
1310
DBG(CXT, mnt_debug_h(cxt, "don't update: no update prepared"));
1313
if (cxt->syscall_status) {
1314
DBG(CXT, mnt_debug_h(cxt, "don't update: syscall failed/not called"));
1318
fl = mnt_update_get_mflags(cxt->update);
1319
if ((cxt->mountflags & MS_RDONLY) != (fl & MS_RDONLY))
1321
* fix MS_RDONLY in options
1323
mnt_update_force_rdonly(cxt->update,
1324
cxt->mountflags & MS_RDONLY);
1326
return mnt_update_table(cxt->update, mnt_context_get_lock(cxt));
1329
static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
1332
struct libmnt_fs *fs = NULL;
1333
const char *src = NULL, *tgt = NULL;
1342
src = mnt_fs_get_source(cxt->fs);
1343
tgt = mnt_fs_get_target(cxt->fs);
1346
fs = mnt_table_find_pair(tb, src, tgt, direction);
1349
fs = mnt_table_find_source(tb, src, direction);
1351
fs = mnt_table_find_target(tb, tgt, direction);
1354
/* swap source and target (if @src is not LABEL/UUID),
1359
* the path could be a mountpoint as well as source (for
1360
* example bind mount, symlink to device, ...).
1362
if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
1363
fs = mnt_table_find_target(tb, src, direction);
1365
fs = mnt_table_find_source(tb, tgt, direction);
1372
DBG(CXT, mnt_debug_h(cxt, "apply entry:"));
1373
DBG(CXT, mnt_fs_print_debug(fs, stderr));
1375
/* copy from tab to our FS description
1377
rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
1379
rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
1381
if (!rc && !mnt_fs_get_fstype(cxt->fs))
1382
rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
1387
if (cxt->optsmode & MNT_OMODE_IGNORE)
1389
else if (cxt->optsmode & MNT_OMODE_REPLACE) {
1390
rc = mnt_fs_set_vfs_options(cxt->fs,
1391
mnt_fs_get_vfs_options(fs));
1393
rc = mnt_fs_set_fs_options(cxt->fs,
1394
mnt_fs_get_fs_options(fs));
1396
rc = mnt_fs_set_user_options(cxt->fs,
1397
mnt_fs_get_user_options(fs));
1399
} else if (cxt->optsmode & MNT_OMODE_APPEND) {
1400
rc = mnt_fs_append_vfs_options(cxt->fs,
1401
mnt_fs_get_vfs_options(fs));
1403
rc = mnt_fs_append_fs_options(cxt->fs,
1404
mnt_fs_get_fs_options(fs));
1406
rc = mnt_fs_append_user_options(cxt->fs,
1407
mnt_fs_get_user_options(fs));
1409
} else if (cxt->optsmode & MNT_OMODE_PREPEND) {
1410
rc = mnt_fs_prepend_vfs_options(cxt->fs,
1411
mnt_fs_get_vfs_options(fs));
1413
rc = mnt_fs_prepend_fs_options(cxt->fs,
1414
mnt_fs_get_fs_options(fs));
1416
rc = mnt_fs_prepend_user_options(cxt->fs,
1417
mnt_fs_get_user_options(fs));
1421
cxt->flags |= MNT_FL_TAB_APPLIED;
1426
* mnt_context_apply_fstab:
1427
* @cxt: mount context
1429
* This function is optional.
1431
* Returns: 0 on success, negative number in case of error.
1433
int mnt_context_apply_fstab(struct libmnt_context *cxt)
1436
struct libmnt_table *tab = NULL;
1437
const char *src = NULL, *tgt = NULL;
1445
if (cxt->flags & MNT_FL_TAB_APPLIED)
1448
if (mnt_context_is_restricted(cxt)) {
1449
DBG(CXT, mnt_debug_h(cxt, "force fstab usage for non-root users"));
1450
cxt->optsmode = MNT_OMODE_USER;
1452
} else if (cxt->optsmode == 0)
1453
cxt->optsmode = MNT_OMODE_AUTO;
1456
src = mnt_fs_get_source(cxt->fs);
1457
tgt = mnt_fs_get_target(cxt->fs);
1460
/* fstab is not required if source and target are specified */
1461
if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
1462
DBG(CXT, mnt_debug_h(cxt, "fstab not required -- skip"));
1466
DBG(CXT, mnt_debug_h(cxt,
1467
"trying to apply fstab (src=%s, target=%s)", src, tgt));
1469
/* let's initialize cxt->fs */
1470
mnt_context_get_fs(cxt);
1473
if (cxt->optsmode & MNT_OMODE_FSTAB) {
1474
rc = mnt_context_get_fstab(cxt, &tab);
1476
rc = apply_table(cxt, tab, MNT_ITER_FORWARD);
1480
if (rc == -1 && (cxt->optsmode & MNT_OMODE_MTAB)) {
1481
rc = mnt_context_get_mtab(cxt, &tab);
1483
rc = apply_table(cxt, tab, MNT_ITER_BACKWARD);
1486
DBG(CXT, mnt_debug_h(cxt, "failed to found entry in fstab/mtab"));
1491
* mnt_context_get_status:
1492
* @cxt: mount context
1494
* Returns: 0 if /sbin/mount.type or mount(2) syscall was successfull.
1496
int mnt_context_get_status(struct libmnt_context *cxt)
1498
return cxt && (!cxt->syscall_status || !cxt->helper_exec_status);
1502
* mnt_context_set_syscall_status:
1503
* @cxt: mount context
1504
* @status: mount(2) return code
1506
* The @status should be 0 on succcess, or negative number on error (-1 or
1509
* This function should be used if [u]mount(2) syscall was NOT called by
1510
* libmount (by mnt_context_mount() or mnt_context_do_mount()) only.
1512
* Returns: 0 or negative number in case of error.
1514
int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
1519
DBG(CXT, mnt_debug_h(cxt, "syscall status set to: %d", status));
1520
cxt->syscall_status = status;
1525
* mnt_context_strerror
1528
* @bufsiz: size of the buffer
1530
* Returns: 0 or negative number in case of error.
1532
int mnt_context_strerror(struct libmnt_context *cxt, char *buf, size_t bufsiz)
1534
/* TODO: based on cxt->syscall_errno or cxt->helper_status */
1539
* mnt_context_init_helper
1540
* @cxt: mount context
1541
* @action: MNT_ACT_{UMOUNT,MOUNT}
1544
* This function infors libmount that used from [u]mount.<type> helper.
1546
* The function also calls mnt_context_disable_helpers() to avoid recursive
1547
* mount.<type> helpers calling. It you really want to call another
1548
* mount.<type> helper from your helper than you have to explicitly enable this
1551
* mnt_context_disable_helpers(cxt, FALSE);
1553
* Returns: 0 on success, negative number in case of error.
1555
int mnt_context_init_helper(struct libmnt_context *cxt, int action, int flags)
1557
int rc = mnt_context_disable_helpers(cxt, TRUE);
1560
rc = set_flag(cxt, MNT_FL_HELPER, 1);
1562
cxt->action = action;
1564
DBG(CXT, mnt_debug_h(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
1569
* mnt_context_helper_setopt:
1571
* @c: getopt() result
1572
* @arg: getopt() optarg
1574
* This function applies [u]mount.<type> command line option (for example parsed
1575
* by getopt() or getopt_long()) to @cxt. All unknown options are ignored and
1576
* then 1 is returned.
1578
* Returns: negative number on error, 1 if @c is unknown option, 0 on success.
1580
int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
1583
switch(cxt->action) {
1585
return mnt_context_mount_setopt(cxt, c, arg);
1586
case MNT_ACT_UMOUNT:
1587
return mnt_context_umount_setopt(cxt, c, arg);
1595
struct libmnt_lock *lock;
1597
static void lock_fallback(void)
1600
mnt_unlock_file(lock);
1603
int test_mount(struct libmnt_test *ts, int argc, char *argv[])
1605
int idx = 1, rc = 0;
1606
struct libmnt_context *cxt;
1611
cxt = mnt_new_context();
1615
if (!strcmp(argv[idx], "-o")) {
1616
mnt_context_set_options(cxt, argv[idx + 1]);
1619
if (!strcmp(argv[idx], "-t")) {
1620
/* TODO: use mnt_context_set_fstype_pattern() */
1621
mnt_context_set_fstype(cxt, argv[idx + 1]);
1625
if (argc == idx + 1)
1626
/* mount <mountpont>|<device> */
1627
mnt_context_set_target(cxt, argv[idx++]);
1629
else if (argc == idx + 2) {
1630
/* mount <device> <mountpoint> */
1631
mnt_context_set_source(cxt, argv[idx++]);
1632
mnt_context_set_target(cxt, argv[idx++]);
1635
lock = mnt_context_get_lock(cxt);
1637
atexit(lock_fallback);
1639
rc = mnt_context_mount(cxt);
1641
printf("failed to mount %s\n", strerror(errno));
1643
printf("successfully mounted\n");
1645
mnt_free_context(cxt);
1649
int test_umount(struct libmnt_test *ts, int argc, char *argv[])
1651
int idx = 1, rc = 0;
1652
struct libmnt_context *cxt;
1657
cxt = mnt_new_context();
1661
if (!strcmp(argv[idx], "-t")) {
1662
mnt_context_set_fstype(cxt, argv[idx + 1]);
1666
if (!strcmp(argv[idx], "-f")) {
1667
mnt_context_enable_force(cxt, TRUE);
1671
if (!strcmp(argv[idx], "-l")) {
1672
mnt_context_enable_lazy(cxt, TRUE);
1676
if (!strcmp(argv[idx], "-r")) {
1677
mnt_context_enable_rdonly_umount(cxt, TRUE);
1681
if (argc == idx + 1) {
1682
/* mount <mountpont>|<device> */
1683
mnt_context_set_target(cxt, argv[idx++]);
1689
lock = mnt_context_get_lock(cxt);
1691
atexit(lock_fallback);
1693
rc = mnt_context_umount(cxt);
1695
printf("failed to umount\n");
1697
printf("successfully umounted\n");
1699
mnt_free_context(cxt);
1703
int main(int argc, char *argv[])
1705
struct libmnt_test tss[] = {
1706
{ "--mount", test_mount, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
1707
{ "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
1711
umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */
1713
return mnt_run_test(tss, argc, argv);
1716
#endif /* TEST_PROGRAM */