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