]> git.ipfire.org Git - thirdparty/util-linux.git/blame - libmount/src/context.c
taskset: Accept 0 pid for current process
[thirdparty/util-linux.git] / libmount / src / context.c
CommitLineData
2c37ca7c 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
c68408c2 2/*
2c37ca7c 3 * This file is part of libmount from util-linux project.
c68408c2 4 *
2c37ca7c
KZ
5 * Copyright (C) 2010-2018 Karel Zak <kzak@redhat.com>
6 *
7 * libmount is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU Lesser General Public License as published by
9 * the Free Software Foundation; either version 2.1 of the License, or
10 * (at your option) any later version.
c68408c2
KZ
11 */
12
0f32f1e2
KZ
13/**
14 * SECTION: context
63de90d4 15 * @title: Library high-level context
0f32f1e2
KZ
16 * @short_description: high-level API to mount/umount devices.
17 *
18 * <informalexample>
19 * <programlisting>
68164f6c 20 * struct libmnt_context *cxt = mnt_new_context();
0f32f1e2
KZ
21 *
22 * mnt_context_set_options(cxt, "aaa,bbb,ccc=CCC");
68164f6c 23 * mnt_context_set_mflags(cxt, MS_NOATIME|MS_NOEXEC);
0f32f1e2
KZ
24 * mnt_context_set_target(cxt, "/mnt/foo");
25 *
cddd0999 26 * if (!mnt_context_mount(cxt))
0f32f1e2
KZ
27 * printf("successfully mounted\n");
28 * mnt_free_context(cxt);
29 *
30 * </programlisting>
31 * </informalexample>
32 *
33 * This code is similar to:
34 *
35 * mount -o aaa,bbb,ccc=CCC,noatime,noexec /mnt/foo
36 *
37 */
38
c68408c2 39#include "mountP.h"
b9a5e23f 40#include "strutils.h"
4917d842 41#include "namespace.h"
1592425a 42#include "match.h"
c68408c2 43
41476dd4 44#include <stdarg.h>
d2c97887
KZ
45#include <sys/wait.h>
46
2a684833 47#include "mount-api-utils.h"
33c42f5b 48#include "strv.h"
2a684833 49
c68408c2
KZ
50/**
51 * mnt_new_context:
52 *
53 * Returns: newly allocated mount context
54 */
68164f6c 55struct libmnt_context *mnt_new_context(void)
c68408c2 56{
68164f6c 57 struct libmnt_context *cxt;
b36add06 58 uid_t ruid;
c68408c2
KZ
59
60 cxt = calloc(1, sizeof(*cxt));
61 if (!cxt)
62 return NULL;
63
64 ruid = getuid();
c68408c2 65
8ab6accf
KZ
66 mnt_context_reset_status(cxt);
67
4917d842
VD
68 cxt->ns_orig.fd = -1;
69 cxt->ns_tgt.fd = -1;
70 cxt->ns_cur = &cxt->ns_orig;
71
93c0f69d
KZ
72 cxt->map_linux = mnt_get_builtin_optmap(MNT_LINUX_MAP);
73 cxt->map_userspace = mnt_get_builtin_optmap(MNT_USERSPACE_MAP);
74
8241fb00
KZ
75 INIT_LIST_HEAD(&cxt->hooksets_hooks);
76 INIT_LIST_HEAD(&cxt->hooksets_datas);
77
c68408c2 78 /* if we're really root and aren't running setuid */
78914c80 79 cxt->restricted = (uid_t) 0 == ruid && !is_privileged_execution() ? 0 : 1;
c68408c2 80
7d084535 81 cxt->noautofs = 0;
22147e08 82
83a78332 83 DBG(CXT, ul_debugobj(cxt, "----> allocate %s",
e6a90b98 84 cxt->restricted ? "[RESTRICTED]" : ""));
c68408c2
KZ
85
86 return cxt;
87}
88
89/**
90 * mnt_free_context:
91 * @cxt: mount context
92 *
93 * Deallocates context struct.
94 */
68164f6c 95void mnt_free_context(struct libmnt_context *cxt)
c68408c2
KZ
96{
97 if (!cxt)
98 return;
99
1d0cd73f
KZ
100 mnt_reset_context(cxt);
101
c68408c2
KZ
102 free(cxt->fstype_pattern);
103 free(cxt->optstr_pattern);
71ed3b83 104 free(cxt->tgt_prefix);
c68408c2 105
c9f1585e 106 mnt_unref_table(cxt->fstab);
0105691d 107 mnt_unref_cache(cxt->cache);
e83c09d4 108 mnt_unref_fs(cxt->fs);
01790c7d
KZ
109
110 mnt_unref_optlist(cxt->optlist_saved);
9a72da2c 111 mnt_unref_optlist(cxt->optlist);
c68408c2 112
87938635 113 mnt_unref_lock(cxt->lock);
c68408c2 114 mnt_free_update(cxt->update);
c68408c2 115
4917d842
VD
116 mnt_context_set_target_ns(cxt, NULL);
117
d2c97887
KZ
118 free(cxt->children);
119
18139743 120 DBG(CXT, ul_debugobj(cxt, "free"));
c68408c2
KZ
121 free(cxt);
122}
123
124/**
125 * mnt_reset_context:
126 * @cxt: mount context
127 *
d58b3157 128 * Resets all information in the context that is directly related to
26d0c0ae 129 * the latest mount (spec, source, target, mount options, ...).
c68408c2 130 *
71ed3b83 131 * The match patterns, target namespace, prefix, cached fstab, cached canonicalized
5cbf01b7 132 * paths and tags and [e]uid are not reset. You have to use
c68408c2
KZ
133 *
134 * mnt_context_set_fstab(cxt, NULL);
135 * mnt_context_set_cache(cxt, NULL);
136 * mnt_context_set_fstype_pattern(cxt, NULL);
76a06ca4 137 * mnt_context_set_options_pattern(cxt, NULL);
5cbf01b7 138 * mnt_context_set_target_ns(cxt, NULL);
76a06ca4 139 *
d58b3157 140 * to reset this stuff.
c68408c2
KZ
141 *
142 * Returns: 0 on success, negative number in case of error.
143 */
68164f6c 144int mnt_reset_context(struct libmnt_context *cxt)
c68408c2
KZ
145{
146 int fl;
147
148 if (!cxt)
149 return -EINVAL;
150
83a78332 151 DBG(CXT, ul_debugobj(cxt, "<---- reset [status=%d] ---->",
9f7472b0 152 mnt_context_get_status(cxt)));
7f8b2bf3 153
c68408c2
KZ
154 fl = cxt->flags;
155
26d0c0ae 156 mnt_unref_fs(cxt->fs);
e9d52e6e 157 mnt_unref_table(cxt->mountinfo);
6a52473e 158 mnt_unref_table(cxt->utab);
01790c7d 159 mnt_unref_optlist(cxt->optlist);
c68408c2 160
a29e2f4f 161 free(cxt->helper);
f58168ff 162
1d0cd73f 163 cxt->fs = NULL;
e9d52e6e 164 cxt->mountinfo = NULL;
01790c7d 165 cxt->optlist = NULL;
6a52473e 166 cxt->utab = NULL;
a29e2f4f 167 cxt->helper = NULL;
c68408c2
KZ
168 cxt->mountdata = NULL;
169 cxt->flags = MNT_FL_DEFAULT;
7d084535 170 cxt->noautofs = 0;
77bc38ce 171 cxt->has_selinux_opt = 0;
6498ece0 172
93c0f69d
KZ
173 cxt->map_linux = mnt_get_builtin_optmap(MNT_LINUX_MAP);
174 cxt->map_userspace = mnt_get_builtin_optmap(MNT_USERSPACE_MAP);
175
8ab6accf 176 mnt_context_reset_status(cxt);
8241fb00 177 mnt_context_deinit_hooksets(cxt);
6a52473e
KZ
178
179 if (cxt->table_fltrcb)
180 mnt_context_set_tabfilter(cxt, NULL, NULL);
c68408c2 181
d58b3157 182 /* restore non-resettable flags */
9f7472b0
KZ
183 cxt->flags |= (fl & MNT_FL_NOMTAB);
184 cxt->flags |= (fl & MNT_FL_FAKE);
185 cxt->flags |= (fl & MNT_FL_SLOPPY);
186 cxt->flags |= (fl & MNT_FL_VERBOSE);
187 cxt->flags |= (fl & MNT_FL_NOHELPERS);
188 cxt->flags |= (fl & MNT_FL_LOOPDEL);
189 cxt->flags |= (fl & MNT_FL_LAZY);
d2c97887 190 cxt->flags |= (fl & MNT_FL_FORK);
9f7472b0
KZ
191 cxt->flags |= (fl & MNT_FL_FORCE);
192 cxt->flags |= (fl & MNT_FL_NOCANONICALIZE);
193 cxt->flags |= (fl & MNT_FL_RDONLY_UMOUNT);
6dede2f2 194 cxt->flags |= (fl & MNT_FL_RWONLY_MOUNT);
f3107fc2 195 cxt->flags |= (fl & MNT_FL_NOSWAPMATCH);
150e696d 196 cxt->flags |= (fl & MNT_FL_TABPATHS_CHECKED);
ea848180 197
e83c09d4
KZ
198 mnt_context_apply_template(cxt);
199
200 return 0;
201}
202
203/*
01790c7d 204 * Saves the current context setting (mount options, etc) to make it usable after
e83c09d4
KZ
205 * mnt_reset_context() or by mnt_context_apply_template(). This is usable for
206 * example for mnt_context_next_mount() where for the next mount operation we
207 * need to restore to the original context setting.
208 *
209 * Returns: 0 on success, negative number in case of error.
210 */
211int mnt_context_save_template(struct libmnt_context *cxt)
212{
e83c09d4
KZ
213 if (!cxt)
214 return -EINVAL;
215
01790c7d 216 DBG(CXT, ul_debugobj(cxt, "saving template"));
e83c09d4 217
01790c7d
KZ
218 /* reset old saved data */
219 mnt_unref_optlist(cxt->optlist_saved);
220 cxt->optlist_saved = NULL;
e83c09d4 221
01790c7d
KZ
222 if (cxt->optlist)
223 cxt->optlist_saved = mnt_copy_optlist(cxt->optlist);
e83c09d4 224
c68408c2
KZ
225 return 0;
226}
227
e83c09d4
KZ
228/*
229 * Restores context FS setting from previously saved template (see
230 * mnt_context_save_template()).
231 *
232 * Returns: 0 on success, negative number in case of error.
233 */
234int mnt_context_apply_template(struct libmnt_context *cxt)
235{
e83c09d4
KZ
236 if (!cxt)
237 return -EINVAL;
238
18139743
KZ
239 if (cxt->optlist) {
240 mnt_unref_optlist(cxt->optlist);
241 cxt->optlist = NULL;
242 }
e83c09d4 243
18139743
KZ
244 if (cxt->optlist_saved) {
245 DBG(CXT, ul_debugobj(cxt, "restoring template"));
01790c7d 246 cxt->optlist = mnt_copy_optlist(cxt->optlist_saved);
18139743 247 }
01790c7d
KZ
248
249 return 0;
e83c09d4
KZ
250}
251
252int mnt_context_has_template(struct libmnt_context *cxt)
253{
01790c7d 254 return cxt && cxt->optlist_saved ? 1 : 0;
e83c09d4
KZ
255}
256
189a1bf3
KZ
257struct libmnt_context *mnt_copy_context(struct libmnt_context *o)
258{
259 struct libmnt_context *n;
260
261 n = mnt_new_context();
262 if (!n)
263 return NULL;
264
265 DBG(CXT, ul_debugobj(n, "<---- clone ---->"));
266
267 n->flags = o->flags;
268
269 if (o->fs) {
270 n->fs = mnt_copy_fs(NULL, o->fs);
271 if (!n->fs)
272 goto failed;
273 }
274
e9d52e6e
KZ
275 n->mountinfo = o->mountinfo;
276 mnt_ref_table(n->mountinfo);
189a1bf3 277
e9d52e6e 278 n->utab = o->utab;
189a1bf3
KZ
279 mnt_ref_table(n->utab);
280
eee7ea55 281 if (strdup_between_structs(n, o, tgt_prefix))
779e3c97 282 goto failed;
eee7ea55 283 if (strdup_between_structs(n, o, helper))
779e3c97 284 goto failed;
189a1bf3 285
93c0f69d
KZ
286 n->map_linux = o->map_linux;
287 n->map_userspace = o->map_userspace;
288
189a1bf3
KZ
289 mnt_context_reset_status(n);
290
291 n->table_fltrcb = o->table_fltrcb;
292 n->table_fltrcb_data = o->table_fltrcb_data;
293
22147e08 294 n->noautofs = o->noautofs;
77bc38ce 295 n->has_selinux_opt = o->has_selinux_opt;
22147e08 296
189a1bf3
KZ
297 return n;
298failed:
299 mnt_free_context(n);
300 return NULL;
301}
302
8ab6accf
KZ
303/**
304 * mnt_context_reset_status:
305 * @cxt: context
306 *
ee314075 307 * Resets mount(2) and mount.type statuses, so mnt_context_do_mount() or
8ab6accf
KZ
308 * mnt_context_do_umount() could be again called with the same settings.
309 *
310 * BE CAREFUL -- after this soft reset the libmount will NOT parse mount
311 * options, evaluate permissions or apply stuff from fstab.
312 *
313 * Returns: 0 on success, negative number in case of error.
314 */
315int mnt_context_reset_status(struct libmnt_context *cxt)
316{
317 if (!cxt)
318 return -EINVAL;
319
6b871f46 320 mnt_context_syscall_reset_status(cxt);
9da5644e 321
8ab6accf
KZ
322 cxt->syscall_status = 1; /* means not called yet */
323 cxt->helper_exec_status = 1;
324 cxt->helper_status = 0;
325 return 0;
326}
327
150e696d
KZ
328static int context_init_paths(struct libmnt_context *cxt, int writable)
329{
cddd2eaa
VD
330 struct libmnt_ns *ns_old;
331
150e696d
KZ
332 assert(cxt);
333
51d51097 334 if (!cxt->utab_path) {
150e696d 335 cxt->utab_path = mnt_get_utab_path();
51d51097
KZ
336 DBG(CXT, ul_debugobj(cxt, "utab path initialized to: %s", cxt->utab_path));
337 }
150e696d
KZ
338
339 if (!writable)
340 return 0; /* only paths wanted */
341 if (mnt_context_is_nomtab(cxt))
9e930041 342 return 0; /* write mode overridden by mount -n */
150e696d
KZ
343 if (cxt->flags & MNT_FL_TABPATHS_CHECKED)
344 return 0;
345
346 DBG(CXT, ul_debugobj(cxt, "checking for writable tab files"));
347
cddd2eaa
VD
348 ns_old = mnt_context_switch_target_ns(cxt);
349 if (!ns_old)
350 return -MNT_ERR_NAMESPACE;
351
7f56e412 352 mnt_has_regular_utab(&cxt->utab_path, &cxt->utab_writable);
150e696d 353
cddd2eaa
VD
354 if (!mnt_context_switch_ns(cxt, ns_old))
355 return -MNT_ERR_NAMESPACE;
356
150e696d
KZ
357 cxt->flags |= MNT_FL_TABPATHS_CHECKED;
358 return 0;
359}
360
150e696d
KZ
361int mnt_context_utab_writable(struct libmnt_context *cxt)
362{
363 assert(cxt);
364
365 context_init_paths(cxt, 1);
366 return cxt->utab_writable == 1;
367}
368
369const char *mnt_context_get_writable_tabpath(struct libmnt_context *cxt)
370{
371 assert(cxt);
372
97f7bfc0 373 return mnt_context_utab_writable(cxt) ? cxt->utab_path : NULL;
150e696d
KZ
374}
375
376
68164f6c 377static int set_flag(struct libmnt_context *cxt, int flag, int enable)
c68408c2
KZ
378{
379 if (!cxt)
380 return -EINVAL;
d2c97887 381 if (enable) {
83a78332 382 DBG(CXT, ul_debugobj(cxt, "enabling flag %04x", flag));
c68408c2 383 cxt->flags |= flag;
d2c97887 384 } else {
83a78332 385 DBG(CXT, ul_debugobj(cxt, "disabling flag %04x", flag));
c68408c2 386 cxt->flags &= ~flag;
d2c97887 387 }
c68408c2
KZ
388 return 0;
389}
390
c68408c2
KZ
391/**
392 * mnt_context_is_restricted:
393 * @cxt: mount context
394 *
d58b3157 395 * Returns: 0 for an unrestricted mount (user is root), or 1 for non-root mounts
c68408c2 396 */
68164f6c 397int mnt_context_is_restricted(struct libmnt_context *cxt)
c68408c2 398{
c68408c2
KZ
399 return cxt->restricted;
400}
401
6497f2d9
KZ
402/**
403 * mnt_context_force_unrestricted:
404 * @cxt: mount context
405 *
406 * This function is DANGEROURS as it disables all security policies in libmount.
407 * Don't use if not sure. It removes "restricted" flag from the context, so
408 * libmount will use the current context as for root user.
409 *
410 * This function is designed for case you have no any suid permissions, so you
411 * can depend on kernel.
412 *
413 * Returns: 0 on success, negative number in case of error.
414 *
415 * Since: 2.35
416 */
417int mnt_context_force_unrestricted(struct libmnt_context *cxt)
418{
419 if (mnt_context_is_restricted(cxt)) {
420 DBG(CXT, ul_debugobj(cxt, "force UNRESTRICTED"));
421 cxt->restricted = 0;
422 }
423
424 return 0;
425}
426
c68408c2
KZ
427/**
428 * mnt_context_set_optsmode
429 * @cxt: mount context
94c7fa6e 430 * @mode: MNT_OMODE_* flags
c68408c2 431 *
e9d52e6e 432 * Controls how to use mount optionssource and target paths from fstab/mountinfo.
374fd21a 433 *
e9d52e6e 434 * @MNT_OMODE_IGNORE: ignore fstab options
cad39614 435 *
e9d52e6e 436 * @MNT_OMODE_APPEND: append fstab options to existing options
cad39614 437 *
e9d52e6e 438 * @MNT_OMODE_PREPEND: prepend fstab options to existing options
cad39614 439 *
e9d52e6e 440 * @MNT_OMODE_REPLACE: replace existing options with options from fstab
374fd21a 441 *
e9d52e6e 442 * @MNT_OMODE_FORCE: always read fstab (although source and target are defined)
374fd21a
KZ
443 *
444 * @MNT_OMODE_FSTAB: read from fstab
cad39614 445 *
e9d52e6e 446 * @MNT_OMODE_MTAB: read from mountinfo if fstab not enabled or failed
cad39614 447 *
e9d52e6e 448 * @MNT_OMODE_NOTAB: do not read fstab/mountinfoat all
374fd21a
KZ
449 *
450 * @MNT_OMODE_AUTO: default mode (MNT_OMODE_PREPEND | MNT_OMODE_FSTAB | MNT_OMODE_MTAB)
cad39614 451 *
374fd21a
KZ
452 * @MNT_OMODE_USER: default for non-root users (MNT_OMODE_REPLACE | MNT_OMODE_FORCE | MNT_OMODE_FSTAB)
453 *
454 * Notes:
455 *
456 * - MNT_OMODE_USER is always used if mount context is in restricted mode
d58b3157
OO
457 * - MNT_OMODE_AUTO is used if nothing else is defined
458 * - the flags are evaluated in this order: MNT_OMODE_NOTAB, MNT_OMODE_FORCE,
e9d52e6e 459 * MNT_OMODE_FSTAB, MNT_OMODE_MTAB and then the mount options from fstab/mountinfo
aa1c7a76 460 * are set according to MNT_OMODE_{IGNORE,APPEND,PREPEND,REPLACE}
c68408c2
KZ
461 *
462 * Returns: 0 on success, negative number in case of error.
463 */
68164f6c 464int mnt_context_set_optsmode(struct libmnt_context *cxt, int mode)
c68408c2
KZ
465{
466 if (!cxt)
467 return -EINVAL;
468 cxt->optsmode = mode;
469 return 0;
470}
471
68e9d35c
KZ
472/**
473 * mnt_context_get_optsmode
474 * @cxt: mount context
475 *
94c7fa6e 476 * Returns: MNT_OMODE_* mask or zero.
68e9d35c
KZ
477 */
478
68164f6c 479int mnt_context_get_optsmode(struct libmnt_context *cxt)
68e9d35c 480{
ba2bdf41 481 return cxt->optsmode;
68e9d35c
KZ
482}
483
c68408c2
KZ
484/**
485 * mnt_context_disable_canonicalize:
486 * @cxt: mount context
487 * @disable: TRUE or FALSE
488 *
489 * Enable/disable paths canonicalization and tags evaluation. The libmount context
d58b3157 490 * canonicalizes paths when searching in fstab and when preparing source and target paths
c68408c2
KZ
491 * for mount(2) syscall.
492 *
9e930041 493 * This function has an effect on the private (within context) fstab instance only
379e8439 494 * (see mnt_context_set_fstab()). If you want to use an external fstab then you
d58b3157 495 * need to manage your private struct libmnt_cache (see mnt_table_set_cache(fstab,
379e8439 496 * NULL).
c68408c2
KZ
497 *
498 * Returns: 0 on success, negative number in case of error.
499 */
68164f6c 500int mnt_context_disable_canonicalize(struct libmnt_context *cxt, int disable)
c68408c2 501{
1bb1d80b 502 return set_flag(cxt, MNT_FL_NOCANONICALIZE, disable);
c68408c2
KZ
503}
504
379e8439
KZ
505/**
506 * mnt_context_is_nocanonicalize:
507 * @cxt: mount context
508 *
a904aefe 509 * Returns: 1 if no-canonicalize mode (on [u]mount command line) is enabled or 0.
379e8439
KZ
510 */
511int mnt_context_is_nocanonicalize(struct libmnt_context *cxt)
512{
372d410d 513 return cxt->flags & MNT_FL_NOCANONICALIZE ? 1 : 0;
379e8439
KZ
514}
515
a904aefe
KZ
516
517/*
518 * Returns 1 if "x-mount.nocanonicalize[=<type>]" userspace mount option is
519 * specified. The optional arguments 'type' should be "source" or "target".
520 */
521int mnt_context_is_xnocanonicalize(
522 struct libmnt_context *cxt,
523 const char *type)
524{
525 struct libmnt_optlist *ol;
526 struct libmnt_opt *opt;
527 const char *arg;
528
529 assert(cxt);
530 assert(type);
531
a904aefe
KZ
532 ol = mnt_context_get_optlist(cxt);
533 if (!ol)
534 return 0;
535 opt = mnt_optlist_get_named(ol, "X-mount.nocanonicalize",
536 cxt->map_userspace);
537 if (!opt)
538 return 0;
539 arg = mnt_opt_get_value(opt);
540 if (!arg)
541 return 1;
542 return strcmp(arg, type) == 0;
543}
544
c68408c2
KZ
545/**
546 * mnt_context_enable_lazy:
547 * @cxt: mount context
548 * @enable: TRUE or FALSE
549 *
550 * Enable/disable lazy umount (see umount(8) man page, option -l).
551 *
552 * Returns: 0 on success, negative number in case of error.
553 */
68164f6c 554int mnt_context_enable_lazy(struct libmnt_context *cxt, int enable)
c68408c2 555{
1bb1d80b 556 return set_flag(cxt, MNT_FL_LAZY, enable);
c68408c2
KZ
557}
558
379e8439
KZ
559/**
560 * mnt_context_is_lazy:
561 * @cxt: mount context
562 *
563 * Returns: 1 if lazy umount is enabled or 0
564 */
565int mnt_context_is_lazy(struct libmnt_context *cxt)
566{
ba2bdf41 567 return cxt->flags & MNT_FL_LAZY ? 1 : 0;
379e8439
KZ
568}
569
3d1c41c8
KZ
570/**
571 * mnt_context_enable_onlyonce:
572 * @cxt: mount context
573 * @enable: TRUE or FALSE
574 *
575 * Enable/disable only-once mount (check if FS is not already mounted).
576 *
577 * Returns: 0 on success, negative number in case of error.
578 */
579int mnt_context_enable_onlyonce(struct libmnt_context *cxt, int enable)
580{
581 return set_flag(cxt, MNT_FL_ONLYONCE, enable);
582}
583
584/**
6d2917f2 585 * mnt_context_is_onlyonce:
3d1c41c8
KZ
586 * @cxt: mount context
587 *
6d2917f2 588 * Returns: 1 if only-once mount is enabled or 0
3d1c41c8
KZ
589 */
590int mnt_context_is_onlyonce(struct libmnt_context *cxt)
591{
592 return cxt->flags & MNT_FL_ONLYONCE ? 1 : 0;
593}
594
d2c97887
KZ
595/**
596 * mnt_context_enable_fork:
597 * @cxt: mount context
598 * @enable: TRUE or FALSE
599 *
600 * Enable/disable fork(2) call in mnt_context_next_mount() (see mount(8) man
601 * page, option -F).
602 *
603 * Returns: 0 on success, negative number in case of error.
604 */
605int mnt_context_enable_fork(struct libmnt_context *cxt, int enable)
606{
607 return set_flag(cxt, MNT_FL_FORK, enable);
608}
609
68e9d35c 610/**
379e8439 611 * mnt_context_is_fork:
68e9d35c
KZ
612 * @cxt: mount context
613 *
379e8439 614 * Returns: 1 if fork (mount -F) is enabled or 0
68e9d35c 615 */
379e8439 616int mnt_context_is_fork(struct libmnt_context *cxt)
68e9d35c 617{
ba2bdf41 618 return cxt->flags & MNT_FL_FORK ? 1 : 0;
68e9d35c
KZ
619}
620
379e8439
KZ
621/**
622 * mnt_context_is_parent:
623 * @cxt: mount context
624 *
625 * Return: 1 if mount -F enabled and the current context is parent, or 0
626 */
627int mnt_context_is_parent(struct libmnt_context *cxt)
628{
629 return mnt_context_is_fork(cxt) && cxt->pid == 0;
630}
631
632/**
633 * mnt_context_is_child:
634 * @cxt: mount context
635 *
d4f0f1cc 636 * Return: 1 f the current context is child, or 0
379e8439
KZ
637 */
638int mnt_context_is_child(struct libmnt_context *cxt)
639{
d4f0f1cc
KZ
640 /* See mnt_fork_context(), the for fork flag is always disabled
641 * for children to avoid recursive forking.
642 */
379e8439
KZ
643 return !mnt_context_is_fork(cxt) && cxt->pid;
644}
68e9d35c 645
ea8f06f9
KZ
646/**
647 * mnt_context_enable_rdonly_umount:
648 * @cxt: mount context
649 * @enable: TRUE or FALSE
650 *
651 * Enable/disable read-only remount on failed umount(2)
652 * (see umount(8) man page, option -r).
653 *
654 * Returns: 0 on success, negative number in case of error.
655 */
68164f6c 656int mnt_context_enable_rdonly_umount(struct libmnt_context *cxt, int enable)
ea8f06f9
KZ
657{
658 return set_flag(cxt, MNT_FL_RDONLY_UMOUNT, enable);
659}
660
68e9d35c
KZ
661/**
662 * mnt_context_is_rdonly_umount
663 * @cxt: mount context
664 *
d58b3157 665 * See also mnt_context_enable_rdonly_umount() and umount(8) man page,
68e9d35c
KZ
666 * option -r.
667 *
668 * Returns: 1 if read-only remount failed umount(2) is enables or 0
669 */
68164f6c 670int mnt_context_is_rdonly_umount(struct libmnt_context *cxt)
68e9d35c 671{
ba2bdf41 672 return cxt->flags & MNT_FL_RDONLY_UMOUNT ? 1 : 0;
68e9d35c
KZ
673}
674
6dede2f2
KZ
675/**
676 * mnt_context_enable_rwonly_mount:
677 * @cxt: mount context
678 * @enable: TRUE or FALSE
679 *
680 * Force read-write mount; if enabled libmount will never try MS_RDONLY
681 * after failed mount(2) EROFS. (See mount(8) man page, option -w).
682 *
a81b1946
KZ
683 * Since: 2.30
684 *
6dede2f2
KZ
685 * Returns: 0 on success, negative number in case of error.
686 */
687int mnt_context_enable_rwonly_mount(struct libmnt_context *cxt, int enable)
688{
689 return set_flag(cxt, MNT_FL_RWONLY_MOUNT, enable);
690}
691
692/**
693 * mnt_context_is_rwonly_mount
694 * @cxt: mount context
695 *
696 * See also mnt_context_enable_rwonly_mount() and mount(8) man page,
697 * option -w.
698 *
a81b1946
KZ
699 * Since: 2.30
700 *
6dede2f2
KZ
701 * Returns: 1 if only read-write mount is allowed.
702 */
703int mnt_context_is_rwonly_mount(struct libmnt_context *cxt)
704{
705 return cxt->flags & MNT_FL_RWONLY_MOUNT ? 1 : 0;
706}
707
708/**
709 * mnt_context_forced_rdonly:
710 * @cxt: mount context
711 *
712 * See also mnt_context_enable_rwonly_mount().
713 *
a81b1946
KZ
714 * Since: 2.30
715 *
6dede2f2
KZ
716 * Returns: 1 if mounted read-only on write-protected device.
717 */
718int mnt_context_forced_rdonly(struct libmnt_context *cxt)
719{
720 return cxt->flags & MNT_FL_FORCED_RDONLY ? 1 : 0;
721}
722
c68408c2
KZ
723/**
724 * mnt_context_disable_helpers:
725 * @cxt: mount context
726 * @disable: TRUE or FALSE
727 *
728 * Enable/disable /sbin/[u]mount.* helpers (see mount(8) man page, option -i).
729 *
730 * Returns: 0 on success, negative number in case of error.
731 */
68164f6c 732int mnt_context_disable_helpers(struct libmnt_context *cxt, int disable)
c68408c2 733{
1bb1d80b 734 return set_flag(cxt, MNT_FL_NOHELPERS, disable);
c68408c2
KZ
735}
736
379e8439
KZ
737/**
738 * mnt_context_is_nohelpers
739 * @cxt: mount context
740 *
741 * Returns: 1 if helpers are disabled (mount -i) or 0
742 */
743int mnt_context_is_nohelpers(struct libmnt_context *cxt)
744{
ba2bdf41 745 return cxt->flags & MNT_FL_NOHELPERS ? 1 : 0;
379e8439
KZ
746}
747
748
c68408c2
KZ
749/**
750 * mnt_context_enable_sloppy:
751 * @cxt: mount context
752 * @enable: TRUE or FALSE
753 *
754 * Set/unset sloppy mounting (see mount(8) man page, option -s).
755 *
756 * Returns: 0 on success, negative number in case of error.
757 */
68164f6c 758int mnt_context_enable_sloppy(struct libmnt_context *cxt, int enable)
c68408c2 759{
1bb1d80b 760 return set_flag(cxt, MNT_FL_SLOPPY, enable);
c68408c2
KZ
761}
762
68e9d35c
KZ
763/**
764 * mnt_context_is_sloppy:
765 * @cxt: mount context
766 *
767 * Returns: 1 if sloppy flag is enabled or 0
768 */
68164f6c 769int mnt_context_is_sloppy(struct libmnt_context *cxt)
68e9d35c 770{
ba2bdf41 771 return cxt->flags & MNT_FL_SLOPPY ? 1 : 0;
68e9d35c
KZ
772}
773
c68408c2
KZ
774/**
775 * mnt_context_enable_fake:
776 * @cxt: mount context
777 * @enable: TRUE or FALSE
778 *
779 * Enable/disable fake mounting (see mount(8) man page, option -f).
780 *
781 * Returns: 0 on success, negative number in case of error.
782 */
68164f6c 783int mnt_context_enable_fake(struct libmnt_context *cxt, int enable)
c68408c2 784{
1bb1d80b 785 return set_flag(cxt, MNT_FL_FAKE, enable);
c68408c2
KZ
786}
787
68e9d35c
KZ
788/**
789 * mnt_context_is_fake:
790 * @cxt: mount context
791 *
792 * Returns: 1 if fake flag is enabled or 0
793 */
68164f6c 794int mnt_context_is_fake(struct libmnt_context *cxt)
68e9d35c 795{
ba2bdf41 796 return cxt->flags & MNT_FL_FAKE ? 1 : 0;
68e9d35c
KZ
797}
798
c68408c2
KZ
799/**
800 * mnt_context_disable_mtab:
801 * @cxt: mount context
802 * @disable: TRUE or FALSE
803 *
e9d52e6e
KZ
804 * Disable/enable userspace mount table update (see mount(8) man page,
805 * option -n). Originally /etc/mtab, now /run/mount/utab.
c68408c2
KZ
806 *
807 * Returns: 0 on success, negative number in case of error.
808 */
68164f6c 809int mnt_context_disable_mtab(struct libmnt_context *cxt, int disable)
c68408c2 810{
1bb1d80b 811 return set_flag(cxt, MNT_FL_NOMTAB, disable);
c68408c2
KZ
812}
813
68e9d35c 814/**
e39cbb76 815 * mnt_context_is_nomtab:
68e9d35c
KZ
816 * @cxt: mount context
817 *
818 * Returns: 1 if no-mtab is enabled or 0
819 */
68164f6c 820int mnt_context_is_nomtab(struct libmnt_context *cxt)
68e9d35c 821{
ba2bdf41 822 return cxt->flags & MNT_FL_NOMTAB ? 1 : 0;
68e9d35c
KZ
823}
824
e39cbb76
KZ
825/**
826 * mnt_context_disable_swapmatch:
827 * @cxt: mount context
828 * @disable: TRUE or FALSE
829 *
830 * Disable/enable swap between source and target for mount(8) if only one path
831 * is specified.
832 *
833 * Returns: 0 on success, negative number in case of error.
834 */
835int mnt_context_disable_swapmatch(struct libmnt_context *cxt, int disable)
836{
837 return set_flag(cxt, MNT_FL_NOSWAPMATCH, disable);
838}
839
840/**
841 * mnt_context_is_swapmatch:
842 * @cxt: mount context
843 *
844 * Returns: 1 if swap between source and target is allowed (default is 1) or 0.
845 */
846int mnt_context_is_swapmatch(struct libmnt_context *cxt)
847{
ba2bdf41 848 return cxt->flags & MNT_FL_NOSWAPMATCH ? 0 : 1;
e39cbb76
KZ
849}
850
c68408c2
KZ
851/**
852 * mnt_context_enable_force:
853 * @cxt: mount context
854 * @enable: TRUE or FALSE
855 *
856 * Enable/disable force umounting (see umount(8) man page, option -f).
857 *
858 * Returns: 0 on success, negative number in case of error.
859 */
68164f6c 860int mnt_context_enable_force(struct libmnt_context *cxt, int enable)
c68408c2 861{
1bb1d80b 862 return set_flag(cxt, MNT_FL_FORCE, enable);
c68408c2
KZ
863}
864
68e9d35c
KZ
865/**
866 * mnt_context_is_force
867 * @cxt: mount context
868 *
869 * Returns: 1 if force umounting flag is enabled or 0
870 */
68164f6c 871int mnt_context_is_force(struct libmnt_context *cxt)
68e9d35c 872{
ba2bdf41 873 return cxt->flags & MNT_FL_FORCE ? 1 : 0;
68e9d35c
KZ
874}
875
c68408c2
KZ
876/**
877 * mnt_context_enable_verbose:
878 * @cxt: mount context
879 * @enable: TRUE or FALSE
880 *
0f32f1e2 881 * Enable/disable verbose output (TODO: not implemented yet)
c68408c2
KZ
882 *
883 * Returns: 0 on success, negative number in case of error.
884 */
68164f6c 885int mnt_context_enable_verbose(struct libmnt_context *cxt, int enable)
c68408c2 886{
1bb1d80b 887 return set_flag(cxt, MNT_FL_VERBOSE, enable);
c68408c2
KZ
888}
889
68e9d35c
KZ
890/**
891 * mnt_context_is_verbose
892 * @cxt: mount context
893 *
894 * Returns: 1 if verbose flag is enabled or 0
895 */
68164f6c 896int mnt_context_is_verbose(struct libmnt_context *cxt)
68e9d35c 897{
ba2bdf41 898 return cxt->flags & MNT_FL_VERBOSE ? 1 : 0;
68e9d35c
KZ
899}
900
c68408c2
KZ
901/**
902 * mnt_context_enable_loopdel:
903 * @cxt: mount context
904 * @enable: TRUE or FALSE
905 *
d58b3157 906 * Enable/disable the loop delete (destroy) after umount (see umount(8), option -d)
c68408c2
KZ
907 *
908 * Returns: 0 on success, negative number in case of error.
909 */
68164f6c 910int mnt_context_enable_loopdel(struct libmnt_context *cxt, int enable)
c68408c2 911{
1bb1d80b 912 return set_flag(cxt, MNT_FL_LOOPDEL, enable);
c68408c2
KZ
913}
914
379e8439
KZ
915/**
916 * mnt_context_is_loopdel:
917 * @cxt: mount context
918 *
919 * Returns: 1 if loop device should be deleted after umount (umount -d) or 0.
920 */
921int mnt_context_is_loopdel(struct libmnt_context *cxt)
922{
ba2bdf41 923 return cxt->flags & MNT_FL_LOOPDEL ? 1 : 0;
379e8439
KZ
924}
925
c68408c2
KZ
926/**
927 * mnt_context_set_fs:
928 * @cxt: mount context
929 * @fs: filesystem description
930 *
29e204d1 931 * The mount context uses private @fs by default. This function can be used to
26d0c0ae 932 * overwrite the private @fs with an external instance. This function
9e930041 933 * increments @fs reference counter (and decrement reference counter of the
26d0c0ae 934 * old fs).
c68408c2 935 *
76a06ca4 936 * The @fs will be modified by mnt_context_set_{source,target,options,fstype}
d58b3157
OO
937 * functions, If the @fs is NULL, then all current FS specific settings (source,
938 * target, etc., exclude spec) are reset.
c68408c2
KZ
939 *
940 * Returns: 0 on success, negative number in case of error.
941 */
68164f6c 942int mnt_context_set_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
c68408c2
KZ
943{
944 if (!cxt)
945 return -EINVAL;
c68408c2 946
7b37d5b5
KZ
947 if (cxt->fs == fs)
948 return 0;
949
e83c09d4 950 DBG(CXT, ul_debugobj(cxt, "setting new FS"));
7b37d5b5
KZ
951
952 /* new */
953 if (fs) {
954 struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
955
956 if (!ol)
957 return -ENOMEM;
958
959 mnt_ref_fs(fs);
960
961 mnt_optlist_set_optstr(ol, mnt_fs_get_options(fs), NULL);
962 mnt_fs_follow_optlist(fs, ol);
963 }
964
965 /* old */
966 if (cxt->fs)
967 mnt_fs_follow_optlist(cxt->fs, NULL);
968 mnt_unref_fs(cxt->fs);
969
c68408c2
KZ
970 cxt->fs = fs;
971 return 0;
972}
973
76a06ca4
KZ
974/**
975 * mnt_context_get_fs:
976 * @cxt: mount context
977 *
978 * The FS contains the basic description of mountpoint, fs type and so on.
979 * Note that the FS is modified by mnt_context_set_{source,target,options,fstype}
980 * functions.
981 *
d58b3157 982 * Returns: pointer to FS description or NULL in case of a calloc() error.
76a06ca4 983 */
68164f6c 984struct libmnt_fs *mnt_context_get_fs(struct libmnt_context *cxt)
1bb1d80b
KZ
985{
986 if (!cxt)
987 return NULL;
7b37d5b5
KZ
988 if (!cxt->fs) {
989 struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
990
991 if (!ol)
992 return NULL;
1bb1d80b 993 cxt->fs = mnt_new_fs();
7b37d5b5
KZ
994 if (!cxt->fs)
995 return NULL;
996
997 mnt_fs_follow_optlist(cxt->fs, ol);
998 }
1bb1d80b
KZ
999 return cxt->fs;
1000}
1001
32953aeb
KZ
1002/**
1003 * mnt_context_get_fs_userdata:
1004 * @cxt: mount context
1005 *
1006 * Returns: pointer to userdata or NULL.
1007 */
1008void *mnt_context_get_fs_userdata(struct libmnt_context *cxt)
1009{
32953aeb
KZ
1010 return cxt->fs ? mnt_fs_get_userdata(cxt->fs) : NULL;
1011}
1012
1013/**
1014 * mnt_context_get_fstab_userdata:
1015 * @cxt: mount context
1016 *
1017 * Returns: pointer to userdata or NULL.
1018 */
1019void *mnt_context_get_fstab_userdata(struct libmnt_context *cxt)
1020{
32953aeb
KZ
1021 return cxt->fstab ? mnt_table_get_userdata(cxt->fstab) : NULL;
1022}
1023
1024/**
1025 * mnt_context_get_mtab_userdata:
1026 * @cxt: mount context
1027 *
e9d52e6e
KZ
1028 * The file /etc/mtab is no more used, @context points always to mountinfo
1029 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
1030 * compatibility only.
1031 *
32953aeb
KZ
1032 * Returns: pointer to userdata or NULL.
1033 */
1034void *mnt_context_get_mtab_userdata(struct libmnt_context *cxt)
1035{
e9d52e6e 1036 return cxt->mountinfo ? mnt_table_get_userdata(cxt->mountinfo) : NULL;
32953aeb
KZ
1037}
1038
c68408c2
KZ
1039/**
1040 * mnt_context_set_source:
1041 * @cxt: mount context
1042 * @source: mount source (device, directory, UUID, LABEL, ...)
1043 *
b6bdccc7
KZ
1044 * Note that libmount does not interpret "nofail" (MNT_MS_NOFAIL)
1045 * mount option. The real return code is always returned, when
1046 * the device does not exist then it's usually MNT_ERR_NOSOURCE
9e930041 1047 * from libmount or ENOENT, ENOTDIR, ENOTBLK, ENXIO from mount(2).
b6bdccc7 1048 *
c68408c2
KZ
1049 * Returns: 0 on success, negative number in case of error.
1050 */
68164f6c 1051int mnt_context_set_source(struct libmnt_context *cxt, const char *source)
c68408c2
KZ
1052{
1053 return mnt_fs_set_source(mnt_context_get_fs(cxt), source);
1054}
1055
e95b3ca3
KZ
1056/**
1057 * mnt_context_get_source:
1058 * @cxt: mount context
1059 *
d58b3157 1060 * Returns: returns pointer or NULL in case of error or if not set.
e95b3ca3
KZ
1061 */
1062const char *mnt_context_get_source(struct libmnt_context *cxt)
1063{
1064 return mnt_fs_get_source(mnt_context_get_fs(cxt));
1065}
1066
c68408c2
KZ
1067/**
1068 * mnt_context_set_target:
1069 * @cxt: mount context
1070 * @target: mountpoint
1071 *
1072 * Returns: 0 on success, negative number in case of error.
1073 */
68164f6c 1074int mnt_context_set_target(struct libmnt_context *cxt, const char *target)
c68408c2
KZ
1075{
1076 return mnt_fs_set_target(mnt_context_get_fs(cxt), target);
1077}
1078
e95b3ca3
KZ
1079/**
1080 * mnt_context_get_target:
1081 * @cxt: mount context
1082 *
d58b3157 1083 * Returns: returns pointer or NULL in case of error or if not set.
e95b3ca3
KZ
1084 */
1085const char *mnt_context_get_target(struct libmnt_context *cxt)
1086{
1087 return mnt_fs_get_target(mnt_context_get_fs(cxt));
1088}
1089
71ed3b83
KZ
1090/**
1091 * mnt_context_set_target_prefix:
1092 * @cxt: mount context
1093 * @path: mountpoint prefix
1094 *
1095 * Returns: 0 on success, negative number in case of error.
1096 */
1097int mnt_context_set_target_prefix(struct libmnt_context *cxt, const char *path)
1098{
1099 char *p = NULL;
1100
1101 if (!cxt)
1102 return -EINVAL;
1103 if (path) {
1104 p = strdup(path);
1105 if (!p)
1106 return -ENOMEM;
1107 }
1108 free(cxt->tgt_prefix);
1109 cxt->tgt_prefix = p;
1110
1111 return 0;
1112}
1113
1114/**
1115 * mnt_context_get_target_prefix:
1116 * @cxt: mount context
1117 *
1118 * Returns: returns pointer or NULL in case of error or if not set.
1119 */
1120const char *mnt_context_get_target_prefix(struct libmnt_context *cxt)
1121{
1122 return cxt ? cxt->tgt_prefix : NULL;
1123}
1124
1125
c68408c2
KZ
1126/**
1127 * mnt_context_set_fstype:
1128 * @cxt: mount context
1129 * @fstype: filesystem type
1130 *
d58b3157
OO
1131 * Note that the @fstype has to be a FS type. For patterns with
1132 * comma-separated list of filesystems or for the "nofs" notation, use
bbf9ce79 1133 * mnt_context_set_fstype_pattern().
c68408c2
KZ
1134 *
1135 * Returns: 0 on success, negative number in case of error.
1136 */
68164f6c 1137int mnt_context_set_fstype(struct libmnt_context *cxt, const char *fstype)
c68408c2
KZ
1138{
1139 return mnt_fs_set_fstype(mnt_context_get_fs(cxt), fstype);
1140}
1141
e95b3ca3
KZ
1142/**
1143 * mnt_context_get_fstype:
1144 * @cxt: mount context
1145 *
d58b3157 1146 * Returns: pointer or NULL in case of error or if not set.
e95b3ca3
KZ
1147 */
1148const char *mnt_context_get_fstype(struct libmnt_context *cxt)
1149{
1150 return mnt_fs_get_fstype(mnt_context_get_fs(cxt));
1151}
1152
9a72da2c
KZ
1153struct libmnt_optlist *mnt_context_get_optlist(struct libmnt_context *cxt)
1154{
1155 if (!cxt)
1156 return NULL;
93c4f825
KZ
1157 if (!cxt->optlist) {
1158 cxt->optlist = mnt_new_optlist();
1159 if (!cxt->optlist)
1160 return NULL;
93c0f69d 1161 if (mnt_optlist_register_map(cxt->optlist, cxt->map_linux))
93c4f825 1162 goto fail;
93c0f69d 1163 if (mnt_optlist_register_map(cxt->optlist, cxt->map_userspace))
93c4f825
KZ
1164 goto fail;
1165 }
9a72da2c 1166
93c4f825
KZ
1167 return cxt->optlist;
1168fail:
1169 mnt_unref_optlist(cxt->optlist);
1170 return NULL;
9a72da2c
KZ
1171}
1172
c68408c2 1173/**
76a06ca4 1174 * mnt_context_set_options:
c68408c2 1175 * @cxt: mount context
0f32f1e2 1176 * @optstr: comma delimited mount options
c68408c2 1177 *
ca793296
KZ
1178 * Please note that MS_MOVE cannot be specified as a "string". The move operation
1179 * cannot be specified in fstab.
6691d537 1180 *
c68408c2
KZ
1181 * Returns: 0 on success, negative number in case of error.
1182 */
68164f6c 1183int mnt_context_set_options(struct libmnt_context *cxt, const char *optstr)
c68408c2 1184{
9a72da2c
KZ
1185 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1186
1187 if (!ls)
1188 return -ENOMEM;
1189 return mnt_optlist_set_optstr(ls, optstr, NULL);
c68408c2
KZ
1190}
1191
1192/**
76a06ca4 1193 * mnt_context_append_options:
c68408c2
KZ
1194 * @cxt: mount context
1195 * @optstr: comma delimited mount options
1196 *
1197 * Returns: 0 on success, negative number in case of error.
1198 */
68164f6c 1199int mnt_context_append_options(struct libmnt_context *cxt, const char *optstr)
c68408c2 1200{
9a72da2c
KZ
1201 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1202
1203 if (!ls)
1204 return -ENOMEM;
1205 return mnt_optlist_append_optstr(ls, optstr, NULL);
c68408c2
KZ
1206}
1207
5d451abb
KZ
1208/**
1209 * mnt_context_get_options:
1210 * @cxt: mount context
1211 *
9a72da2c
KZ
1212 * This function returns mount options set by mnt_context_set_options(),
1213 * mnt_context_append_options() or mnt_context_set_mflags();
5d451abb 1214 *
9a72da2c
KZ
1215 * Before v2.39 this function ignored options specified by flags (see
1216 * mnt_context_set_mflags()) before mnt_context_prepare_mount() call. Now this
1217 * function always returns all mount options.
5d451abb
KZ
1218 *
1219 * Returns: pointer or NULL
1220 */
1221const char *mnt_context_get_options(struct libmnt_context *cxt)
1222{
9a72da2c
KZ
1223 const char *str = NULL;
1224
01790c7d
KZ
1225 if (cxt->optlist && !mnt_optlist_is_empty(cxt->optlist))
1226 mnt_optlist_get_optstr(cxt->optlist, &str, NULL, 0);
9a72da2c 1227 return str;
5d451abb
KZ
1228}
1229
c68408c2
KZ
1230/**
1231 * mnt_context_set_fstype_pattern:
1232 * @cxt: mount context
1233 * @pattern: FS name pattern (or NULL to reset the current setting)
1234 *
1235 * See mount(8), option -t.
1236 *
1237 * Returns: 0 on success, negative number in case of error.
1238 */
68164f6c 1239int mnt_context_set_fstype_pattern(struct libmnt_context *cxt, const char *pattern)
c68408c2
KZ
1240{
1241 char *p = NULL;
1242
1243 if (!cxt)
1244 return -EINVAL;
1245 if (pattern) {
1246 p = strdup(pattern);
1247 if (!p)
1248 return -ENOMEM;
1249 }
1250 free(cxt->fstype_pattern);
1251 cxt->fstype_pattern = p;
1252 return 0;
1253}
1254
1255/**
76a06ca4 1256 * mnt_context_set_options_pattern:
c68408c2
KZ
1257 * @cxt: mount context
1258 * @pattern: options pattern (or NULL to reset the current setting)
1259 *
1260 * See mount(8), option -O.
1261 *
1262 * Returns: 0 on success, negative number in case of error.
1263 */
68164f6c 1264int mnt_context_set_options_pattern(struct libmnt_context *cxt, const char *pattern)
c68408c2
KZ
1265{
1266 char *p = NULL;
1267
1268 if (!cxt)
1269 return -EINVAL;
1270 if (pattern) {
1271 p = strdup(pattern);
1272 if (!p)
1273 return -ENOMEM;
1274 }
1275 free(cxt->optstr_pattern);
1276 cxt->optstr_pattern = p;
1277 return 0;
1278}
1279
1280/**
1281 * mnt_context_set_fstab:
1282 * @cxt: mount context
1283 * @tb: fstab
1284 *
ef75bc88 1285 * The mount context reads /etc/fstab to the private struct libmnt_table by default.
29e204d1 1286 * This function can be used to overwrite the private fstab with an external
c9f1585e
KZ
1287 * instance.
1288 *
1289 * This function modify the @tb reference counter. This function does not set
1290 * the cache for the @tb. You have to explicitly call mnt_table_set_cache(tb,
1291 * mnt_context_get_cache(cxt));
c68408c2
KZ
1292 *
1293 * The fstab is used read-only and is not modified, it should be possible to
d58b3157 1294 * share the fstab between more mount contexts (TODO: test it.)
c68408c2 1295 *
d58b3157
OO
1296 * If the @tb argument is NULL, then the current private fstab instance is
1297 * reset.
c68408c2
KZ
1298 *
1299 * Returns: 0 on success, negative number in case of error.
1300 */
68164f6c 1301int mnt_context_set_fstab(struct libmnt_context *cxt, struct libmnt_table *tb)
c68408c2
KZ
1302{
1303 if (!cxt)
1304 return -EINVAL;
c68408c2 1305
c9f1585e
KZ
1306 mnt_ref_table(tb); /* new */
1307 mnt_unref_table(cxt->fstab); /* old */
1308
c68408c2
KZ
1309 cxt->fstab = tb;
1310 return 0;
1311}
1312
cf94e97f
KZ
1313/**
1314 * mnt_context_get_fstab:
1315 * @cxt: mount context
1316 * @tb: returns fstab
1317 *
68164f6c 1318 * See also mnt_table_parse_fstab() for more details about fstab.
cf94e97f
KZ
1319 *
1320 * Returns: 0 on success, negative number in case of error.
1321 */
68164f6c 1322int mnt_context_get_fstab(struct libmnt_context *cxt, struct libmnt_table **tb)
cf94e97f 1323{
cddd2eaa
VD
1324 struct libmnt_ns *ns_old;
1325
cf94e97f
KZ
1326 if (!cxt)
1327 return -EINVAL;
cf94e97f
KZ
1328 if (!cxt->fstab) {
1329 int rc;
1330
68164f6c 1331 cxt->fstab = mnt_new_table();
cf94e97f
KZ
1332 if (!cxt->fstab)
1333 return -ENOMEM;
d84508cf
KZ
1334 if (cxt->table_errcb)
1335 mnt_table_set_parser_errcb(cxt->fstab, cxt->table_errcb);
cddd2eaa
VD
1336
1337 ns_old = mnt_context_switch_target_ns(cxt);
1338 if (!ns_old)
1339 return -MNT_ERR_NAMESPACE;
1340
c9f1585e 1341 mnt_table_set_cache(cxt->fstab, mnt_context_get_cache(cxt));
68164f6c 1342 rc = mnt_table_parse_fstab(cxt->fstab, NULL);
cddd2eaa
VD
1343
1344 if (!mnt_context_switch_ns(cxt, ns_old))
1345 return -MNT_ERR_NAMESPACE;
1346
cf94e97f
KZ
1347 if (rc)
1348 return rc;
1349 }
1350
cf94e97f
KZ
1351 if (tb)
1352 *tb = cxt->fstab;
1353 return 0;
1354}
1355
e9d52e6e 1356int mnt_context_get_mountinfo(struct libmnt_context *cxt, struct libmnt_table **tb)
cf94e97f 1357{
cddd2eaa
VD
1358 int rc = 0;
1359 struct libmnt_ns *ns_old = NULL;
1360
cf94e97f
KZ
1361 if (!cxt)
1362 return -EINVAL;
e9d52e6e 1363 if (!cxt->mountinfo) {
cddd2eaa
VD
1364 ns_old = mnt_context_switch_target_ns(cxt);
1365 if (!ns_old)
1366 return -MNT_ERR_NAMESPACE;
cf94e97f 1367
150e696d
KZ
1368 context_init_paths(cxt, 0);
1369
e9d52e6e
KZ
1370 cxt->mountinfo = mnt_new_table();
1371 if (!cxt->mountinfo) {
cddd2eaa
VD
1372 rc = -ENOMEM;
1373 goto end;
1374 }
e5c5abae 1375
22147e08
IK
1376 mnt_table_enable_noautofs(cxt->mountinfo, cxt->noautofs);
1377
d84508cf 1378 if (cxt->table_errcb)
e9d52e6e 1379 mnt_table_set_parser_errcb(cxt->mountinfo, cxt->table_errcb);
4709c9e6 1380 if (cxt->table_fltrcb)
e9d52e6e 1381 mnt_table_set_parser_fltrcb(cxt->mountinfo,
4709c9e6
KZ
1382 cxt->table_fltrcb,
1383 cxt->table_fltrcb_data);
e5c5abae 1384
e9d52e6e 1385 mnt_table_set_cache(cxt->mountinfo, mnt_context_get_cache(cxt));
b8f2fce2
KZ
1386 }
1387
e9d52e6e 1388 /* Read the table; it's empty, because this first mnt_context_get_mountinfo()
b8f2fce2 1389 * call, or because /proc was not accessible in previous calls */
e9d52e6e 1390 if (mnt_table_is_empty(cxt->mountinfo)) {
b8f2fce2
KZ
1391 if (!ns_old) {
1392 ns_old = mnt_context_switch_target_ns(cxt);
1393 if (!ns_old)
1394 return -MNT_ERR_NAMESPACE;
1395 }
e778642a 1396
e9d52e6e 1397 rc = __mnt_table_parse_mountinfo(cxt->mountinfo, NULL, cxt->utab);
cf94e97f 1398 if (rc)
cddd2eaa 1399 goto end;
cf94e97f
KZ
1400 }
1401
cf94e97f 1402 if (tb)
e9d52e6e 1403 *tb = cxt->mountinfo;
9be1607f 1404
e9d52e6e
KZ
1405 DBG(CXT, ul_debugobj(cxt, "mountinfo requested [nents=%d]",
1406 mnt_table_get_nents(cxt->mountinfo)));
cddd2eaa
VD
1407
1408end:
1409 if (ns_old && !mnt_context_switch_ns(cxt, ns_old))
1410 return -MNT_ERR_NAMESPACE;
1411
1412 return rc;
e5c5abae
KZ
1413}
1414
e9d52e6e
KZ
1415/**
1416 * mnt_context_get_mtab:
1417 * @cxt: mount context
1418 * @tb: returns mtab
1419 *
1420 * Parse /proc/self/mountinfo mount table.
1421 *
1422 * The file /etc/mtab is no more used, @context points always to mountinfo
1423 * (/proc/self/mountinfo). The function uses "mtab" in the name for backward
1424 * compatibility only.
1425 *
1426 * See also mnt_table_parse_mtab() for more details about mountinfo. The
1427 * result will be deallocated by mnt_free_context(@cxt).
1428 *
1429 * Returns: 0 on success, negative number in case of error.
1430 */
1431int mnt_context_get_mtab(struct libmnt_context *cxt, struct libmnt_table **tb)
1432{
1433 return mnt_context_get_mountinfo(cxt, tb);
1434}
1435
7deae03f 1436/*
e9d52e6e 1437 * Called by mountinfo parser to filter out entries, non-zero means that
7deae03f
KZ
1438 * an entry has to be filtered out.
1439 */
e9d52e6e 1440static int mountinfo_filter(struct libmnt_fs *fs, void *data)
7deae03f
KZ
1441{
1442 if (!fs || !data)
1443 return 0;
1444 if (mnt_fs_streq_target(fs, data))
1445 return 0;
1446 if (mnt_fs_streq_srcpath(fs, data))
1447 return 0;
1448 return 1;
1449}
1450
1451/*
e9d52e6e 1452 * The same like mnt_context_get_mountinfo(), but does not read all mountinfo
7deae03f
KZ
1453 * file, but only entries relevant for @tgt.
1454 */
e9d52e6e
KZ
1455int mnt_context_get_mountinfo_for_target(struct libmnt_context *cxt,
1456 struct libmnt_table **mountinfo,
7deae03f
KZ
1457 const char *tgt)
1458{
1459 struct stat st;
1460 struct libmnt_cache *cache = NULL;
1461 char *cn_tgt = NULL;
1462 int rc;
cddd2eaa
VD
1463 struct libmnt_ns *ns_old;
1464
1465 ns_old = mnt_context_switch_target_ns(cxt);
1466 if (!ns_old)
1467 return -MNT_ERR_NAMESPACE;
7deae03f 1468
f8416301 1469 if (mnt_context_is_nocanonicalize(cxt))
e9d52e6e 1470 mnt_context_set_tabfilter(cxt, mountinfo_filter, (void *) tgt);
f8416301 1471
f2663ba7 1472 else if (mnt_safe_stat(tgt, &st) == 0 && S_ISDIR(st.st_mode)) {
7deae03f
KZ
1473 cache = mnt_context_get_cache(cxt);
1474 cn_tgt = mnt_resolve_path(tgt, cache);
1475 if (cn_tgt)
e9d52e6e 1476 mnt_context_set_tabfilter(cxt, mountinfo_filter, cn_tgt);
7deae03f
KZ
1477 }
1478
e9d52e6e 1479 rc = mnt_context_get_mountinfo(cxt, mountinfo);
f8416301 1480 mnt_context_set_tabfilter(cxt, NULL, NULL);
7deae03f 1481
cddd2eaa
VD
1482 if (!mnt_context_switch_ns(cxt, ns_old))
1483 return -MNT_ERR_NAMESPACE;
1484
f8416301
KZ
1485 if (cn_tgt && !cache)
1486 free(cn_tgt);
7deae03f
KZ
1487
1488 return rc;
1489}
1490
4709c9e6 1491/*
d58b3157 1492 * Allows to specify a filter for tab file entries. The filter is called by
e9d52e6e 1493 * the table parser. Currently used for utab only.
4709c9e6
KZ
1494 */
1495int mnt_context_set_tabfilter(struct libmnt_context *cxt,
1496 int (*fltr)(struct libmnt_fs *, void *),
1497 void *data)
1498{
1499 if (!cxt)
1500 return -EINVAL;
1501
1502 cxt->table_fltrcb = fltr;
1503 cxt->table_fltrcb_data = data;
1504
e9d52e6e
KZ
1505 if (cxt->mountinfo)
1506 mnt_table_set_parser_fltrcb(cxt->mountinfo,
4709c9e6
KZ
1507 cxt->table_fltrcb,
1508 cxt->table_fltrcb_data);
1509
83a78332 1510 DBG(CXT, ul_debugobj(cxt, "tabfilter %s", fltr ? "ENABLED!" : "disabled"));
4709c9e6
KZ
1511 return 0;
1512}
1513
e5c5abae
KZ
1514/**
1515 * mnt_context_get_table:
1516 * @cxt: mount context
e6ecd606 1517 * @filename: e.g. /proc/self/mountinfo
e5c5abae
KZ
1518 * @tb: returns the table
1519 *
1520 * This function allocates a new table and parses the @file. The parser error
1521 * callback and cache for tags and paths is set according to the @cxt setting.
1522 * See also mnt_table_parse_file().
1523 *
d58b3157 1524 * It's strongly recommended to use the mnt_context_get_mtab() and
e9d52e6e 1525 * mnt_context_get_fstab() functions for mountinfo and fstab files. This function
e5c5abae
KZ
1526 * does not care about LIBMOUNT_* env.variables and does not merge userspace
1527 * options.
1528 *
1529 * The result will NOT be deallocated by mnt_free_context(@cxt).
1530 *
1531 * Returns: 0 on success, negative number in case of error.
1532 */
1533int mnt_context_get_table(struct libmnt_context *cxt,
1534 const char *filename, struct libmnt_table **tb)
1535{
e5c5abae 1536 int rc;
cddd2eaa 1537 struct libmnt_ns *ns_old;
e5c5abae
KZ
1538
1539 if (!cxt || !tb)
1540 return -EINVAL;
1541
1542 *tb = mnt_new_table();
1543 if (!*tb)
1544 return -ENOMEM;
1545
1546 if (cxt->table_errcb)
1547 mnt_table_set_parser_errcb(*tb, cxt->table_errcb);
1548
cddd2eaa
VD
1549 ns_old = mnt_context_switch_target_ns(cxt);
1550 if (!ns_old)
1551 return -MNT_ERR_NAMESPACE;
1552
e5c5abae 1553 rc = mnt_table_parse_file(*tb, filename);
cddd2eaa 1554
e5c5abae 1555 if (rc) {
c9f1585e 1556 mnt_unref_table(*tb);
cddd2eaa 1557 goto end;
e5c5abae
KZ
1558 }
1559
0105691d 1560 mnt_table_set_cache(*tb, mnt_context_get_cache(cxt));
cddd2eaa
VD
1561
1562end:
1563 if (!mnt_context_switch_ns(cxt, ns_old))
1564 return -MNT_ERR_NAMESPACE;
1565
1566 return rc;
cf94e97f
KZ
1567}
1568
d84508cf
KZ
1569/**
1570 * mnt_context_set_tables_errcb
1571 * @cxt: mount context
1572 * @cb: pointer to callback function
1573 *
e9d52e6e 1574 * The error callback is used for all tab files (e.g. mountinfo, fstab)
d84508cf
KZ
1575 * parsed within the context.
1576 *
1577 * See also mnt_context_get_mtab(),
1578 * mnt_context_get_fstab(),
1579 * mnt_table_set_parser_errcb().
1580 *
1581 * Returns: 0 on success, negative number in case of error.
1582 */
1583int mnt_context_set_tables_errcb(struct libmnt_context *cxt,
1584 int (*cb)(struct libmnt_table *tb, const char *filename, int line))
1585{
1586 if (!cxt)
1587 return -EINVAL;
1588
e9d52e6e
KZ
1589 if (cxt->mountinfo)
1590 mnt_table_set_parser_errcb(cxt->mountinfo, cb);
c9f1585e
KZ
1591 if (cxt->fstab)
1592 mnt_table_set_parser_errcb(cxt->fstab, cb);
1593
d84508cf
KZ
1594 cxt->table_errcb = cb;
1595 return 0;
1596}
1597
c68408c2
KZ
1598/**
1599 * mnt_context_set_cache:
1600 * @cxt: mount context
9e930041 1601 * @cache: cache instance or NULL
c68408c2 1602 *
0105691d 1603 * The mount context maintains a private struct libmnt_cache by default. This
29e204d1 1604 * function can be used to overwrite the private cache with an external instance.
0105691d 1605 * This function increments cache reference counter.
c68408c2 1606 *
c9f1585e 1607 * If the @cache argument is NULL, then the current cache instance is reset.
e9d52e6e 1608 * This function apply the cache to fstab and mountinfo instances (if already
c9f1585e 1609 * exists).
c68408c2 1610 *
0105691d
KZ
1611 * The old cache instance reference counter is de-incremented.
1612 *
c68408c2
KZ
1613 * Returns: 0 on success, negative number in case of error.
1614 */
68164f6c 1615int mnt_context_set_cache(struct libmnt_context *cxt, struct libmnt_cache *cache)
c68408c2
KZ
1616{
1617 if (!cxt)
1618 return -EINVAL;
c68408c2 1619
0105691d
KZ
1620 mnt_ref_cache(cache); /* new */
1621 mnt_unref_cache(cxt->cache); /* old */
1622
c68408c2 1623 cxt->cache = cache;
c9f1585e 1624
e9d52e6e
KZ
1625 if (cxt->mountinfo)
1626 mnt_table_set_cache(cxt->mountinfo, cache);
c9f1585e
KZ
1627 if (cxt->fstab)
1628 mnt_table_set_cache(cxt->fstab, cache);
1629
c68408c2
KZ
1630 return 0;
1631}
1632
1bb1d80b
KZ
1633/**
1634 * mnt_context_get_cache
1635 * @cxt: mount context
1636 *
1637 * See also mnt_context_set_cache().
1638 *
1639 * Returns: pointer to cache or NULL if canonicalization is disabled.
1640 */
68164f6c 1641struct libmnt_cache *mnt_context_get_cache(struct libmnt_context *cxt)
c68408c2 1642{
379e8439 1643 if (!cxt || mnt_context_is_nocanonicalize(cxt))
c68408c2
KZ
1644 return NULL;
1645
1646 if (!cxt->cache) {
c9f1585e
KZ
1647 struct libmnt_cache *cache = mnt_new_cache();
1648 mnt_context_set_cache(cxt, cache);
1649 mnt_unref_cache(cache);
c68408c2
KZ
1650 }
1651 return cxt->cache;
1652}
1653
1a7a421e
KZ
1654/**
1655 * mnt_context_set_passwd_cb:
1656 * @cxt: mount context
ee314075 1657 * @get: callback to get password
9e930041 1658 * @release: callback to release (deallocate) password
1a7a421e 1659 *
90cd46cb 1660 * Sets callbacks for encryption password (e.g encrypted loopdev). This
d58b3157 1661 * function is deprecated (encrypted loops are no longer supported).
1a7a421e
KZ
1662 *
1663 * Returns: 0 on success, negative number in case of error.
1664 */
1665int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
1666 char *(*get)(struct libmnt_context *),
1667 void (*release)(struct libmnt_context *, char *))
1668{
1669 if (!cxt)
1670 return -EINVAL;
1a7a421e
KZ
1671 cxt->pwd_get_cb = get;
1672 cxt->pwd_release_cb = release;
1673 return 0;
1674}
1675
1bb1d80b
KZ
1676/**
1677 * mnt_context_get_lock:
1678 * @cxt: mount context
1679 *
e9d52e6e 1680 * The libmount applications don't have to care about utab locking, but with a
5976114f
KZ
1681 * small exception: the application has to be able to remove the lock file when
1682 * interrupted by signal or signals have to be ignored when the lock is locked.
1bb1d80b 1683 *
86cd5870 1684 * The default behavior is to ignore all signals (except SIGALRM and
e9d52e6e 1685 * SIGTRAP for utab update) when the lock is locked. If this behavior
d58b3157 1686 * is unacceptable, then use:
5976114f
KZ
1687 *
1688 * lc = mnt_context_get_lock(cxt);
1689 * if (lc)
1690 * mnt_lock_block_signals(lc, FALSE);
1691 *
1692 * and don't forget to call mnt_unlock_file(lc) before exit.
1693 *
1d0cd73f 1694 * Returns: pointer to lock struct or NULL.
1bb1d80b 1695 */
68164f6c 1696struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
1bb1d80b 1697{
86cd5870
KZ
1698 /*
1699 * DON'T call this function within libmount, it will always allocate
1700 * the lock. The mnt_update_* functions are able to allocate the lock
e9d52e6e 1701 * only when utab update is really necessary.
86cd5870 1702 */
379e8439 1703 if (!cxt || mnt_context_is_nomtab(cxt))
1bb1d80b 1704 return NULL;
1d0cd73f 1705
86cd5870 1706 if (!cxt->lock) {
150e696d
KZ
1707 cxt->lock = mnt_new_lock(
1708 mnt_context_get_writable_tabpath(cxt), 0);
5976114f
KZ
1709 if (cxt->lock)
1710 mnt_lock_block_signals(cxt->lock, TRUE);
1711 }
1d0cd73f 1712 return cxt->lock;
1bb1d80b
KZ
1713}
1714
c68408c2 1715/**
68164f6c 1716 * mnt_context_set_mflags:
c68408c2
KZ
1717 * @cxt: mount context
1718 * @flags: mount(2) flags (MS_* flags)
1719 *
68164f6c
KZ
1720 * Sets mount flags (see mount(2) man page).
1721 *
9a72da2c
KZ
1722 * Note that order of mount options (strings) and flags matter if you mix
1723 * mnt_context_append_options() and mnt_context_set_mflags().
e6a90b98 1724 *
9a72da2c
KZ
1725 * Be careful if use MS_REC flag -- this is flags is generic for
1726 * all mask. In this case is better to use options string where
1a02c7a7 1727 * mount options are independent and nothing is applied to all options.
816773b4 1728 *
c68408c2
KZ
1729 * Returns: 0 on success, negative number in case of error.
1730 */
68164f6c 1731int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
c68408c2 1732{
9a72da2c 1733 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
dc4dbbf1 1734
9a72da2c
KZ
1735 if (!ls)
1736 return -ENOMEM;
dc4dbbf1 1737
93c0f69d 1738 return mnt_optlist_set_flags(ls, flags, cxt->map_linux);
c68408c2
KZ
1739}
1740
1741/**
68164f6c 1742 * mnt_context_get_mflags:
c68408c2 1743 * @cxt: mount context
68164f6c 1744 * @flags: returns MS_* mount flags
c68408c2 1745 *
9e930041 1746 * Converts mount options string to MS_* flags and bitwise-OR the result with
d58b3157 1747 * the already defined flags (see mnt_context_set_mflags()).
c68408c2
KZ
1748 *
1749 * Returns: 0 on success, negative number in case of error.
1750 */
68164f6c 1751int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
c68408c2 1752{
9a72da2c 1753 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
56a21c93 1754
9a72da2c
KZ
1755 if (!ls)
1756 return -ENOMEM;
56a21c93 1757
b5a71296 1758 return mnt_optlist_get_flags(ls, flags, cxt->map_linux, 0);
c68408c2
KZ
1759}
1760
c68408c2 1761/**
68164f6c 1762 * mnt_context_set_user_mflags:
c68408c2
KZ
1763 * @cxt: mount context
1764 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1765 *
68164f6c
KZ
1766 * Sets userspace mount flags.
1767 *
d58b3157 1768 * See also notes for mnt_context_set_mflags().
e6a90b98 1769 *
c68408c2
KZ
1770 * Returns: 0 on success, negative number in case of error.
1771 */
68164f6c 1772int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
c68408c2 1773{
9a72da2c
KZ
1774 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1775
1776 if (!ls)
1777 return -ENOMEM;
1778
93c0f69d 1779 return mnt_optlist_set_flags(ls, flags, cxt->map_userspace);
c68408c2
KZ
1780}
1781
1782/**
68164f6c 1783 * mnt_context_get_user_mflags:
c68408c2
KZ
1784 * @cxt: mount context
1785 * @flags: returns mount flags
1786 *
9e930041 1787 * Converts mount options string to MNT_MS_* flags and bitwise-OR the result
d58b3157 1788 * with the already defined flags (see mnt_context_set_user_mflags()).
c68408c2
KZ
1789 *
1790 * Returns: 0 on success, negative number in case of error.
1791 */
68164f6c 1792int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
c68408c2 1793{
9a72da2c 1794 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
4569bbea 1795
9a72da2c
KZ
1796 if (!ls)
1797 return -ENOMEM;
c68408c2 1798
93c0f69d 1799 return mnt_optlist_get_flags(ls, flags, cxt->map_userspace, 0);
c68408c2
KZ
1800}
1801
c68408c2
KZ
1802/**
1803 * mnt_context_set_mountdata:
1804 * @cxt: mount context
1805 * @data: mount(2) data
1806 *
1807 * The mount context generates mountdata from mount options by default. This
29e204d1 1808 * function can be used to overwrite this behavior, and @data will be used instead
c68408c2
KZ
1809 * of mount options.
1810 *
d58b3157 1811 * The libmount does not deallocate the data by mnt_free_context(). Note that
c68408c2
KZ
1812 * NULL is also valid mount data.
1813 *
1814 * Returns: 0 on success, negative number in case of error.
1815 */
68164f6c 1816int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
c68408c2
KZ
1817{
1818 if (!cxt)
1819 return -EINVAL;
1820 cxt->mountdata = data;
1821 cxt->flags |= MNT_FL_MOUNTDATA;
1822 return 0;
1823}
1824
2a684833
KZ
1825#ifdef USE_LIBMOUNT_MOUNTFD_SUPPORT
1826int mnt_context_open_tree(struct libmnt_context *cxt, const char *path, unsigned long mflg)
1827{
1828 unsigned long oflg = OPEN_TREE_CLOEXEC;
1829 int rc = 0, fd = -1;
1830
1831 if (mflg == (unsigned long) -1) {
1832 rc = mnt_optlist_get_flags(cxt->optlist, &mflg, cxt->map_linux, 0);
1833 if (rc)
1834 return rc;
1835 }
1836 if (!path) {
1837 path = mnt_fs_get_target(cxt->fs);
1838 if (!path)
1839 return -EINVAL;
1840 }
1841
1842 /* Classic -oremount,bind,ro is not bind operation, it's just
1843 * VFS flags update only */
1844 if ((mflg & MS_BIND) && !(mflg & MS_REMOUNT)) {
1845 oflg |= OPEN_TREE_CLONE;
1846
03b2e73a
KZ
1847 /* AT_RECURSIVE is only permitted for OPEN_TREE_CLONE (rbind).
1848 * The other recursive operations are handled by
1849 * mount_setattr() and are independent of open_tree() */
2a684833
KZ
1850 if (mnt_optlist_is_rbind(cxt->optlist))
1851 oflg |= AT_RECURSIVE;
1852 }
1853
1854 if (cxt->force_clone)
1855 oflg |= OPEN_TREE_CLONE;
1856
22cda2f7
KZ
1857 if (mnt_context_is_xnocanonicalize(cxt, "source"))
1858 oflg |= AT_SYMLINK_NOFOLLOW;
1859
2a684833
KZ
1860 DBG(CXT, ul_debugobj(cxt, "open_tree(path=%s%s%s)", path,
1861 oflg & OPEN_TREE_CLONE ? " clone" : "",
1862 oflg & AT_RECURSIVE ? " recursive" : ""));
1863 fd = open_tree(AT_FDCWD, path, oflg);
1864 mnt_context_syscall_save_status(cxt, "open_tree", fd >= 0);
1865
1866 return fd;
1867}
1868#endif
1869
e6a90b98 1870/*
1bb1d80b 1871 * Translates LABEL/UUID/path to mountable path
e6a90b98 1872 */
68164f6c 1873int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
c68408c2 1874{
c59cf20c 1875 const char *path = NULL;
68164f6c 1876 struct libmnt_cache *cache;
372ce5b7 1877 const char *t, *v, *src, *type;
c68408c2 1878 int rc = 0;
cddd2eaa 1879 struct libmnt_ns *ns_old;
94d57d48 1880 struct libmnt_optlist *ol;
c68408c2 1881
1b56aae8
KZ
1882 assert(cxt);
1883 assert(cxt->fs);
1884 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1885
6ba7fbb4 1886 DBG(CXT, ul_debugobj(cxt, "--> preparing source path"));
1b56aae8 1887
c68408c2
KZ
1888 src = mnt_fs_get_source(cxt->fs);
1889
6498ece0 1890 if (!src && mnt_context_propagation_only(cxt))
41d6af28
KZ
1891 /* mount --make-{shared,private,...} */
1892 return mnt_fs_set_source(cxt->fs, "none");
1893
c59cf20c 1894 /* ignore filesystems without source or filesystems
d58b3157 1895 * where the source is a quasi-path (//foo/bar)
c59cf20c 1896 */
c70d9d76 1897 if (!src || mnt_fs_is_netfs(cxt->fs))
c68408c2
KZ
1898 return 0;
1899
372ce5b7
KZ
1900 /* ZFS source is always "dataset", not a real path */
1901 type = mnt_fs_get_fstype(cxt->fs);
1902 if (type && strcmp(type, "zfs") == 0)
1903 return 0;
1904
83a78332 1905 DBG(CXT, ul_debugobj(cxt, "srcpath '%s'", src));
c68408c2 1906
cddd2eaa
VD
1907 ns_old = mnt_context_switch_target_ns(cxt);
1908 if (!ns_old)
1909 return -MNT_ERR_NAMESPACE;
1910
c68408c2
KZ
1911 cache = mnt_context_get_cache(cxt);
1912
1913 if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
1914 /*
1915 * Source is TAG (evaluate)
1916 */
1917 if (cache)
1918 path = mnt_resolve_tag(t, v, cache);
1919
47dea49b 1920 rc = path ? mnt_fs_set_source(cxt->fs, path) : -MNT_ERR_NOSOURCE;
0a98127b 1921
a904aefe
KZ
1922 } else if (cache && !mnt_fs_is_pseudofs(cxt->fs)
1923 && !mnt_context_is_xnocanonicalize(cxt, "source")) {
c68408c2
KZ
1924 /*
1925 * Source is PATH (canonicalize)
1926 */
c59cf20c 1927 path = mnt_resolve_path(src, cache);
ad296391 1928 if (path && strcmp(path, src) != 0)
c59cf20c
KZ
1929 rc = mnt_fs_set_source(cxt->fs, path);
1930 }
c68408c2
KZ
1931
1932 if (rc) {
83a78332 1933 DBG(CXT, ul_debugobj(cxt, "failed to prepare srcpath [rc=%d]", rc));
cddd2eaa 1934 goto end;
c68408c2
KZ
1935 }
1936
0a98127b
KZ
1937 if (!path)
1938 path = src;
1939
94d57d48
KZ
1940 ol = mnt_context_get_optlist(cxt);
1941 if (!ol)
1942 return -ENOMEM;
1943
1944 if (mnt_optlist_is_bind(ol)
1945 || mnt_optlist_is_move(ol)
1946 || mnt_optlist_is_remount(ol)
6498ece0 1947 || mnt_fs_is_pseudofs(cxt->fs)) {
83a78332 1948 DBG(CXT, ul_debugobj(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
cddd2eaa 1949 goto end;
c59cf20c
KZ
1950 }
1951
3611b10c
KZ
1952 rc = mnt_context_call_hooks(cxt, MNT_STAGE_PREP_SOURCE);
1953 if (rc)
1954 goto end;
e6a49887 1955
83a78332 1956 DBG(CXT, ul_debugobj(cxt, "final srcpath '%s'",
7f8b2bf3 1957 mnt_fs_get_source(cxt->fs)));
cddd2eaa
VD
1958
1959end:
1960 if (!mnt_context_switch_ns(cxt, ns_old))
1961 return -MNT_ERR_NAMESPACE;
1962 return rc;
c68408c2
KZ
1963}
1964
7bc2fd3d
KZ
1965/* Guess type, but not set to cxt->fs, always use free() for the result. It's
1966 * no error when we're not able to guess a filesystem type. Note that error
1967 * does not mean that result in @type is NULL.
b1f03df7
KZ
1968 */
1969int mnt_context_guess_srcpath_fstype(struct libmnt_context *cxt, char **type)
1970{
1971 int rc = 0;
cddd2eaa 1972 struct libmnt_ns *ns_old;
779e3c97
KZ
1973 const char *dev;
1974
1975 assert(type);
1976 assert(cxt);
b1f03df7
KZ
1977
1978 *type = NULL;
1979
779e3c97 1980 dev = mnt_fs_get_srcpath(cxt->fs);
b1f03df7 1981 if (!dev)
779e3c97 1982 return 0;
b1f03df7 1983
cddd2eaa
VD
1984 ns_old = mnt_context_switch_target_ns(cxt);
1985 if (!ns_old)
1986 return -MNT_ERR_NAMESPACE;
1987
b1f03df7
KZ
1988 if (access(dev, F_OK) == 0) {
1989 struct libmnt_cache *cache = mnt_context_get_cache(cxt);
1990 int ambi = 0;
1991
1992 *type = mnt_get_fstype(dev, &ambi, cache);
b1f03df7
KZ
1993 if (ambi)
1994 rc = -MNT_ERR_AMBIFS;
779e3c97
KZ
1995
1996 if (cache && *type) {
1997 *type = strdup(*type);
1998 if (!*type)
1999 rc = -ENOMEM;
2000 }
b1f03df7
KZ
2001 } else {
2002 DBG(CXT, ul_debugobj(cxt, "access(%s) failed [%m]", dev));
779e3c97 2003 if (strchr(dev, ':') != NULL) {
b1f03df7 2004 *type = strdup("nfs");
779e3c97
KZ
2005 if (!*type)
2006 rc = -ENOMEM;
2007 } else if (!strncmp(dev, "//", 2)) {
b1f03df7 2008 *type = strdup("cifs");
779e3c97
KZ
2009 if (!*type)
2010 rc = -ENOMEM;
2011 }
b1f03df7
KZ
2012 }
2013
cddd2eaa
VD
2014 if (!mnt_context_switch_ns(cxt, ns_old))
2015 return -MNT_ERR_NAMESPACE;
2016
1592425a
KZ
2017 if (rc == 0 && *type) {
2018 struct libmnt_optlist *ol = mnt_context_get_optlist(cxt);
2019 struct libmnt_opt *opt;
2020 const char *allowed;
2021
6e212738
KZ
2022 if (!ol) {
2023 free(*type);
2024 *type = NULL;
1592425a 2025 return -ENOMEM;
6e212738 2026 }
1592425a
KZ
2027
2028 opt = mnt_optlist_get_named(ol,
2029 "X-mount.auto-fstypes", cxt->map_userspace);
2030
2031 if (opt
2032 && (allowed = mnt_opt_get_value(opt))
2033 && !match_fstype(*type, allowed)) {
e435d787 2034 DBG(CXT, ul_debugobj(cxt, "%s is not allowed by auto-fstypes=%s",
1592425a
KZ
2035 *type, allowed));
2036 free(*type);
2037 *type = NULL;
2038 rc = -MNT_ERR_NOFSTYPE;
2039 }
2040 }
2041
b1f03df7
KZ
2042 return rc;
2043}
2044
47dea49b 2045/*
d58b3157
OO
2046 * It's usually no error when we're not able to detect the filesystem type -- we
2047 * will try to use the types from /{etc,proc}/filesystems.
47dea49b 2048 */
68164f6c 2049int mnt_context_guess_fstype(struct libmnt_context *cxt)
c68408c2 2050{
94d57d48 2051 struct libmnt_optlist *ol;
f58168ff 2052 char *type;
47dea49b 2053 int rc = 0;
8485e709 2054
1b56aae8
KZ
2055 assert(cxt);
2056 assert(cxt->fs);
2057 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
2058
6ba7fbb4 2059 DBG(CXT, ul_debugobj(cxt, "--> preparing fstype"));
ff5ace78 2060
94d57d48
KZ
2061 ol = mnt_context_get_optlist(cxt);
2062 if (!ol)
2063 return -ENOMEM;
2064
2065 if (mnt_optlist_is_bind(ol)
2066 || mnt_optlist_is_move(ol)
6498ece0 2067 || mnt_context_propagation_only(cxt))
f58168ff 2068 goto none;
8485e709
KZ
2069
2070 type = (char *) mnt_fs_get_fstype(cxt->fs);
2071 if (type && !strcmp(type, "auto")) {
2072 mnt_fs_set_fstype(cxt->fs, NULL);
2073 type = NULL;
2074 }
2075
f58168ff
KZ
2076 if (type)
2077 goto done;
94d57d48 2078 if (mnt_optlist_is_remount(ol))
f58168ff 2079 goto none;
97e23b5e
KZ
2080 if (cxt->fstype_pattern)
2081 goto done;
2082
b1f03df7
KZ
2083 rc = mnt_context_guess_srcpath_fstype(cxt, &type);
2084 if (rc == 0 && type)
2085 __mnt_fs_set_fstype_ptr(cxt->fs, type);
0c8cd4ba
KZ
2086 else
2087 free(type);
f58168ff 2088done:
83a78332 2089 DBG(CXT, ul_debugobj(cxt, "FS type: %s [rc=%d]",
82a2c160 2090 mnt_fs_get_fstype(cxt->fs), rc));
54a3d5ee 2091 return rc;
f58168ff
KZ
2092none:
2093 return mnt_fs_set_fstype(cxt->fs, "none");
c68408c2
KZ
2094}
2095
a29e2f4f
KZ
2096/*
2097 * The default is to use fstype from cxt->fs, this could be overwritten by
2098 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
2099 *
2100 * Returns: 0 on success or negative number in case of error. Note that success
2101 * does not mean that there is any usable helper, you have to check cxt->helper.
2102 */
68164f6c 2103int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
1bb1d80b 2104 const char *type)
a29e2f4f
KZ
2105{
2106 char search_path[] = FS_SEARCH_PATH; /* from config.h */
2107 char *p = NULL, *path;
cddd2eaa 2108 struct libmnt_ns *ns_old;
779e3c97 2109 int rc = 0;
a29e2f4f
KZ
2110
2111 assert(cxt);
2112 assert(cxt->fs);
1b56aae8 2113 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
a29e2f4f 2114
18139743
KZ
2115 DBG(CXT, ul_debugobj(cxt, "checking for helper"));
2116
b6787fca
KZ
2117 if (cxt->helper) {
2118 free(cxt->helper);
2119 cxt->helper = NULL;
2120 }
2121
a29e2f4f
KZ
2122 if (!type)
2123 type = mnt_fs_get_fstype(cxt->fs);
2124
bbf9ce79
GFM
2125 if (type && strchr(type, ','))
2126 return 0; /* type is fstype pattern */
2127
379e8439
KZ
2128 if (mnt_context_is_nohelpers(cxt)
2129 || !type
2130 || !strcmp(type, "none")
51e3530c 2131 || strstr(type, "/..") /* don't try to smuggle path */
379e8439 2132 || mnt_fs_is_swaparea(cxt->fs))
a29e2f4f
KZ
2133 return 0;
2134
cddd2eaa
VD
2135 ns_old = mnt_context_switch_origin_ns(cxt);
2136 if (!ns_old)
2137 return -MNT_ERR_NAMESPACE;
2138
f2663ba7 2139 /* Ignore errors when search in $PATH and do not modify @rc
779e3c97 2140 */
a29e2f4f
KZ
2141 path = strtok_r(search_path, ":", &p);
2142 while (path) {
2143 char helper[PATH_MAX];
f2663ba7 2144 int len, found = 0;
a29e2f4f 2145
f2663ba7 2146 len = snprintf(helper, sizeof(helper), "%s/%s.%s",
a29e2f4f
KZ
2147 path, name, type);
2148 path = strtok_r(NULL, ":", &p);
2149
f2663ba7 2150 if (len < 0 || (size_t) len >= sizeof(helper))
a29e2f4f
KZ
2151 continue;
2152
f2663ba7
KZ
2153 found = mnt_is_path(helper);
2154 if (!found && strchr(type, '.')) {
a29e2f4f 2155 /* If type ends with ".subtype" try without it */
ff7eba4d
KZ
2156 char *hs = strrchr(helper, '.');
2157 if (hs)
2158 *hs = '\0';
f2663ba7 2159 found = mnt_is_path(helper);
a29e2f4f
KZ
2160 }
2161
83a78332 2162 DBG(CXT, ul_debugobj(cxt, "%-25s ... %s", helper,
f2663ba7
KZ
2163 found ? "found" : "not found"));
2164 if (!found)
a29e2f4f
KZ
2165 continue;
2166
779e3c97
KZ
2167 /* success */
2168 rc = strdup_to_struct_member(cxt, helper, helper);
2169 break;
a29e2f4f
KZ
2170 }
2171
cddd2eaa 2172 if (!mnt_context_switch_ns(cxt, ns_old))
779e3c97
KZ
2173 rc = -MNT_ERR_NAMESPACE;
2174
2175 /* make sure helper is not set on error */
2176 if (rc) {
2177 free(cxt->helper);
2178 cxt->helper = NULL;
2179 }
2180 return rc;
a29e2f4f
KZ
2181}
2182
9a72da2c 2183/* stop differentiate between options defined by flags and strings */
68164f6c 2184int mnt_context_merge_mflags(struct libmnt_context *cxt)
1b56aae8 2185{
9a72da2c 2186 struct libmnt_optlist *ls = mnt_context_get_optlist(cxt);
1b56aae8 2187
9a72da2c
KZ
2188 if (!ls)
2189 return -ENOMEM;
87a07a4c 2190
9a72da2c 2191 /* TODO: optlist returns always flags as merged, so
1a02c7a7 2192 * MNT_FL_MOUNTFLAGS_MERGED is unnecessary anymore
9a72da2c 2193 */
1b56aae8 2194 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
9a72da2c 2195 return mnt_optlist_merge_opts(ls);
1b56aae8
KZ
2196}
2197
1bb1d80b 2198/*
e9d52e6e 2199 * Prepare /run/mount/utab
1bb1d80b 2200 */
68164f6c 2201int mnt_context_prepare_update(struct libmnt_context *cxt)
5944e4e6
KZ
2202{
2203 int rc;
c8e5b8a8 2204 const char *target, *source, *name;
94d57d48 2205 unsigned long flags = 0;
c8e5b8a8 2206 struct libmnt_optlist *ol;
ea8f06f9 2207
1b56aae8
KZ
2208 assert(cxt);
2209 assert(cxt->fs);
1d0cd73f 2210 assert(cxt->action);
1b56aae8
KZ
2211 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
2212
6ba7fbb4 2213 DBG(CXT, ul_debugobj(cxt, "--> prepare update"));
92b7c04d 2214
6498ece0 2215 if (mnt_context_propagation_only(cxt)) {
83a78332 2216 DBG(CXT, ul_debugobj(cxt, "skip update: only MS_PROPAGATION"));
36bda5cb
KZ
2217 return 0;
2218 }
2219
1d0cd73f 2220 target = mnt_fs_get_target(cxt->fs);
c8e5b8a8 2221 source = mnt_fs_get_srcpath(cxt->fs);
1d0cd73f 2222
28cdf9c6
KZ
2223 if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/")) {
2224 DBG(CXT, ul_debugobj(cxt, "root umount: setting NOMTAB"));
379e8439 2225 mnt_context_disable_mtab(cxt, TRUE);
28cdf9c6 2226 }
379e8439 2227 if (mnt_context_is_nomtab(cxt)) {
83a78332 2228 DBG(CXT, ul_debugobj(cxt, "skip update: NOMTAB flag"));
5944e4e6 2229 return 0;
b0bb8fb6 2230 }
2454f701
KZ
2231 name = mnt_context_get_writable_tabpath(cxt);
2232 if (!name) {
83a78332 2233 DBG(CXT, ul_debugobj(cxt, "skip update: no writable destination"));
b0bb8fb6
KZ
2234 return 0;
2235 }
c8e5b8a8 2236
92b7c04d
KZ
2237 /* 0 = success, 1 = not called yet */
2238 if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
83a78332 2239 DBG(CXT, ul_debugobj(cxt,
92b7c04d
KZ
2240 "skip update: syscall failed [status=%d]",
2241 cxt->syscall_status));
2242 return 0;
2243 }
2b90c471 2244
c8e5b8a8
KZ
2245 ol = mnt_context_get_optlist(cxt);
2246 if (!ol)
2247 return -ENOMEM;
2b90c471 2248
c8e5b8a8
KZ
2249 if ((cxt->action == MNT_ACT_UMOUNT || mnt_optlist_is_move(ol))
2250 && is_file_empty(name)) {
2251 DBG(CXT, ul_debugobj(cxt, "skip update: umount/move, empty table"));
2252 return 0;
2253 }
2254
2255 if (mnt_optlist_is_move(ol) &&
2256 ((target && startswithpath(name, target))
2257 || (source && startswithpath(name, source)))) {
2258 DBG(CXT, ul_debugobj(cxt, "skip update: utab move"));
2259 return 0;
2260 }
2261
2262 if (!cxt->update) {
77417bc0 2263 cxt->update = mnt_new_update();
f58168ff
KZ
2264 if (!cxt->update)
2265 return -ENOMEM;
77417bc0 2266
e9d52e6e 2267 mnt_update_set_filename(cxt->update, name);
f58168ff 2268 }
5944e4e6 2269
94d57d48
KZ
2270 mnt_context_get_mflags(cxt, &flags);
2271
2915bdc0 2272 if (cxt->action == MNT_ACT_UMOUNT)
94d57d48 2273 rc = mnt_update_set_fs(cxt->update, flags,
085f163b 2274 mnt_context_get_target(cxt), NULL);
2915bdc0 2275 else
94d57d48 2276 rc = mnt_update_set_fs(cxt->update, flags,
2915bdc0 2277 NULL, cxt->fs);
5944e4e6 2278
9218c967
KZ
2279 if (mnt_update_is_ready(cxt->update)) {
2280 DBG(CXT, ul_debugobj(cxt, "update is ready"));
2281 mnt_update_start(cxt->update);
2282 }
1d0cd73f
KZ
2283 return rc < 0 ? rc : 0;
2284}
5944e4e6 2285
68164f6c 2286int mnt_context_update_tabs(struct libmnt_context *cxt)
1d0cd73f 2287{
cddd2eaa
VD
2288 int rc = 0;
2289 struct libmnt_ns *ns_old;
36bda5cb 2290
1d0cd73f
KZ
2291 assert(cxt);
2292
379e8439 2293 if (mnt_context_is_nomtab(cxt)) {
83a78332 2294 DBG(CXT, ul_debugobj(cxt, "don't update: NOMTAB flag"));
1d0cd73f 2295 return 0;
21193a48 2296 }
21193a48 2297 if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
83a78332 2298 DBG(CXT, ul_debugobj(cxt, "don't update: no update prepared"));
46cfd4a2 2299 return 0;
21193a48 2300 }
7e0c0619 2301
cddd2eaa
VD
2302 ns_old = mnt_context_switch_target_ns(cxt);
2303 if (!ns_old)
2304 return -MNT_ERR_NAMESPACE;
2305
7e0c0619
KZ
2306 /* check utab update when external helper executed */
2307 if (mnt_context_helper_executed(cxt)
2308 && mnt_context_get_helper_status(cxt) == 0
150e696d 2309 && mnt_context_utab_writable(cxt)) {
7e0c0619 2310
b94b5929 2311 if (mnt_update_already_done(cxt->update)) {
83a78332 2312 DBG(CXT, ul_debugobj(cxt, "don't update: error evaluate or already updated"));
54482492 2313 goto emit;
7e0c0619
KZ
2314 }
2315 } else if (cxt->helper) {
83a78332 2316 DBG(CXT, ul_debugobj(cxt, "don't update: external helper"));
cddd2eaa 2317 goto end;
7e0c0619
KZ
2318 }
2319
2320 if (cxt->syscall_status != 0
2321 && !(mnt_context_helper_executed(cxt) &&
2322 mnt_context_get_helper_status(cxt) == 0)) {
2323
83a78332 2324 DBG(CXT, ul_debugobj(cxt, "don't update: syscall/helper failed/not called"));
cddd2eaa 2325 goto end;
21193a48 2326 }
1d0cd73f 2327
cddd2eaa 2328 rc = mnt_update_table(cxt->update, cxt->lock);
54482492
KZ
2329emit:
2330 if (rc == 0 && !mnt_context_within_helper(cxt))
2331 mnt_update_emit_event(cxt->update);
9218c967 2332
cddd2eaa 2333end:
9218c967
KZ
2334 mnt_update_end(cxt->update);
2335
cddd2eaa
VD
2336 if (!mnt_context_switch_ns(cxt, ns_old))
2337 return -MNT_ERR_NAMESPACE;
2338 return rc;
5944e4e6
KZ
2339}
2340
7b78b571
KZ
2341/* apply @fs to @cxt;
2342 *
2343 * @mflags are mount flags as specified on command-line -- used only to save
2344 * MS_RDONLY which is allowed for non-root users.
7a56878d 2345 */
7b78b571 2346static int apply_fs(struct libmnt_context *cxt, struct libmnt_fs *fs, unsigned long mflags)
7a56878d 2347{
1017f628 2348 struct libmnt_optlist *ls;
7a56878d
KZ
2349 int rc;
2350
01790c7d
KZ
2351
2352
6a735c2c
KZ
2353 if (!cxt->optsmode) {
2354 if (mnt_context_is_restricted(cxt)) {
2355 DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
2356 cxt->optsmode = MNT_OMODE_USER;
2357 } else {
2358 DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
2359 cxt->optsmode = MNT_OMODE_AUTO;
2360 }
7b78b571 2361
6a735c2c
KZ
2362 }
2363
01790c7d
KZ
2364 if (!mnt_context_get_fs(cxt))
2365 return -ENOMEM;
2366
7a56878d
KZ
2367 DBG(CXT, ul_debugobj(cxt, "apply entry:"));
2368 DBG(CXT, mnt_fs_print_debug(fs, stderr));
6a735c2c
KZ
2369 DBG(CXT, ul_debugobj(cxt, "OPTSMODE (opt-part): ignore=%d, append=%d, prepend=%d, replace=%d",
2370 cxt->optsmode & MNT_OMODE_IGNORE ? 1 : 0,
2371 cxt->optsmode & MNT_OMODE_APPEND ? 1 : 0,
2372 cxt->optsmode & MNT_OMODE_PREPEND ? 1 : 0,
2373 cxt->optsmode & MNT_OMODE_REPLACE ? 1 : 0));
7a56878d
KZ
2374
2375 /* copy from fs to our FS description
2376 */
2377 rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
2378 if (!rc)
2379 rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
2380
2381 if (!rc && !mnt_fs_get_fstype(cxt->fs))
2382 rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
2383
2384 if (!rc && !mnt_fs_get_root(cxt->fs) && mnt_fs_get_root(fs))
2385 rc = mnt_fs_set_root(cxt->fs, mnt_fs_get_root(fs));
2386
2387 if (rc)
6a735c2c 2388 goto done;
7a56878d 2389
1017f628
KZ
2390 ls = mnt_context_get_optlist(cxt);
2391 if (!ls) {
2392 rc = -ENOMEM;
2393 goto done;
2394 }
2395
7a56878d
KZ
2396 if (cxt->optsmode & MNT_OMODE_IGNORE)
2397 ;
7b78b571 2398 else if (cxt->optsmode & MNT_OMODE_REPLACE) {
1017f628 2399 rc = mnt_optlist_set_optstr(ls, mnt_fs_get_options(fs), NULL);
7a56878d 2400
7b78b571
KZ
2401 /* mount --read-only for non-root users is allowed */
2402 if (rc == 0 && (mflags & MS_RDONLY)
2403 && mnt_context_is_restricted(cxt)
2404 && cxt->optsmode == MNT_OMODE_USER)
1017f628 2405 rc = mnt_optlist_append_optstr(ls, "ro", NULL);
7b78b571 2406 }
7a56878d 2407 else if (cxt->optsmode & MNT_OMODE_APPEND)
1017f628 2408 rc = mnt_optlist_append_optstr(ls, mnt_fs_get_options(fs), NULL);
7a56878d
KZ
2409
2410 else if (cxt->optsmode & MNT_OMODE_PREPEND)
1017f628 2411 rc = mnt_optlist_prepend_optstr(ls, mnt_fs_get_options(fs), NULL);
7a56878d
KZ
2412
2413 if (!rc)
2414 cxt->flags |= MNT_FL_TAB_APPLIED;
6a735c2c
KZ
2415
2416done:
1017f628 2417 DBG(CXT, ul_debugobj(cxt, "final entry [rc=%d]", rc));
6a735c2c
KZ
2418 DBG(CXT, mnt_fs_print_debug(cxt->fs, stderr));
2419
7a56878d
KZ
2420 return rc;
2421}
2422
68164f6c 2423static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
7b78b571 2424 int direction, unsigned long mflags)
f63173b2 2425{
68164f6c 2426 struct libmnt_fs *fs = NULL;
1b504263 2427 const char *src, *tgt;
f63173b2 2428
1b56aae8
KZ
2429 assert(cxt);
2430 assert(cxt->fs);
2431
f63173b2
KZ
2432 src = mnt_fs_get_source(cxt->fs);
2433 tgt = mnt_fs_get_target(cxt->fs);
2434
2435 if (tgt && src)
68164f6c 2436 fs = mnt_table_find_pair(tb, src, tgt, direction);
f63173b2
KZ
2437 else {
2438 if (src)
68164f6c 2439 fs = mnt_table_find_source(tb, src, direction);
f63173b2 2440 else if (tgt)
68164f6c 2441 fs = mnt_table_find_target(tb, tgt, direction);
f63173b2 2442
e39cbb76 2443 if (!fs && mnt_context_is_swapmatch(cxt)) {
f63173b2
KZ
2444 /* swap source and target (if @src is not LABEL/UUID),
2445 * for example in
2446 *
2447 * mount /foo/bar
2448 *
d58b3157
OO
2449 * the path could be a mountpoint as well as a source (for
2450 * example bind mount, symlink to a device, ...).
f63173b2
KZ
2451 */
2452 if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
68164f6c 2453 fs = mnt_table_find_target(tb, src, direction);
f63173b2 2454 if (!fs && tgt)
68164f6c 2455 fs = mnt_table_find_source(tb, tgt, direction);
f63173b2
KZ
2456 }
2457 }
2458
2459 if (!fs)
47dea49b 2460 return -MNT_ERR_NOFSTAB; /* not found */
f63173b2 2461
7b78b571
KZ
2462 return apply_fs(cxt, fs, mflags);
2463}
2464
2465/* apply @fs to @cxt -- use mnt_context_apply_fstab() if not sure
2466 */
2467int mnt_context_apply_fs(struct libmnt_context *cxt, struct libmnt_fs *fs)
2468{
2469 return apply_fs(cxt, fs, 0);
f63173b2
KZ
2470}
2471
97e23b5e
KZ
2472/**
2473 * mnt_context_apply_fstab:
2474 * @cxt: mount context
2475 *
cddd0999 2476 * This function is optional.
97e23b5e
KZ
2477 *
2478 * Returns: 0 on success, negative number in case of error.
2479 */
68164f6c 2480int mnt_context_apply_fstab(struct libmnt_context *cxt)
f63173b2 2481{
9b76b0e9 2482 int rc = -1, isremount = 0, iscmdbind = 0;
cddd2eaa 2483 struct libmnt_ns *ns_old;
68164f6c 2484 struct libmnt_table *tab = NULL;
f63173b2 2485 const char *src = NULL, *tgt = NULL;
7deae03f 2486 unsigned long mflags = 0;
f63173b2 2487
37290a53 2488 if (!cxt || !cxt->fs)
f63173b2
KZ
2489 return -EINVAL;
2490
6dede2f2
KZ
2491 if (mnt_context_tab_applied(cxt)) { /* already applied */
2492 DBG(CXT, ul_debugobj(cxt, "fstab already applied -- skip"));
f63173b2 2493 return 0;
6dede2f2 2494 }
f63173b2 2495
30e43998 2496 if (mnt_context_is_restricted(cxt)) {
83a78332 2497 DBG(CXT, ul_debugobj(cxt, "force fstab usage for non-root users!"));
30e43998 2498 cxt->optsmode = MNT_OMODE_USER;
9267c099 2499 } else if (cxt->optsmode == 0) {
83a78332 2500 DBG(CXT, ul_debugobj(cxt, "use default optsmode"));
30e43998 2501 cxt->optsmode = MNT_OMODE_AUTO;
374fd21a
KZ
2502 } else if (cxt->optsmode & MNT_OMODE_NOTAB) {
2503 cxt->optsmode &= ~MNT_OMODE_FSTAB;
2504 cxt->optsmode &= ~MNT_OMODE_MTAB;
2505 cxt->optsmode &= ~MNT_OMODE_FORCE;
9267c099
KZ
2506 }
2507
9b76b0e9
KZ
2508 if (mnt_context_get_mflags(cxt, &mflags) == 0) {
2509 isremount = !!(mflags & MS_REMOUNT);
2510 iscmdbind = !!(mflags & MS_BIND);
2511 }
7deae03f 2512
f63173b2
KZ
2513 if (cxt->fs) {
2514 src = mnt_fs_get_source(cxt->fs);
2515 tgt = mnt_fs_get_target(cxt->fs);
2516 }
2517
6a735c2c 2518 DBG(CXT, ul_debugobj(cxt, "OPTSMODE (file-part): force=%d, fstab=%d, mtab=%d",
9267c099
KZ
2519 cxt->optsmode & MNT_OMODE_FORCE ? 1 : 0,
2520 cxt->optsmode & MNT_OMODE_FSTAB ? 1 : 0,
2521 cxt->optsmode & MNT_OMODE_MTAB ? 1 : 0));
2522
f63173b2 2523 /* fstab is not required if source and target are specified */
5a669b12 2524 if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
83a78332 2525 DBG(CXT, ul_debugobj(cxt, "fstab not required -- skip"));
f63173b2 2526 return 0;
5a669b12 2527 }
f63173b2 2528
374fd21a
KZ
2529 if (!src && tgt
2530 && !(cxt->optsmode & MNT_OMODE_FSTAB)
2531 && !(cxt->optsmode & MNT_OMODE_MTAB)) {
83a78332 2532 DBG(CXT, ul_debugobj(cxt, "only target; fstab/mtab not required "
374fd21a
KZ
2533 "-- skip, probably MS_PROPAGATION"));
2534 return 0;
2535 }
2536
f63173b2 2537 /* let's initialize cxt->fs */
90cd46cb 2538 ignore_result( mnt_context_get_fs(cxt) );
f63173b2 2539
cddd2eaa
VD
2540 ns_old = mnt_context_switch_target_ns(cxt);
2541 if (!ns_old)
2542 return -MNT_ERR_NAMESPACE;
2543
f63173b2 2544 /* try fstab */
0c6d9b63 2545 if (cxt->optsmode & MNT_OMODE_FSTAB) {
7deae03f 2546 DBG(CXT, ul_debugobj(cxt, "trying to apply fstab (src=%s, target=%s)", src, tgt));
30e43998
KZ
2547 rc = mnt_context_get_fstab(cxt, &tab);
2548 if (!rc)
7b78b571 2549 rc = apply_table(cxt, tab, MNT_ITER_FORWARD, mflags);
30e43998 2550 }
f63173b2 2551
e9d52e6e 2552 /* try mountinfo */
ff5ace78
KZ
2553 if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)
2554 && (isremount || cxt->action == MNT_ACT_UMOUNT)) {
e9d52e6e 2555 DBG(CXT, ul_debugobj(cxt, "trying to apply mountinfo (src=%s, target=%s)", src, tgt));
7deae03f 2556 if (tgt)
e9d52e6e 2557 rc = mnt_context_get_mountinfo_for_target(cxt, &tab, tgt);
7deae03f 2558 else
e9d52e6e 2559 rc = mnt_context_get_mountinfo(cxt, &tab);
cf94e97f 2560 if (!rc)
7b78b571 2561 rc = apply_table(cxt, tab, MNT_ITER_BACKWARD, mflags);
f63173b2 2562 }
cddd2eaa
VD
2563
2564 if (!mnt_context_switch_ns(cxt, ns_old))
2565 return -MNT_ERR_NAMESPACE;
2566
a3b92242 2567 if (rc) {
01966ce8
KZ
2568 if (!mnt_context_is_restricted(cxt)
2569 && tgt && !src
2570 && isremount) {
e9d52e6e 2571 DBG(CXT, ul_debugobj(cxt, "only target; ignore missing mountinfo entry on remount"));
01966ce8
KZ
2572 return 0;
2573 }
2574
e9d52e6e 2575 DBG(CXT, ul_debugobj(cxt, "failed to find entry in fstab/mountinfo [rc=%d]: %m", rc));
a3b92242 2576
e9d52e6e 2577 /* force to "not found in fstab/mountinfo" error, the details why
a3b92242
KZ
2578 * not found are not so important and may be misinterpreted by
2579 * applications... */
2580 rc = -MNT_ERR_NOFSTAB;
9b76b0e9
KZ
2581
2582
1017f628 2583 } else if (isremount && !iscmdbind && cxt->optlist) {
9b76b0e9 2584
1017f628
KZ
2585 /* ignore "bind" on remount when the flag is read from fstab */
2586 mnt_optlist_remove_named(cxt->optlist, "bind", NULL);
a3b92242 2587 }
f63173b2
KZ
2588 return rc;
2589}
ea8f06f9 2590
e01c7319 2591/**
b11c9b7e 2592 * mnt_context_tab_applied:
e01c7319
KZ
2593 * @cxt: mount context
2594 *
e9d52e6e 2595 * Returns: 1 if fstab (or mountinfo) has been applied to the context, or 0.
e01c7319 2596 */
b11c9b7e 2597int mnt_context_tab_applied(struct libmnt_context *cxt)
e01c7319 2598{
ba2bdf41 2599 return cxt->flags & MNT_FL_TAB_APPLIED;
e01c7319
KZ
2600}
2601
6498ece0 2602/*
d58b3157 2603 * This is not a public function!
6498ece0
KZ
2604 *
2605 * Returns 1 if *only propagation flags* change is requested.
2606 */
2607int mnt_context_propagation_only(struct libmnt_context *cxt)
2608{
856518b0
KZ
2609 struct libmnt_optlist *ls;
2610
6498ece0
KZ
2611 if (cxt->action != MNT_ACT_MOUNT)
2612 return 0;
856518b0
KZ
2613 if (cxt->mountdata || cxt->fs == NULL)
2614 return 0;
6753e6f6
KZ
2615 if (cxt->fs->fstype && strcmp(cxt->fs->fstype, "none") != 0)
2616 return 0;
2617 if (cxt->fs->source && strcmp(cxt->fs->source, "none") != 0)
856518b0
KZ
2618 return 0;
2619
2620 ls = mnt_context_get_optlist(cxt);
2621 return ls ? mnt_optlist_is_propagation_only(ls) : 0;
6498ece0
KZ
2622}
2623
97e23b5e
KZ
2624/**
2625 * mnt_context_get_status:
2626 * @cxt: mount context
2627 *
be3df383
KZ
2628 * Global libmount status.
2629 *
2630 * The real exit code of the mount.type helper has to be tested by
d58b3157 2631 * mnt_context_get_helper_status(). The mnt_context_get_status() only informs
7007991f 2632 * that exec() has been successful.
be3df383 2633 *
455fe9a0 2634 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
97e23b5e 2635 */
68164f6c 2636int mnt_context_get_status(struct libmnt_context *cxt)
97e23b5e 2637{
ba2bdf41 2638 return !cxt->syscall_status || !cxt->helper_exec_status;
97e23b5e
KZ
2639}
2640
8ab6accf
KZ
2641/**
2642 * mnt_context_helper_executed:
2643 * @cxt: mount context
2644 *
2645 * Returns: 1 if mount.type helper has been executed, or 0.
2646 */
2647int mnt_context_helper_executed(struct libmnt_context *cxt)
2648{
2649 return cxt->helper_exec_status != 1;
2650}
2651
2652/**
2653 * mnt_context_get_helper_status:
2654 * @cxt: mount context
2655 *
ee314075 2656 * Return: mount.type helper exit status, result is reliable only if
8ab6accf
KZ
2657 * mnt_context_helper_executed() returns 1.
2658 */
2659int mnt_context_get_helper_status(struct libmnt_context *cxt)
2660{
2661 return cxt->helper_status;
2662}
2663
2664/**
2665 * mnt_context_syscall_called:
2666 * @cxt: mount context
2667 *
2668 * Returns: 1 if mount(2) syscall has been called, or 0.
2669 */
2670int mnt_context_syscall_called(struct libmnt_context *cxt)
2671{
2672 return cxt->syscall_status != 1;
2673}
2674
2675/**
2676 * mnt_context_get_syscall_errno:
2677 * @cxt: mount context
2678 *
2679 * The result from this function is reliable only if
2680 * mnt_context_syscall_called() returns 1.
2681 *
2682 * Returns: mount(2) errno if the syscall failed or 0.
2683 */
2684int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
2685{
2686 if (cxt->syscall_status < 0)
2687 return -cxt->syscall_status;
8ab6accf
KZ
2688 return 0;
2689}
2690
f5017242
KZ
2691/**
2692 * mnt_context_set_syscall_status:
2693 * @cxt: mount context
9f7472b0 2694 * @status: mount(2) status
f5017242 2695 *
8ab6accf 2696 * The @status should be 0 on success, or negative number on error (-errno).
5982583a 2697 *
6b871f46
KZ
2698 * This function is intended for cases where mount/umount is called externally,
2699 * rather than by libmount.
f5017242
KZ
2700 *
2701 * Returns: 0 or negative number in case of error.
2702 */
2703int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
2704{
2705 if (!cxt)
2706 return -EINVAL;
2707
83a78332 2708 DBG(CXT, ul_debugobj(cxt, "syscall status set to: %d", status));
f5017242
KZ
2709 cxt->syscall_status = status;
2710 return 0;
2711}
2712
6b871f46
KZ
2713/* Use this for syscalls called from libmount */
2714void mnt_context_syscall_save_status( struct libmnt_context *cxt,
2715 const char *syscallname,
2716 int success)
2717{
2718 if (!success) {
2719 DBG(CXT, ul_debug("syscall '%s' [failed: %m]", syscallname));
2720 cxt->syscall_status = -errno;
2721 cxt->syscall_name = syscallname;
2722 } else {
2723 DBG(CXT, ul_debug("syscall '%s' [success]", syscallname));
2724 cxt->syscall_status = 0;
2725 }
2726}
2727
2728void mnt_context_syscall_reset_status(struct libmnt_context *cxt)
2729{
2730 DBG(CXT, ul_debug("reset syscall status"));
2731 cxt->syscall_status = 0;
2732 cxt->syscall_name = NULL;
2733
33c42f5b 2734 mnt_context_reset_mesgs(cxt);
c4023572
KZ
2735}
2736
33c42f5b 2737void mnt_context_reset_mesgs(struct libmnt_context *cxt)
c4023572 2738{
33c42f5b 2739 DBG(CXT, ul_debug("reset messages"));
f39ffccf 2740 ul_strv_free(cxt->mesgs);
33c42f5b 2741 cxt->mesgs = NULL;
c4023572
KZ
2742}
2743
33c42f5b 2744int mnt_context_append_mesg(struct libmnt_context *cxt, const char *msg)
c4023572 2745{
8369f2a7
KZ
2746 if (msg) {
2747 DBG(CXT, ul_debug("mesg: '%s'", msg));
2748 }
f39ffccf 2749 return ul_strv_extend(&cxt->mesgs, msg);
6b871f46
KZ
2750}
2751
33c42f5b 2752int mnt_context_sprintf_mesg(struct libmnt_context *cxt, const char *msg, ...)
41476dd4
KZ
2753{
2754 int rc;
2755 va_list ap;
41476dd4
KZ
2756
2757 va_start(ap, msg);
f39ffccf 2758 rc = ul_strv_extendv(&cxt->mesgs, msg, ap);
41476dd4
KZ
2759 va_end(ap);
2760
33c42f5b
KZ
2761 return rc;
2762}
2763
8369f2a7
KZ
2764int mnt_context_read_mesgs(struct libmnt_context *cxt, int fd)
2765{
2766 uint8_t buf[BUFSIZ];
2767 ssize_t sz;
2768 size_t count = 0;
2769 int errsv = errno;
2770
2771 if (fd < 0)
2772 return 0;
2773
2774 while ((sz = read(fd, buf, sizeof(buf) - 1)) != -1) {
2775
2776 if (sz <= 0)
2777 continue;
2778 if (buf[sz - 1] == '\n')
2779 buf[--sz] = '\0';
2780 else
2781 buf[sz] = '\0';
2782
2783 if (!*buf)
2784 continue;
2785
2786 mnt_context_append_mesg(cxt, (char *) buf);
2787 count++;;
2788 }
2789
2790 errno = errsv;
2791 return count;
2792}
2793
33c42f5b
KZ
2794/**
2795 * mnt_context_get_nmesgs:
2796 * @cxt: mount context
2797 * @type: type of message (see fsopen() man page) or zero for all types
2798 *
2799 * Returns: number of messages
2800 *
2801 * Since: 2.41
2802 */
2803size_t mnt_context_get_nmesgs(struct libmnt_context *cxt, char type)
2804{
2805 size_t n;
2806 char **s;
2807
2808 if (!cxt || !cxt->mesgs)
2809 return 0;
41476dd4 2810
f39ffccf 2811 n = ul_strv_length(cxt->mesgs);
33c42f5b
KZ
2812 if (n && type) {
2813 n = 0;
f39ffccf 2814 UL_STRV_FOREACH(s, cxt->mesgs) {
33c42f5b
KZ
2815 if (*s && **s == type)
2816 n++;
2817 }
2818 }
41476dd4 2819
33c42f5b
KZ
2820 return n;
2821}
2822
2823/**
2824 * mnt_context_get_mesgs:
2825 * @cxt: mount context
2826 *
2827 * Returns: NULL terminated array of messages or NULL
2828 *
2829 * Since: 2.41
2830 */
2831char **mnt_context_get_mesgs(struct libmnt_context *cxt)
2832{
2833 return cxt ? cxt->mesgs : NULL;
41476dd4
KZ
2834}
2835
1d0cd73f
KZ
2836/**
2837 * mnt_context_strerror
2838 * @cxt: context
2839 * @buf: buffer
2840 * @bufsiz: size of the buffer
2841 *
ea848180 2842 * Not implemented, deprecated in favor or mnt_context_get_excode().
8ab6accf 2843 *
1d0cd73f
KZ
2844 * Returns: 0 or negative number in case of error.
2845 */
7fc6d2b8
KZ
2846int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
2847 char *buf __attribute__((__unused__)),
2848 size_t bufsiz __attribute__((__unused__)))
1d0cd73f
KZ
2849{
2850 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
2851 return 0;
2852}
ea8f06f9 2853
22147e08
IK
2854/**
2855 * mnt_context_enable_noautofs:
2856 * @cxt: context
2857 * @ignore: ignore or don't ignore
2858 *
2859 * Enable/disable ignore autofs mount table entries on reading the
2860 * mount table. Only effective if the "ignore" mount option is being
2861 * used for autofs mounts (such as if automount(8) has been configured
2862 * to do so).
2863 */
2864int mnt_context_enable_noautofs(struct libmnt_context *cxt, int ignore)
2865{
2866 if (!cxt)
2867 return -EINVAL;
2868 cxt->noautofs = ignore ? 1 : 0;
2869 return 0;
2870}
ea848180 2871
b77e3e34 2872int mnt_context_get_generic_excode(int rc, char *buf, size_t bufsz, const char *fmt, ...)
ea848180
KZ
2873{
2874 va_list va;
2875
2876 if (rc == 0)
2877 return MNT_EX_SUCCESS;
2878
2879 va_start(va, fmt);
2880
2881 /* we need to support "%m" */
2882 errno = rc < 0 ? -rc : rc;
2883
810dfb7d
KZ
2884 if (buf && bufsz && vsnprintf(buf, bufsz, fmt, va) < 0)
2885 *buf = '\0';
ea848180
KZ
2886
2887 switch (errno) {
2888 case EINVAL:
2889 case EPERM:
2890 rc = MNT_EX_USAGE;
2891 break;
2892 case ENOMEM:
2893 rc = MNT_EX_SYSERR;
2894 break;
2895 default:
2896 rc = MNT_EX_FAIL;
2897 break;
2898 }
2899 va_end(va);
2900 return rc;
2901}
2902
2903/**
2904 * mnt_context_get_excode:
2905 * @cxt: context
2906 * @rc: return code of the previous operation
2907 * @buf: buffer to print error message (optional)
2908 * @bufsz: size of the buffer
2909 *
2910 * This function analyzes context, [u]mount syscall and external helper status
2911 * and @mntrc and generates unified return code (see MNT_EX_*) as expected
2912 * from mount(8) or umount(8).
2913 *
8503c0ed 2914 * If the external helper (e.g. /sbin/mount.type) has been executed than it
ea848180
KZ
2915 * returns status from wait() of the helper. It's not libmount fail if helper
2916 * returns some crazy undocumented codes... See mnt_context_helper_executed()
2917 * and mnt_context_get_helper_status(). Note that mount(8) and umount(8) utils
2918 * always return code from helper without extra care about it.
2919 *
79acb5bf
KZ
2920 * The current implementation does not read error message from external
2921 * helper into @buf.
2922 *
ea848180
KZ
2923 * If the argument @buf is not NULL then error message is generated (if
2924 * anything failed).
2925 *
2926 * The @mntrc is usually return code from mnt_context_mount(),
2927 * mnt_context_umount(), or 'mntrc' as returned by mnt_context_next_mount().
2928 *
a81b1946
KZ
2929 * Since: 2.30
2930 *
ea848180
KZ
2931 * Returns: MNT_EX_* codes.
2932 */
2933int mnt_context_get_excode(
2934 struct libmnt_context *cxt,
2935 int rc,
2936 char *buf,
2937 size_t bufsz)
2938{
2939 if (buf) {
2940 *buf = '\0'; /* for sure */
2941
2942 if (!cxt->enabled_textdomain) {
2943 bindtextdomain(LIBMOUNT_TEXTDOMAIN, LOCALEDIR);
2944 cxt->enabled_textdomain = 1;
2945 }
2946 }
2947
2948 switch (cxt->action) {
2949 case MNT_ACT_MOUNT:
2950 rc = mnt_context_get_mount_excode(cxt, rc, buf, bufsz);
2951 break;
2952 case MNT_ACT_UMOUNT:
2953 rc = mnt_context_get_umount_excode(cxt, rc, buf, bufsz);
2954 break;
2955 default:
2956 if (rc)
2957 rc = mnt_context_get_generic_excode(rc, buf, bufsz,
2958 _("operation failed: %m"));
2959 else
2960 rc = MNT_EX_SUCCESS;
2961 break;
2962 }
2963
0361cb6f 2964 DBG(CXT, ul_debugobj(cxt, "excode: rc=%d message=\"%s\"", rc,
ea848180
KZ
2965 buf ? buf : "<no-message>"));
2966 return rc;
2967}
2968
8c0797e7
KZ
2969/**
2970 * mnt_context_init_helper
2971 * @cxt: mount context
b70785bc 2972 * @action: MNT_ACT_{UMOUNT,MOUNT}
7fc6d2b8 2973 * @flags: not used now
8c0797e7 2974 *
d58b3157 2975 * This function informs libmount that used from [u]mount.type helper.
8c0797e7 2976 *
e95b3ca3 2977 * The function also calls mnt_context_disable_helpers() to avoid recursive
63de90d4 2978 * mount.type helpers calling. It you really want to call another
d58b3157 2979 * mount.type helper from your helper, then you have to explicitly enable this
e95b3ca3
KZ
2980 * feature by:
2981 *
2982 * mnt_context_disable_helpers(cxt, FALSE);
2983 *
8c0797e7
KZ
2984 * Returns: 0 on success, negative number in case of error.
2985 */
7fc6d2b8
KZ
2986int mnt_context_init_helper(struct libmnt_context *cxt, int action,
2987 int flags __attribute__((__unused__)))
8c0797e7 2988{
4569bbea 2989 int rc;
e95b3ca3 2990
37290a53
KZ
2991 if (!cxt)
2992 return -EINVAL;
4569bbea
KZ
2993
2994 rc = mnt_context_disable_helpers(cxt, TRUE);
e95b3ca3 2995 if (!rc)
b70785bc
KZ
2996 rc = set_flag(cxt, MNT_FL_HELPER, 1);
2997 if (!rc)
2998 cxt->action = action;
f5017242 2999
83a78332 3000 DBG(CXT, ul_debugobj(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
e95b3ca3 3001 return rc;
8c0797e7
KZ
3002}
3003
0f9b2438
KZ
3004/*
3005 * libmount used in /sbin/[u]mount.<type> helper
3006 */
3007int mnt_context_within_helper(struct libmnt_context *cxt)
3008{
3009 return cxt && (cxt->flags & MNT_FL_HELPER);
3010}
3011
b70785bc
KZ
3012/**
3013 * mnt_context_helper_setopt:
e6ecd606 3014 * @cxt: context
b70785bc
KZ
3015 * @c: getopt() result
3016 * @arg: getopt() optarg
3017 *
d58b3157 3018 * This function applies the [u]mount.type command line option (for example parsed
e6ecd606 3019 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
b70785bc
KZ
3020 * then 1 is returned.
3021 *
3022 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
3023 */
3024int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
3025{
3026 if (cxt) {
3027 switch(cxt->action) {
3028 case MNT_ACT_MOUNT:
3029 return mnt_context_mount_setopt(cxt, c, arg);
3030 case MNT_ACT_UMOUNT:
3031 return mnt_context_umount_setopt(cxt, c, arg);
3032 }
3033 }
3034 return -EINVAL;
3035}
3036
9f7472b0 3037/**
e6ecd606 3038 * mnt_context_is_fs_mounted:
9f7472b0 3039 * @cxt: context
e6ecd606 3040 * @fs: filesystem
9f7472b0
KZ
3041 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
3042 *
d58b3157 3043 * Please, read the mnt_table_is_fs_mounted() description!
975e14bd 3044 *
9f7472b0
KZ
3045 * Returns: 0 on success and negative number in case of error.
3046 */
3047int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
3048 struct libmnt_fs *fs, int *mounted)
3049{
e9d52e6e 3050 struct libmnt_table *mountinfo, *orig;
b8f2fce2 3051 int rc = 0;
cddd2eaa 3052 struct libmnt_ns *ns_old;
9f7472b0
KZ
3053
3054 if (!cxt || !fs || !mounted)
3055 return -EINVAL;
3056
cddd2eaa
VD
3057 ns_old = mnt_context_switch_target_ns(cxt);
3058 if (!ns_old)
3059 return -MNT_ERR_NAMESPACE;
3060
e9d52e6e
KZ
3061 orig = cxt->mountinfo;
3062 rc = mnt_context_get_mountinfo(cxt, &mountinfo);
3063 if (rc == -ENOENT && mnt_fs_streq_target(fs, "/proc")) {
b9a5e23f 3064 if (!orig) {
e9d52e6e
KZ
3065 mnt_unref_table(cxt->mountinfo);
3066 cxt->mountinfo = NULL;
b9a5e23f
ID
3067 }
3068 *mounted = 0;
b8f2fce2 3069 rc = 0; /* /proc not mounted */
042f62df 3070
b8f2fce2 3071 } else if (rc == 0) {
e9d52e6e 3072 *mounted = __mnt_table_is_fs_mounted(mountinfo, fs,
71ed3b83 3073 mnt_context_get_target_prefix(cxt));
cddd2eaa 3074
b8f2fce2
KZ
3075 }
3076
cddd2eaa
VD
3077 if (!mnt_context_switch_ns(cxt, ns_old))
3078 return -MNT_ERR_NAMESPACE;
b8f2fce2 3079 return rc;
9f7472b0
KZ
3080}
3081
d2c97887
KZ
3082static int mnt_context_add_child(struct libmnt_context *cxt, pid_t pid)
3083{
3084 pid_t *pids;
3085
3086 if (!cxt)
3087 return -EINVAL;
3088
64d6d400 3089 pids = reallocarray(cxt->children, cxt->nchildren + 1, sizeof(pid_t));
d2c97887
KZ
3090 if (!pids)
3091 return -ENOMEM;
3092
83a78332 3093 DBG(CXT, ul_debugobj(cxt, "add new child %d", pid));
d2c97887
KZ
3094 cxt->children = pids;
3095 cxt->children[cxt->nchildren++] = pid;
3096
3097 return 0;
3098}
3099
3100int mnt_fork_context(struct libmnt_context *cxt)
3101{
3102 int rc = 0;
3103 pid_t pid;
3104
4569bbea 3105 assert(cxt);
d2c97887
KZ
3106 if (!mnt_context_is_parent(cxt))
3107 return -EINVAL;
3108
83a78332 3109 DBG(CXT, ul_debugobj(cxt, "forking context"));
d2c97887
KZ
3110
3111 DBG_FLUSH;
3112
3113 pid = fork();
3114
3115 switch (pid) {
3116 case -1: /* error */
83a78332 3117 DBG(CXT, ul_debugobj(cxt, "fork failed %m"));
d2c97887
KZ
3118 return -errno;
3119
3120 case 0: /* child */
3121 cxt->pid = getpid();
379e8439 3122 mnt_context_enable_fork(cxt, FALSE);
83a78332 3123 DBG(CXT, ul_debugobj(cxt, "child created"));
d2c97887
KZ
3124 break;
3125
3126 default:
3127 rc = mnt_context_add_child(cxt, pid);
3128 break;
3129 }
3130
3131 return rc;
3132}
3133
3134int mnt_context_wait_for_children(struct libmnt_context *cxt,
3135 int *nchildren, int *nerrs)
3136{
3137 int i;
3138
3139 if (!cxt)
3140 return -EINVAL;
3141
3142 assert(mnt_context_is_parent(cxt));
3143
3144 for (i = 0; i < cxt->nchildren; i++) {
3145 pid_t pid = cxt->children[i];
3146 int rc = 0, ret = 0;
3147
3148 if (!pid)
3149 continue;
3150 do {
83a78332 3151 DBG(CXT, ul_debugobj(cxt,
d2c97887
KZ
3152 "waiting for child (%d/%d): %d",
3153 i + 1, cxt->nchildren, pid));
3154 errno = 0;
3155 rc = waitpid(pid, &ret, 0);
3156
3157 } while (rc == -1 && errno == EINTR);
3158
3159 if (nchildren)
3160 (*nchildren)++;
3161
3162 if (rc != -1 && nerrs) {
3163 if (WIFEXITED(ret))
3164 (*nerrs) += WEXITSTATUS(ret) == 0 ? 0 : 1;
3165 else
3166 (*nerrs)++;
3167 }
3168 cxt->children[i] = 0;
3169 }
3170
3171 cxt->nchildren = 0;
3172 free(cxt->children);
3173 cxt->children = NULL;
3174 return 0;
3175}
3176
4917d842
VD
3177static void close_ns(struct libmnt_ns *ns)
3178{
3179 if (ns->fd == -1)
3180 return;
3181
3182 close(ns->fd);
3183 ns->fd = -1;
3184
3185 mnt_unref_cache(ns->cache);
3186 ns->cache = NULL;
3187}
3188
3189/**
3190 * mnt_context_set_target_ns:
3191 * @cxt: mount context
3192 * @path: path to target namespace or NULL
3193 *
3194 * Sets target namespace to namespace represented by @path. If @path is NULL,
3195 * target namespace is cleared.
3196 *
4f7acf32
KZ
3197 * This function sets errno to ENOSYS and returns error if libmount is
3198 * compiled without namespaces support.
722c9697 3199 *
4917d842 3200 * Returns: 0 on success, negative number in case of error.
fae83289
KZ
3201 *
3202 * Since: 2.33
4917d842
VD
3203 */
3204int mnt_context_set_target_ns(struct libmnt_context *cxt, const char *path)
3205{
4917d842
VD
3206 if (!cxt)
3207 return -EINVAL;
3208
3209 DBG(CXT, ul_debugobj(cxt, "Setting %s as target namespace", path));
3210
3211 /* cleanup only */
3212 if (!path) {
3213 close_ns(&cxt->ns_orig);
3214 close_ns(&cxt->ns_tgt);
3215 return 0;
3216 }
3217
4f7acf32
KZ
3218#ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
3219 int errsv = 0;
3220 int tmp;
3221
de7ccabd
KZ
3222 errno = 0;
3223
4917d842
VD
3224 /* open original namespace */
3225 if (cxt->ns_orig.fd == -1) {
3226 cxt->ns_orig.fd = open("/proc/self/ns/mnt", O_RDONLY | O_CLOEXEC);
3227 if (cxt->ns_orig.fd == -1)
3228 return -errno;
3229 cxt->ns_orig.cache = NULL;
3230 }
3231
3232 /* open target (wanted) namespace */
3233 tmp = open(path, O_RDONLY | O_CLOEXEC);
3234 if (tmp == -1)
3235 return -errno;
3236
3237 /* test whether namespace switching works */
3238 DBG(CXT, ul_debugobj(cxt, "Trying whether namespace is valid"));
3239 if (setns(tmp, CLONE_NEWNS)
3240 || setns(cxt->ns_orig.fd, CLONE_NEWNS)) {
de7ccabd 3241 errsv = errno;
4917d842
VD
3242 DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
3243 goto err;
3244 }
3245
3246 close_ns(&cxt->ns_tgt);
3247
3248 cxt->ns_tgt.fd = tmp;
3249 cxt->ns_tgt.cache = NULL;
3250
3251 return 0;
3252err:
3253 close(tmp);
de7ccabd 3254 errno = errsv;
4f7acf32
KZ
3255
3256#else /* ! USE_LIBMOUNT_SUPPORT_NAMESPACES */
3257 errno = ENOSYS;
3258#endif
de7ccabd 3259 return -errno;
4917d842
VD
3260}
3261
3262/**
3263 * mnt_context_get_target_ns:
3264 * @cxt: mount context
3265 *
3266 * Returns: pointer to target namespace
fae83289
KZ
3267 *
3268 * Since: 2.33
4917d842
VD
3269 */
3270struct libmnt_ns *mnt_context_get_target_ns(struct libmnt_context *cxt)
3271{
3272 return &cxt->ns_tgt;
3273}
3274
3275/**
3276 * mnt_context_get_origin_ns:
3277 * @cxt: mount context
3278 *
3279 * Returns: pointer to original namespace
fae83289
KZ
3280 *
3281 * Since: 2.33
4917d842
VD
3282 */
3283struct libmnt_ns *mnt_context_get_origin_ns(struct libmnt_context *cxt)
3284{
3285 return &cxt->ns_orig;
3286}
3287
3288
3289/**
3290 * mnt_context_switch_ns:
3291 * @cxt: mount context
3292 * @ns: namespace to switch to
3293 *
3294 * Switch to namespace specified by ns
3295 *
3296 * Typical usage:
3297 * <informalexample>
3298 * <programlisting>
3299 * struct libmnt_ns *ns_old;
3300 * ns_old = mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3301 * ... code ...
3302 * mnt_context_switch_ns(cxt, ns_old);
3303 * </programlisting>
3304 * </informalexample>
3305 *
3306 * Returns: pointer to previous namespace or NULL on error
fae83289
KZ
3307 *
3308 * Since: 2.33
4917d842
VD
3309 */
3310struct libmnt_ns *mnt_context_switch_ns(struct libmnt_context *cxt, struct libmnt_ns *ns)
3311{
4f7acf32 3312 struct libmnt_ns *old = NULL;
4917d842
VD
3313
3314 if (!cxt || !ns)
3315 return NULL;
3316
4f7acf32
KZ
3317 /*
3318 * If mnt_context_set_target_ns() has never been used than @ns file
3319 * descriptor is -1 and this function is noop.
3320 */
4917d842
VD
3321 old = cxt->ns_cur;
3322 if (ns == old || ns->fd == -1)
3323 return old;
3324
4f7acf32 3325#ifdef USE_LIBMOUNT_SUPPORT_NAMESPACES
bb607cb3 3326 /* remember the current cache */
4917d842
VD
3327 if (old->cache != cxt->cache) {
3328 mnt_unref_cache(old->cache);
3329 old->cache = cxt->cache;
3330 mnt_ref_cache(old->cache);
3331 }
3332
3333 /* switch */
3334 DBG(CXT, ul_debugobj(cxt, "Switching to %s namespace",
3335 ns == mnt_context_get_target_ns(cxt) ? "target" :
3336 ns == mnt_context_get_origin_ns(cxt) ? "original" : "other"));
3337
3338 if (setns(ns->fd, CLONE_NEWNS)) {
3339 int errsv = errno;
3340
3341 DBG(CXT, ul_debugobj(cxt, "setns(2) failed [errno=%d %m]", errno));
3342 errno = errsv;
3343 return NULL;
3344 }
3345
3346 /* update pointer to the current namespace */
3347 cxt->ns_cur = ns;
3348
3349 /* update pointer to the cache */
3350 mnt_unref_cache(cxt->cache);
3351 cxt->cache = ns->cache;
3352 mnt_ref_cache(cxt->cache);
4f7acf32 3353#endif /* USE_LIBMOUNT_SUPPORT_NAMESPACES */
4917d842
VD
3354
3355 return old;
3356}
3357
3358/**
3359 * mnt_context_switch_origin_ns:
3360 * @cxt: mount context
3361 *
3362 * Switch to original namespace
3363 *
3364 * This is shorthand for
3365 * <informalexample>
3366 * <programlisting>
3367 * mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3368 * </programlisting>
3369 * </informalexample>
3370 *
3371 * Returns: pointer to previous namespace or NULL on error
fae83289
KZ
3372 *
3373 * Since: 2.33
4917d842
VD
3374 */
3375struct libmnt_ns *mnt_context_switch_origin_ns(struct libmnt_context *cxt)
3376{
3377 return mnt_context_switch_ns(cxt, mnt_context_get_origin_ns(cxt));
3378}
3379
3380/**
3381 * mnt_context_switch_target_ns:
3382 * @cxt: mount context
3383 *
3384 * Switch to target namespace
3385 *
3386 * This is shorthand for
3387 * <informalexample>
3388 * <programlisting>
3389 * mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3390 * </programlisting>
3391 * </informalexample>
3392 *
3393 * Returns: pointer to previous namespace or NULL on error
fae83289
KZ
3394 *
3395 * Since: 2.33
4917d842
VD
3396 */
3397struct libmnt_ns *mnt_context_switch_target_ns(struct libmnt_context *cxt)
3398{
3399 return mnt_context_switch_ns(cxt, mnt_context_get_target_ns(cxt));
3400}
d2c97887
KZ
3401
3402
ea8f06f9
KZ
3403#ifdef TEST_PROGRAM
3404
2a472ae8
TW
3405static int test_search_helper(struct libmnt_test *ts __attribute__((unused)),
3406 int argc, char *argv[])
779e3c97
KZ
3407{
3408 struct libmnt_context *cxt;
3409 const char *type;
3410 int rc;
3411
3412 if (argc < 2)
3413 return -EINVAL;
3414
3415 cxt = mnt_new_context();
3416 if (!cxt)
3417 return -ENOMEM;
3418
3419 type = argv[1];
3420
3421 mnt_context_get_fs(cxt); /* just to fill cxt->fs */
3422 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED; /* fake */
3423
3424 rc = mnt_context_prepare_helper(cxt, "mount", type);
3425 printf("helper is: %s\n", cxt->helper ? cxt->helper : "not found");
3426
3427 mnt_free_context(cxt);
3428 return rc;
3429}
3430
3431
41427f97 3432static struct libmnt_lock *lock;
ea8f06f9
KZ
3433
3434static void lock_fallback(void)
3435{
46cfd4a2 3436 if (lock)
ea8f06f9 3437 mnt_unlock_file(lock);
ea8f06f9
KZ
3438}
3439
2a472ae8
TW
3440static int test_mount(struct libmnt_test *ts __attribute__((unused)),
3441 int argc, char *argv[])
ea8f06f9
KZ
3442{
3443 int idx = 1, rc = 0;
68164f6c 3444 struct libmnt_context *cxt;
ea8f06f9
KZ
3445
3446 if (argc < 2)
3447 return -EINVAL;
3448
3449 cxt = mnt_new_context();
3450 if (!cxt)
3451 return -ENOMEM;
3452
3453 if (!strcmp(argv[idx], "-o")) {
76a06ca4 3454 mnt_context_set_options(cxt, argv[idx + 1]);
ea8f06f9
KZ
3455 idx += 2;
3456 }
3457 if (!strcmp(argv[idx], "-t")) {
3458 /* TODO: use mnt_context_set_fstype_pattern() */
3459 mnt_context_set_fstype(cxt, argv[idx + 1]);
3460 idx += 2;
3461 }
3462
3463 if (argc == idx + 1)
9e930041 3464 /* mount <mountpoint>|<device> */
ea8f06f9
KZ
3465 mnt_context_set_target(cxt, argv[idx++]);
3466
3467 else if (argc == idx + 2) {
3468 /* mount <device> <mountpoint> */
3469 mnt_context_set_source(cxt, argv[idx++]);
3470 mnt_context_set_target(cxt, argv[idx++]);
3471 }
3472
d58b3157 3473 /* this is unnecessary! -- libmount is able to internally
86cd5870
KZ
3474 * create and manage the lock
3475 */
46cfd4a2
KZ
3476 lock = mnt_context_get_lock(cxt);
3477 if (lock)
3478 atexit(lock_fallback);
ea8f06f9 3479
cfb9db30 3480 rc = mnt_context_mount(cxt);
46cfd4a2 3481 if (rc)
9104cd28 3482 warn("failed to mount");
64a2331f
KZ
3483 else
3484 printf("successfully mounted\n");
ea8f06f9 3485
d89670b5 3486 lock = NULL; /* because we use atexit lock_fallback */
ea8f06f9
KZ
3487 mnt_free_context(cxt);
3488 return rc;
3489}
3490
2a472ae8
TW
3491static int test_umount(struct libmnt_test *ts __attribute__((unused)),
3492 int argc, char *argv[])
ea8f06f9
KZ
3493{
3494 int idx = 1, rc = 0;
68164f6c 3495 struct libmnt_context *cxt;
ea8f06f9
KZ
3496
3497 if (argc < 2)
3498 return -EINVAL;
3499
3500 cxt = mnt_new_context();
3501 if (!cxt)
3502 return -ENOMEM;
3503
3504 if (!strcmp(argv[idx], "-t")) {
3505 mnt_context_set_fstype(cxt, argv[idx + 1]);
3506 idx += 2;
3507 }
3508
3509 if (!strcmp(argv[idx], "-f")) {
3510 mnt_context_enable_force(cxt, TRUE);
3511 idx++;
3512 }
3513
3514 if (!strcmp(argv[idx], "-l")) {
3515 mnt_context_enable_lazy(cxt, TRUE);
3516 idx++;
3517 }
3518
3519 if (!strcmp(argv[idx], "-r")) {
3520 mnt_context_enable_rdonly_umount(cxt, TRUE);
3521 idx++;
3522 }
3523
3524 if (argc == idx + 1) {
9e930041 3525 /* mount <mountpoint>|<device> */
ea8f06f9
KZ
3526 mnt_context_set_target(cxt, argv[idx++]);
3527 } else {
3528 rc = -EINVAL;
3529 goto err;
3530 }
3531
46cfd4a2
KZ
3532 lock = mnt_context_get_lock(cxt);
3533 if (lock)
3534 atexit(lock_fallback);
ea8f06f9 3535
cddd0999 3536 rc = mnt_context_umount(cxt);
46cfd4a2
KZ
3537 if (rc)
3538 printf("failed to umount\n");
64a2331f
KZ
3539 else
3540 printf("successfully umounted\n");
ea8f06f9 3541err:
d89670b5 3542 lock = NULL; /* because we use atexit lock_fallback */
ea8f06f9
KZ
3543 mnt_free_context(cxt);
3544 return rc;
3545}
3546
2a472ae8
TW
3547static int test_flags(struct libmnt_test *ts __attribute__((unused)),
3548 int argc, char *argv[])
ddfc6f28
KZ
3549{
3550 int idx = 1, rc = 0;
3551 struct libmnt_context *cxt;
3552 const char *opt = NULL;
3553 unsigned long flags = 0;
3554
3555 if (argc < 2)
3556 return -EINVAL;
3557
3558 cxt = mnt_new_context();
3559 if (!cxt)
3560 return -ENOMEM;
3561
3562 if (!strcmp(argv[idx], "-o")) {
3563 mnt_context_set_options(cxt, argv[idx + 1]);
3564 idx += 2;
3565 }
3566
3567 if (argc == idx + 1)
9e930041 3568 /* mount <mountpoint>|<device> */
ddfc6f28
KZ
3569 mnt_context_set_target(cxt, argv[idx++]);
3570
3571 rc = mnt_context_prepare_mount(cxt);
3572 if (rc)
3573 printf("failed to prepare mount %s\n", strerror(-rc));
3574
3575 opt = mnt_fs_get_options(cxt->fs);
3576 if (opt)
3577 fprintf(stdout, "options: %s\n", opt);
3578
3579 mnt_context_get_mflags(cxt, &flags);
3580 fprintf(stdout, "flags: %08lx\n", flags);
3581
3582 mnt_free_context(cxt);
3583 return rc;
3584}
3585
2a472ae8
TW
3586static int test_cxtsync(struct libmnt_test *ts __attribute__((unused)),
3587 int argc, char *argv[])
7b37d5b5
KZ
3588{
3589 struct libmnt_context *cxt;
3590 struct libmnt_fs *fs;
3591 unsigned long flags = 0;
3592 int rc;
3593
3594 if (argc != 4)
3595 return -EINVAL;
3596
3597 fs = mnt_new_fs();
3598 if (!fs)
3599 return -ENOMEM;
3600
3601 rc = mnt_fs_set_options(fs, argv[1]);
3602 if (rc)
3603 return rc;
3604
3605 cxt = mnt_new_context();
3606 if (!cxt)
3607 return -ENOMEM;
3608
3609 rc = mnt_context_set_fs(cxt, fs);
3610 if (rc)
3611 return rc;
3612
3613 rc = mnt_context_append_options(cxt, argv[2]);
3614 if (rc)
3615 return rc;
3616
3617 rc = mnt_fs_append_options(fs, argv[3]);
3618 if (rc)
3619 return rc;
3620
3621 mnt_context_get_mflags(cxt, &flags);
3622
3623 printf(" fs options: %s\n", mnt_fs_get_options(fs));
3624 printf("context options: %s\n", mnt_context_get_options(cxt));
3625 printf(" context mflags: %08lx\n", flags);
3626
3627 mnt_free_context(cxt);
3628 return 0;
3629}
3630
2a472ae8
TW
3631static int test_mountall(struct libmnt_test *ts __attribute__((unused)),
3632 int argc, char *argv[])
9f7472b0
KZ
3633{
3634 struct libmnt_context *cxt;
3635 struct libmnt_iter *itr;
3636 struct libmnt_fs *fs;
3637 int mntrc, ignored, idx = 1;
3638
3639 cxt = mnt_new_context();
3640 itr = mnt_new_iter(MNT_ITER_FORWARD);
3641
3642 if (!cxt || !itr)
3643 return -ENOMEM;
3644
3645 if (argc > 2) {
0770effc 3646 if (argv[idx] && !strcmp(argv[idx], "-O")) {
9f7472b0
KZ
3647 mnt_context_set_options_pattern(cxt, argv[idx + 1]);
3648 idx += 2;
3649 }
1049c4a2 3650 if (argv[idx] && !strcmp(argv[idx], "-t"))
9f7472b0 3651 mnt_context_set_fstype_pattern(cxt, argv[idx + 1]);
9f7472b0
KZ
3652 }
3653
3654 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
3655
3656 const char *tgt = mnt_fs_get_target(fs);
3657
3658 if (ignored == 1)
3659 printf("%s: ignored: not match\n", tgt);
3660 else if (ignored == 2)
3661 printf("%s: ignored: already mounted\n", tgt);
3662
3663 else if (!mnt_context_get_status(cxt)) {
3664 if (mntrc > 0) {
3665 errno = mntrc;
3666 warn("%s: mount failed", tgt);
3667 } else
3668 warnx("%s: mount failed", tgt);
3669 } else
3670 printf("%s: successfully mounted\n", tgt);
3671 }
3672
3673 mnt_free_context(cxt);
3674 return 0;
3675}
3676
7b37d5b5
KZ
3677
3678
ea8f06f9
KZ
3679int main(int argc, char *argv[])
3680{
68164f6c 3681 struct libmnt_test tss[] = {
ea8f06f9
KZ
3682 { "--mount", test_mount, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
3683 { "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
9f7472b0 3684 { "--mount-all", test_mountall, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
ddfc6f28 3685 { "--flags", test_flags, "[-o <opts>] <spec>" },
7b37d5b5 3686 { "--cxtsync", test_cxtsync, "<fsopts> <cxtopts> <fsopts>" },
779e3c97 3687 { "--search-helper", test_search_helper, "<fstype>" },
ea8f06f9
KZ
3688 { NULL }};
3689
b0bb8fb6
KZ
3690 umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */
3691
ea8f06f9
KZ
3692 return mnt_run_test(tss, argc, argv);
3693}
3694
3695#endif /* TEST_PROGRAM */