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