]> git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context.c
libmount: add function attributes to private API
[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). This
1098 * function is deprecated (encrypted loops are no ore supported).
1099 *
1100 * Returns: 0 on success, negative number in case of error.
1101 */
1102 int mnt_context_set_passwd_cb(struct libmnt_context *cxt,
1103 char *(*get)(struct libmnt_context *),
1104 void (*release)(struct libmnt_context *, char *))
1105 {
1106 if (!cxt)
1107 return -EINVAL;
1108
1109 cxt->pwd_get_cb = get;
1110 cxt->pwd_release_cb = release;
1111 return 0;
1112 }
1113
1114 /**
1115 * mnt_context_get_lock:
1116 * @cxt: mount context
1117 *
1118 * The libmount applications don't have to care about mtab locking, but with a
1119 * small exception: the application has to be able to remove the lock file when
1120 * interrupted by signal or signals have to be ignored when the lock is locked.
1121 *
1122 * The default behavior is to ignore all signals (except SIGALRM and
1123 * SIGTRAP for mtab udate) when the lock is locked. If this behavior
1124 * is unacceptable then use:
1125 *
1126 * lc = mnt_context_get_lock(cxt);
1127 * if (lc)
1128 * mnt_lock_block_signals(lc, FALSE);
1129 *
1130 * and don't forget to call mnt_unlock_file(lc) before exit.
1131 *
1132 * Returns: pointer to lock struct or NULL.
1133 */
1134 struct libmnt_lock *mnt_context_get_lock(struct libmnt_context *cxt)
1135 {
1136 /*
1137 * DON'T call this function within libmount, it will always allocate
1138 * the lock. The mnt_update_* functions are able to allocate the lock
1139 * only when mtab/utab update is really necessary.
1140 */
1141 if (!cxt || mnt_context_is_nomtab(cxt))
1142 return NULL;
1143
1144 if (!cxt->lock) {
1145 cxt->lock = mnt_new_lock(cxt->mtab_writable ?
1146 cxt->mtab_path : cxt->utab_path, 0);
1147 if (cxt->lock)
1148 mnt_lock_block_signals(cxt->lock, TRUE);
1149 }
1150 return cxt->lock;
1151 }
1152
1153 /**
1154 * mnt_context_set_mflags:
1155 * @cxt: mount context
1156 * @flags: mount(2) flags (MS_* flags)
1157 *
1158 * Sets mount flags (see mount(2) man page).
1159 *
1160 * Note that mount context allows to define mount options by mount flags. It
1161 * means you can for example use
1162 *
1163 * mnt_context_set_mflags(cxt, MS_NOEXEC | MS_NOSUID);
1164 *
1165 * rather than
1166 *
1167 * mnt_context_set_options(cxt, "noexec,nosuid");
1168 *
1169 * these both calls have the same effect.
1170 *
1171 * Returns: 0 on success, negative number in case of error.
1172 */
1173 int mnt_context_set_mflags(struct libmnt_context *cxt, unsigned long flags)
1174 {
1175 if (!cxt)
1176 return -EINVAL;
1177
1178 cxt->mountflags = flags;
1179
1180 if ((cxt->flags & MNT_FL_MOUNTOPTS_FIXED) && cxt->fs)
1181 /*
1182 * the final mount options are already generated, refresh...
1183 */
1184 return mnt_optstr_apply_flags(
1185 &cxt->fs->vfs_optstr,
1186 cxt->mountflags,
1187 mnt_get_builtin_optmap(MNT_LINUX_MAP));
1188
1189 return 0;
1190 }
1191
1192 /**
1193 * mnt_context_get_mflags:
1194 * @cxt: mount context
1195 * @flags: returns MS_* mount flags
1196 *
1197 * Converts mount options string to MS_* flags and bitewise-OR the result with
1198 * already defined flags (see mnt_context_set_mflags()).
1199 *
1200 * Returns: 0 on success, negative number in case of error.
1201 */
1202 int mnt_context_get_mflags(struct libmnt_context *cxt, unsigned long *flags)
1203 {
1204 int rc = 0;
1205 if (!cxt || !flags)
1206 return -EINVAL;
1207
1208 *flags = 0;
1209 if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1210 const char *o = mnt_fs_get_options(cxt->fs);
1211 if (o)
1212 rc = mnt_optstr_get_flags(o, flags,
1213 mnt_get_builtin_optmap(MNT_LINUX_MAP));
1214 }
1215 if (!rc)
1216 *flags |= cxt->mountflags;
1217 return rc;
1218 }
1219
1220 /**
1221 * mnt_context_set_user_mflags:
1222 * @cxt: mount context
1223 * @flags: mount(2) flags (MNT_MS_* flags, e.g. MNT_MS_LOOP)
1224 *
1225 * Sets userspace mount flags.
1226 *
1227 * See also notest for mnt_context_set_mflags().
1228 *
1229 * Returns: 0 on success, negative number in case of error.
1230 */
1231 int mnt_context_set_user_mflags(struct libmnt_context *cxt, unsigned long flags)
1232 {
1233 if (!cxt)
1234 return -EINVAL;
1235 cxt->user_mountflags = flags;
1236 return 0;
1237 }
1238
1239 /**
1240 * mnt_context_get_user_mflags:
1241 * @cxt: mount context
1242 * @flags: returns mount flags
1243 *
1244 * Converts mount options string to MNT_MS_* flags and bitewise-OR the result
1245 * with already defined flags (see mnt_context_set_user_mflags()).
1246 *
1247 * Returns: 0 on success, negative number in case of error.
1248 */
1249 int mnt_context_get_user_mflags(struct libmnt_context *cxt, unsigned long *flags)
1250 {
1251 int rc = 0;
1252 if (!cxt || !flags)
1253 return -EINVAL;
1254
1255 *flags = 0;
1256 if (!(cxt->flags & MNT_FL_MOUNTFLAGS_MERGED) && cxt->fs) {
1257 const char *o = mnt_fs_get_user_options(cxt->fs);
1258 if (o)
1259 rc = mnt_optstr_get_flags(o, flags,
1260 mnt_get_builtin_optmap(MNT_USERSPACE_MAP));
1261 }
1262 if (!rc)
1263 *flags |= cxt->user_mountflags;
1264 return rc;
1265 }
1266
1267 /**
1268 * mnt_context_set_mountdata:
1269 * @cxt: mount context
1270 * @data: mount(2) data
1271 *
1272 * The mount context generates mountdata from mount options by default. This
1273 * function allows to overwrite this behavior, and @data will be used instead
1274 * of mount options.
1275 *
1276 * The libmount does not deallocated the data by mnt_free_context(). Note that
1277 * NULL is also valid mount data.
1278 *
1279 * Returns: 0 on success, negative number in case of error.
1280 */
1281 int mnt_context_set_mountdata(struct libmnt_context *cxt, void *data)
1282 {
1283 if (!cxt)
1284 return -EINVAL;
1285 cxt->mountdata = data;
1286 cxt->flags |= MNT_FL_MOUNTDATA;
1287 return 0;
1288 }
1289
1290 /*
1291 * Translates LABEL/UUID/path to mountable path
1292 */
1293 int mnt_context_prepare_srcpath(struct libmnt_context *cxt)
1294 {
1295 const char *path = NULL;
1296 struct libmnt_cache *cache;
1297 const char *t, *v, *src;
1298 int rc = 0;
1299
1300 assert(cxt);
1301 assert(cxt->fs);
1302 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1303
1304 if (!cxt || !cxt->fs)
1305 return -EINVAL;
1306
1307 DBG(CXT, mnt_debug_h(cxt, "preparing source path"));
1308
1309 src = mnt_fs_get_source(cxt->fs);
1310
1311 if (!src && (cxt->mountflags & MS_PROPAGATION))
1312 /* mount --make-{shared,private,...} */
1313 return mnt_fs_set_source(cxt->fs, "none");
1314
1315 /* ignore filesystems without source or filesystems
1316 * where the source is quasi-path (//foo/bar)
1317 */
1318 if (!src || mnt_fs_is_netfs(cxt->fs))
1319 return 0;
1320
1321 DBG(CXT, mnt_debug_h(cxt, "srcpath '%s'", src));
1322
1323 cache = mnt_context_get_cache(cxt);
1324
1325 if (!mnt_fs_get_tag(cxt->fs, &t, &v)) {
1326 /*
1327 * Source is TAG (evaluate)
1328 */
1329 if (cache)
1330 path = mnt_resolve_tag(t, v, cache);
1331
1332 rc = path ? mnt_fs_set_source(cxt->fs, path) : -MNT_ERR_NOSOURCE;
1333
1334 } else if (cache && !mnt_fs_is_pseudofs(cxt->fs)) {
1335 /*
1336 * Source is PATH (canonicalize)
1337 */
1338 path = mnt_resolve_path(src, cache);
1339 if (path && strcmp(path, src))
1340 rc = mnt_fs_set_source(cxt->fs, path);
1341 }
1342
1343 if (rc) {
1344 DBG(CXT, mnt_debug_h(cxt, "failed to prepare srcpath [rc=%d]", rc));
1345 return rc;
1346 }
1347
1348 if (!path)
1349 path = src;
1350
1351 if ((cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION | MS_REMOUNT)) ||
1352 mnt_fs_is_pseudofs(cxt->fs)) {
1353 DBG(CXT, mnt_debug_h(cxt, "REMOUNT/BIND/MOVE/pseudo FS source: %s", path));
1354 return rc;
1355 }
1356
1357 /*
1358 * Initialize loop device
1359 */
1360 if (mnt_context_is_loopdev(cxt)) {
1361 rc = mnt_context_setup_loopdev(cxt);
1362 if (rc)
1363 return rc;
1364 }
1365
1366 DBG(CXT, mnt_debug_h(cxt, "final srcpath '%s'",
1367 mnt_fs_get_source(cxt->fs)));
1368 return 0;
1369 }
1370
1371 int mnt_context_prepare_target(struct libmnt_context *cxt)
1372 {
1373 const char *tgt;
1374 struct libmnt_cache *cache;
1375 int rc = 0;
1376
1377 assert(cxt);
1378 assert(cxt->fs);
1379 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1380
1381 if (!cxt || !cxt->fs)
1382 return -EINVAL;
1383
1384 DBG(CXT, mnt_debug_h(cxt, "preparing target path"));
1385
1386 tgt = mnt_fs_get_target(cxt->fs);
1387 if (!tgt)
1388 return 0;
1389
1390 cache = mnt_context_get_cache(cxt);
1391 if (cache) {
1392 char *path = mnt_resolve_path(tgt, cache);
1393 if (path && strcmp(path, tgt) != 0)
1394 rc = mnt_fs_set_target(cxt->fs, path);
1395 }
1396
1397 if (rc)
1398 DBG(CXT, mnt_debug_h(cxt, "failed to prepare target '%s'", tgt));
1399 else
1400 DBG(CXT, mnt_debug_h(cxt, "final target '%s'",
1401 mnt_fs_get_target(cxt->fs)));
1402 return 0;
1403 }
1404
1405 /*
1406 * It's usully no error when we're not able to detect filesystem type -- we
1407 * will try to use types from /{etc,proc}/filesystems.
1408 */
1409 int mnt_context_guess_fstype(struct libmnt_context *cxt)
1410 {
1411 char *type;
1412 const char *dev;
1413 int rc = 0;
1414
1415 assert(cxt);
1416 assert(cxt->fs);
1417 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1418
1419 if (!cxt || !cxt->fs)
1420 return -EINVAL;
1421
1422 if (cxt->mountflags & (MS_BIND | MS_MOVE | MS_PROPAGATION))
1423 goto none;
1424
1425 type = (char *) mnt_fs_get_fstype(cxt->fs);
1426 if (type && !strcmp(type, "auto")) {
1427 mnt_fs_set_fstype(cxt->fs, NULL);
1428 type = NULL;
1429 }
1430
1431 if (type)
1432 goto done;
1433 if (cxt->flags & MS_REMOUNT)
1434 goto none;
1435 if (cxt->fstype_pattern)
1436 goto done;
1437
1438 dev = mnt_fs_get_srcpath(cxt->fs);
1439 if (!dev)
1440 goto done;
1441
1442 if (access(dev, F_OK) == 0) {
1443 struct libmnt_cache *cache = mnt_context_get_cache(cxt);
1444
1445 type = mnt_get_fstype(dev, &cxt->ambi, cache);
1446 if (type) {
1447 rc = mnt_fs_set_fstype(cxt->fs, type);
1448 if (!cache)
1449 free(type); /* type is not cached */
1450 }
1451 } else {
1452 if (strchr(dev, ':') != NULL)
1453 rc = mnt_fs_set_fstype(cxt->fs, "nfs");
1454 else if (!strncmp(dev, "//", 2))
1455 rc = mnt_fs_set_fstype(cxt->fs, "cifs");
1456 }
1457
1458 done:
1459 DBG(CXT, mnt_debug_h(cxt, "FS type: %s", mnt_fs_get_fstype(cxt->fs)));
1460 return rc;
1461 none:
1462 return mnt_fs_set_fstype(cxt->fs, "none");
1463 }
1464
1465 /*
1466 * The default is to use fstype from cxt->fs, this could be overwritten by
1467 * @type. The @act is MNT_ACT_{MOUNT,UMOUNT}.
1468 *
1469 * Returns: 0 on success or negative number in case of error. Note that success
1470 * does not mean that there is any usable helper, you have to check cxt->helper.
1471 */
1472 int mnt_context_prepare_helper(struct libmnt_context *cxt, const char *name,
1473 const char *type)
1474 {
1475 char search_path[] = FS_SEARCH_PATH; /* from config.h */
1476 char *p = NULL, *path;
1477
1478 assert(cxt);
1479 assert(cxt->fs);
1480 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1481
1482 if (!type)
1483 type = mnt_fs_get_fstype(cxt->fs);
1484
1485 if (type && strchr(type, ','))
1486 return 0; /* type is fstype pattern */
1487
1488 if (mnt_context_is_nohelpers(cxt)
1489 || !type
1490 || !strcmp(type, "none")
1491 || mnt_fs_is_swaparea(cxt->fs))
1492 return 0;
1493
1494 path = strtok_r(search_path, ":", &p);
1495 while (path) {
1496 char helper[PATH_MAX];
1497 struct stat st;
1498 int rc;
1499
1500 rc = snprintf(helper, sizeof(helper), "%s/%s.%s",
1501 path, name, type);
1502 path = strtok_r(NULL, ":", &p);
1503
1504 if (rc < 0 || (size_t) rc >= sizeof(helper))
1505 continue;
1506
1507 rc = stat(helper, &st);
1508 if (rc == -1 && errno == ENOENT && strchr(type, '.')) {
1509 /* If type ends with ".subtype" try without it */
1510 char *hs = strrchr(helper, '.');
1511 if (hs)
1512 *hs = '\0';
1513 rc = stat(helper, &st);
1514 }
1515
1516 DBG(CXT, mnt_debug_h(cxt, "%-25s ... %s", helper,
1517 rc ? "not found" : "found"));
1518 if (rc)
1519 continue;
1520
1521 free(cxt->helper);
1522 cxt->helper = strdup(helper);
1523 if (!cxt->helper)
1524 return -ENOMEM;
1525 return 0;
1526 }
1527
1528 return 0;
1529 }
1530
1531 int mnt_context_merge_mflags(struct libmnt_context *cxt)
1532 {
1533 unsigned long fl = 0;
1534 int rc;
1535
1536 assert(cxt);
1537
1538 DBG(CXT, mnt_debug_h(cxt, "merging mount flags"));
1539
1540 rc = mnt_context_get_mflags(cxt, &fl);
1541 if (rc)
1542 return rc;
1543 cxt->mountflags = fl;
1544
1545 fl = 0;
1546 rc = mnt_context_get_user_mflags(cxt, &fl);
1547 if (rc)
1548 return rc;
1549 cxt->user_mountflags = fl;
1550
1551 DBG(CXT, mnt_debug_h(cxt, "final flags: VFS=%08lx user=%08lx",
1552 cxt->mountflags, cxt->user_mountflags));
1553
1554 cxt->flags |= MNT_FL_MOUNTFLAGS_MERGED;
1555 return 0;
1556 }
1557
1558 /*
1559 * Prepare /etc/mtab or /run/mount/utab
1560 */
1561 int mnt_context_prepare_update(struct libmnt_context *cxt)
1562 {
1563 int rc;
1564 const char *target;
1565
1566 assert(cxt);
1567 assert(cxt->fs);
1568 assert(cxt->action);
1569 assert((cxt->flags & MNT_FL_MOUNTFLAGS_MERGED));
1570
1571 DBG(CXT, mnt_debug_h(cxt, "prepare update"));
1572
1573 if (cxt->mountflags & MS_PROPAGATION) {
1574 DBG(CXT, mnt_debug_h(cxt, "skip update: MS_PROPAGATION"));
1575 return 0;
1576 }
1577
1578 target = mnt_fs_get_target(cxt->fs);
1579
1580 if (cxt->action == MNT_ACT_UMOUNT && target && !strcmp(target, "/"))
1581 /* Don't try to touch mtab if umounting root FS */
1582 mnt_context_disable_mtab(cxt, TRUE);
1583
1584 if (mnt_context_is_nomtab(cxt)) {
1585 DBG(CXT, mnt_debug_h(cxt, "skip update: NOMTAB flag"));
1586 return 0;
1587 }
1588 if (cxt->helper) {
1589 DBG(CXT, mnt_debug_h(cxt, "skip update: external helper"));
1590 return 0;
1591 }
1592 if (!cxt->mtab_writable && !cxt->utab_writable) {
1593 DBG(CXT, mnt_debug_h(cxt, "skip update: no writable destination"));
1594 return 0;
1595 }
1596 /* 0 = success, 1 = not called yet */
1597 if (cxt->syscall_status != 1 && cxt->syscall_status != 0) {
1598 DBG(CXT, mnt_debug_h(cxt,
1599 "skip update: syscall failed [status=%d]",
1600 cxt->syscall_status));
1601 return 0;
1602 }
1603 if (!cxt->update) {
1604 cxt->update = mnt_new_update();
1605 if (!cxt->update)
1606 return -ENOMEM;
1607
1608 mnt_update_set_filename(cxt->update,
1609 cxt->mtab_writable ? cxt->mtab_path : cxt->utab_path,
1610 !cxt->mtab_writable);
1611 }
1612
1613 if (cxt->action == MNT_ACT_UMOUNT)
1614 rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1615 mnt_context_get_target(cxt), NULL);
1616 else
1617 rc = mnt_update_set_fs(cxt->update, cxt->mountflags,
1618 NULL, cxt->fs);
1619
1620 return rc < 0 ? rc : 0;
1621 }
1622
1623 int mnt_context_update_tabs(struct libmnt_context *cxt)
1624 {
1625 unsigned long fl;
1626
1627 assert(cxt);
1628
1629 if (mnt_context_is_nomtab(cxt)) {
1630 DBG(CXT, mnt_debug_h(cxt, "don't update: NOMTAB flag"));
1631 return 0;
1632 }
1633 if (cxt->helper) {
1634 DBG(CXT, mnt_debug_h(cxt, "don't update: external helper"));
1635 return 0;
1636 }
1637 if (!cxt->update || !mnt_update_is_ready(cxt->update)) {
1638 DBG(CXT, mnt_debug_h(cxt, "don't update: no update prepared"));
1639 return 0;
1640 }
1641 if (cxt->syscall_status) {
1642 DBG(CXT, mnt_debug_h(cxt, "don't update: syscall failed/not called"));
1643 return 0;
1644 }
1645
1646 fl = mnt_update_get_mflags(cxt->update);
1647 if ((cxt->mountflags & MS_RDONLY) != (fl & MS_RDONLY))
1648 /*
1649 * fix MS_RDONLY in options
1650 */
1651 mnt_update_force_rdonly(cxt->update,
1652 cxt->mountflags & MS_RDONLY);
1653
1654 return mnt_update_table(cxt->update, cxt->lock);
1655 }
1656
1657 static int apply_table(struct libmnt_context *cxt, struct libmnt_table *tb,
1658 int direction)
1659 {
1660 struct libmnt_fs *fs = NULL;
1661 const char *src = NULL, *tgt = NULL;
1662 int rc;
1663
1664 assert(cxt);
1665 assert(cxt->fs);
1666
1667 if (!cxt->fs)
1668 return -EINVAL;
1669
1670 src = mnt_fs_get_source(cxt->fs);
1671 tgt = mnt_fs_get_target(cxt->fs);
1672
1673 if (tgt && src)
1674 fs = mnt_table_find_pair(tb, src, tgt, direction);
1675 else {
1676 if (src)
1677 fs = mnt_table_find_source(tb, src, direction);
1678 else if (tgt)
1679 fs = mnt_table_find_target(tb, tgt, direction);
1680
1681 if (!fs && mnt_context_is_swapmatch(cxt)) {
1682 /* swap source and target (if @src is not LABEL/UUID),
1683 * for example in
1684 *
1685 * mount /foo/bar
1686 *
1687 * the path could be a mountpoint as well as source (for
1688 * example bind mount, symlink to device, ...).
1689 */
1690 if (src && !mnt_fs_get_tag(cxt->fs, NULL, NULL))
1691 fs = mnt_table_find_target(tb, src, direction);
1692 if (!fs && tgt)
1693 fs = mnt_table_find_source(tb, tgt, direction);
1694 }
1695 }
1696
1697 if (!fs)
1698 return -MNT_ERR_NOFSTAB; /* not found */
1699
1700 DBG(CXT, mnt_debug_h(cxt, "apply entry:"));
1701 DBG(CXT, mnt_fs_print_debug(fs, stderr));
1702
1703 /* copy from tab to our FS description
1704 */
1705 rc = mnt_fs_set_source(cxt->fs, mnt_fs_get_source(fs));
1706 if (!rc)
1707 rc = mnt_fs_set_target(cxt->fs, mnt_fs_get_target(fs));
1708
1709 if (!rc && !mnt_fs_get_fstype(cxt->fs))
1710 rc = mnt_fs_set_fstype(cxt->fs, mnt_fs_get_fstype(fs));
1711
1712 if (rc)
1713 return rc;
1714
1715 if (cxt->optsmode & MNT_OMODE_IGNORE)
1716 ;
1717 else if (cxt->optsmode & MNT_OMODE_REPLACE)
1718 rc = mnt_fs_set_options(cxt->fs, mnt_fs_get_options(fs));
1719
1720 else if (cxt->optsmode & MNT_OMODE_APPEND)
1721 rc = mnt_fs_append_options(cxt->fs, mnt_fs_get_options(fs));
1722
1723 else if (cxt->optsmode & MNT_OMODE_PREPEND)
1724 rc = mnt_fs_prepend_options(cxt->fs, mnt_fs_get_options(fs));
1725
1726 if (!rc)
1727 cxt->flags |= MNT_FL_TAB_APPLIED;
1728 return rc;
1729 }
1730
1731 /**
1732 * mnt_context_apply_fstab:
1733 * @cxt: mount context
1734 *
1735 * This function is optional.
1736 *
1737 * Returns: 0 on success, negative number in case of error.
1738 */
1739 int mnt_context_apply_fstab(struct libmnt_context *cxt)
1740 {
1741 int rc = -1;
1742 struct libmnt_table *tab = NULL;
1743 const char *src = NULL, *tgt = NULL;
1744
1745 assert(cxt);
1746 assert(cxt->fs);
1747
1748 if (!cxt)
1749 return -EINVAL;
1750
1751 if (mnt_context_tab_applied(cxt)) /* already applied */
1752 return 0;
1753
1754 if (mnt_context_is_restricted(cxt)) {
1755 DBG(CXT, mnt_debug_h(cxt, "force fstab usage for non-root users!"));
1756 cxt->optsmode = MNT_OMODE_USER;
1757 } else if (cxt->optsmode == 0) {
1758 DBG(CXT, mnt_debug_h(cxt, "use default optmode"));
1759 cxt->optsmode = MNT_OMODE_AUTO;
1760 } else if (cxt->optsmode & MNT_OMODE_NOTAB) {
1761 cxt->optsmode &= ~MNT_OMODE_FSTAB;
1762 cxt->optsmode &= ~MNT_OMODE_MTAB;
1763 cxt->optsmode &= ~MNT_OMODE_FORCE;
1764 }
1765
1766 if (cxt->fs) {
1767 src = mnt_fs_get_source(cxt->fs);
1768 tgt = mnt_fs_get_target(cxt->fs);
1769 }
1770
1771 DBG(CXT, mnt_debug_h(cxt, "OPTSMODE: ignore=%d, append=%d, prepend=%d, "
1772 "replace=%d, force=%d, fstab=%d, mtab=%d",
1773 cxt->optsmode & MNT_OMODE_IGNORE ? 1 : 0,
1774 cxt->optsmode & MNT_OMODE_APPEND ? 1 : 0,
1775 cxt->optsmode & MNT_OMODE_PREPEND ? 1 : 0,
1776 cxt->optsmode & MNT_OMODE_REPLACE ? 1 : 0,
1777 cxt->optsmode & MNT_OMODE_FORCE ? 1 : 0,
1778 cxt->optsmode & MNT_OMODE_FSTAB ? 1 : 0,
1779 cxt->optsmode & MNT_OMODE_MTAB ? 1 : 0));
1780
1781 /* fstab is not required if source and target are specified */
1782 if (src && tgt && !(cxt->optsmode & MNT_OMODE_FORCE)) {
1783 DBG(CXT, mnt_debug_h(cxt, "fstab not required -- skip"));
1784 return 0;
1785 }
1786
1787 if (!src && tgt
1788 && !(cxt->optsmode & MNT_OMODE_FSTAB)
1789 && !(cxt->optsmode & MNT_OMODE_MTAB)) {
1790 DBG(CXT, mnt_debug_h(cxt, "only target; fstab/mtab not required "
1791 "-- skip, probably MS_PROPAGATION"));
1792 return 0;
1793 }
1794
1795 DBG(CXT, mnt_debug_h(cxt,
1796 "trying to apply fstab (src=%s, target=%s)", src, tgt));
1797
1798 /* let's initialize cxt->fs */
1799 ignore_result( mnt_context_get_fs(cxt) );
1800
1801 /* try fstab */
1802 if (cxt->optsmode & MNT_OMODE_FSTAB) {
1803 rc = mnt_context_get_fstab(cxt, &tab);
1804 if (!rc)
1805 rc = apply_table(cxt, tab, MNT_ITER_FORWARD);
1806 }
1807
1808 /* try mtab */
1809 if (rc < 0 && (cxt->optsmode & MNT_OMODE_MTAB)) {
1810 DBG(CXT, mnt_debug_h(cxt, "trying to apply from mtab"));
1811 rc = mnt_context_get_mtab(cxt, &tab);
1812 if (!rc)
1813 rc = apply_table(cxt, tab, MNT_ITER_BACKWARD);
1814 }
1815 if (rc)
1816 DBG(CXT, mnt_debug_h(cxt, "failed to find entry in fstab/mtab"));
1817 return rc;
1818 }
1819
1820 /**
1821 * mnt_context_tab_applied:
1822 * @cxt: mount context
1823 *
1824 * Returns: 1 if fstab (or mtab) has been applied to the context, or 0.
1825 */
1826 int mnt_context_tab_applied(struct libmnt_context *cxt)
1827 {
1828 return cxt && (cxt->flags & MNT_FL_TAB_APPLIED);
1829 }
1830
1831 /**
1832 * mnt_context_get_status:
1833 * @cxt: mount context
1834 *
1835 * Global libmount status.
1836 *
1837 * The real exit code of the mount.type helper has to be tested by
1838 * mnt_context_get_helper_status(). The mnt_context_get_status() only inform
1839 * that exec() has been successful.
1840 *
1841 * Returns: 1 if mount.type or mount(2) syscall has been successfully called.
1842 */
1843 int mnt_context_get_status(struct libmnt_context *cxt)
1844 {
1845 return cxt && (!cxt->syscall_status || !cxt->helper_exec_status);
1846 }
1847
1848 /**
1849 * mnt_context_helper_executed:
1850 * @cxt: mount context
1851 *
1852 * Returns: 1 if mount.type helper has been executed, or 0.
1853 */
1854 int mnt_context_helper_executed(struct libmnt_context *cxt)
1855 {
1856 return cxt->helper_exec_status != 1;
1857 }
1858
1859 /**
1860 * mnt_context_get_helper_status:
1861 * @cxt: mount context
1862 *
1863 * Return: mount.type helper exit status, result is reliable only if
1864 * mnt_context_helper_executed() returns 1.
1865 */
1866 int mnt_context_get_helper_status(struct libmnt_context *cxt)
1867 {
1868 return cxt->helper_status;
1869 }
1870
1871 /**
1872 * mnt_context_syscall_called:
1873 * @cxt: mount context
1874 *
1875 * Returns: 1 if mount(2) syscall has been called, or 0.
1876 */
1877 int mnt_context_syscall_called(struct libmnt_context *cxt)
1878 {
1879 return cxt->syscall_status != 1;
1880 }
1881
1882 /**
1883 * mnt_context_get_syscall_errno:
1884 * @cxt: mount context
1885 *
1886 * The result from this function is reliable only if
1887 * mnt_context_syscall_called() returns 1.
1888 *
1889 * Returns: mount(2) errno if the syscall failed or 0.
1890 */
1891 int mnt_context_get_syscall_errno(struct libmnt_context *cxt)
1892 {
1893 if (cxt->syscall_status < 0)
1894 return -cxt->syscall_status;
1895
1896 return 0;
1897 }
1898
1899 /**
1900 * mnt_context_set_syscall_status:
1901 * @cxt: mount context
1902 * @status: mount(2) status
1903 *
1904 * The @status should be 0 on success, or negative number on error (-errno).
1905 *
1906 * This function should be used only if [u]mount(2) syscall is NOT called by
1907 * libmount code.
1908 *
1909 * Returns: 0 or negative number in case of error.
1910 */
1911 int mnt_context_set_syscall_status(struct libmnt_context *cxt, int status)
1912 {
1913 if (!cxt)
1914 return -EINVAL;
1915
1916 DBG(CXT, mnt_debug_h(cxt, "syscall status set to: %d", status));
1917 cxt->syscall_status = status;
1918 return 0;
1919 }
1920
1921 /**
1922 * mnt_context_strerror
1923 * @cxt: context
1924 * @buf: buffer
1925 * @bufsiz: size of the buffer
1926 *
1927 * Not implemented yet.
1928 *
1929 * Returns: 0 or negative number in case of error.
1930 */
1931 int mnt_context_strerror(struct libmnt_context *cxt __attribute__((__unused__)),
1932 char *buf __attribute__((__unused__)),
1933 size_t bufsiz __attribute__((__unused__)))
1934 {
1935 /* TODO: based on cxt->syscall_errno or cxt->helper_status */
1936 return 0;
1937 }
1938
1939 /**
1940 * mnt_context_init_helper
1941 * @cxt: mount context
1942 * @action: MNT_ACT_{UMOUNT,MOUNT}
1943 * @flags: not used now
1944 *
1945 * This function infors libmount that used from [u]mount.type helper.
1946 *
1947 * The function also calls mnt_context_disable_helpers() to avoid recursive
1948 * mount.type helpers calling. It you really want to call another
1949 * mount.type helper from your helper than you have to explicitly enable this
1950 * feature by:
1951 *
1952 * mnt_context_disable_helpers(cxt, FALSE);
1953 *
1954 * Returns: 0 on success, negative number in case of error.
1955 */
1956 int mnt_context_init_helper(struct libmnt_context *cxt, int action,
1957 int flags __attribute__((__unused__)))
1958 {
1959 int rc = mnt_context_disable_helpers(cxt, TRUE);
1960
1961 if (!rc)
1962 rc = set_flag(cxt, MNT_FL_HELPER, 1);
1963 if (!rc)
1964 cxt->action = action;
1965
1966 DBG(CXT, mnt_debug_h(cxt, "initialized for [u]mount.<type> helper [rc=%d]", rc));
1967 return rc;
1968 }
1969
1970 /**
1971 * mnt_context_helper_setopt:
1972 * @cxt: context
1973 * @c: getopt() result
1974 * @arg: getopt() optarg
1975 *
1976 * This function applies [u]mount.type command line option (for example parsed
1977 * by getopt or getopt_long) to @cxt. All unknown options are ignored and
1978 * then 1 is returned.
1979 *
1980 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
1981 */
1982 int mnt_context_helper_setopt(struct libmnt_context *cxt, int c, char *arg)
1983 {
1984 if (cxt) {
1985 switch(cxt->action) {
1986 case MNT_ACT_MOUNT:
1987 return mnt_context_mount_setopt(cxt, c, arg);
1988 case MNT_ACT_UMOUNT:
1989 return mnt_context_umount_setopt(cxt, c, arg);
1990 }
1991 }
1992 return -EINVAL;
1993 }
1994
1995 /**
1996 * mnt_context_is_fs_mounted:
1997 * @cxt: context
1998 * @fs: filesystem
1999 * @mounted: returns 1 for mounted and 0 for non-mounted filesystems
2000 *
2001 * Please, read mnt_table_is_fs_mounted() description!
2002 *
2003 * Returns: 0 on success and negative number in case of error.
2004 */
2005 int mnt_context_is_fs_mounted(struct libmnt_context *cxt,
2006 struct libmnt_fs *fs, int *mounted)
2007 {
2008 struct libmnt_table *mtab;
2009 int rc;
2010
2011 if (!cxt || !fs || !mounted)
2012 return -EINVAL;
2013
2014 rc = mnt_context_get_mtab(cxt, &mtab);
2015 if (rc)
2016 return rc;
2017
2018 *mounted = mnt_table_is_fs_mounted(mtab, fs);
2019 return 0;
2020 }
2021
2022 static int mnt_context_add_child(struct libmnt_context *cxt, pid_t pid)
2023 {
2024 pid_t *pids;
2025
2026 if (!cxt)
2027 return -EINVAL;
2028
2029 pids = realloc(cxt->children, sizeof(pid_t) * cxt->nchildren + 1);
2030 if (!pids)
2031 return -ENOMEM;
2032
2033 DBG(CXT, mnt_debug_h(cxt, "add new child %d", pid));
2034 cxt->children = pids;
2035 cxt->children[cxt->nchildren++] = pid;
2036
2037 return 0;
2038 }
2039
2040 int mnt_fork_context(struct libmnt_context *cxt)
2041 {
2042 int rc = 0;
2043 pid_t pid;
2044
2045 if (!mnt_context_is_parent(cxt))
2046 return -EINVAL;
2047
2048 DBG(CXT, mnt_debug_h(cxt, "forking context"));
2049
2050 DBG_FLUSH;
2051
2052 pid = fork();
2053
2054 switch (pid) {
2055 case -1: /* error */
2056 DBG(CXT, mnt_debug_h(cxt, "fork failed %m"));
2057 return -errno;
2058
2059 case 0: /* child */
2060 cxt->pid = getpid();
2061 mnt_context_enable_fork(cxt, FALSE);
2062 DBG(CXT, mnt_debug_h(cxt, "child created"));
2063 break;
2064
2065 default:
2066 rc = mnt_context_add_child(cxt, pid);
2067 break;
2068 }
2069
2070 return rc;
2071 }
2072
2073 int mnt_context_wait_for_children(struct libmnt_context *cxt,
2074 int *nchildren, int *nerrs)
2075 {
2076 int i;
2077
2078 if (!cxt)
2079 return -EINVAL;
2080
2081 assert(mnt_context_is_parent(cxt));
2082
2083 for (i = 0; i < cxt->nchildren; i++) {
2084 pid_t pid = cxt->children[i];
2085 int rc = 0, ret = 0;
2086
2087 if (!pid)
2088 continue;
2089 do {
2090 DBG(CXT, mnt_debug_h(cxt,
2091 "waiting for child (%d/%d): %d",
2092 i + 1, cxt->nchildren, pid));
2093 errno = 0;
2094 rc = waitpid(pid, &ret, 0);
2095
2096 } while (rc == -1 && errno == EINTR);
2097
2098 if (nchildren)
2099 (*nchildren)++;
2100
2101 if (rc != -1 && nerrs) {
2102 if (WIFEXITED(ret))
2103 (*nerrs) += WEXITSTATUS(ret) == 0 ? 0 : 1;
2104 else
2105 (*nerrs)++;
2106 }
2107 cxt->children[i] = 0;
2108 }
2109
2110 cxt->nchildren = 0;
2111 free(cxt->children);
2112 cxt->children = NULL;
2113 return 0;
2114 }
2115
2116
2117
2118 #ifdef TEST_PROGRAM
2119
2120 struct libmnt_lock *lock;
2121
2122 static void lock_fallback(void)
2123 {
2124 if (lock)
2125 mnt_unlock_file(lock);
2126 }
2127
2128 int test_mount(struct libmnt_test *ts, int argc, char *argv[])
2129 {
2130 int idx = 1, rc = 0;
2131 struct libmnt_context *cxt;
2132
2133 if (argc < 2)
2134 return -EINVAL;
2135
2136 cxt = mnt_new_context();
2137 if (!cxt)
2138 return -ENOMEM;
2139
2140 if (!strcmp(argv[idx], "-o")) {
2141 mnt_context_set_options(cxt, argv[idx + 1]);
2142 idx += 2;
2143 }
2144 if (!strcmp(argv[idx], "-t")) {
2145 /* TODO: use mnt_context_set_fstype_pattern() */
2146 mnt_context_set_fstype(cxt, argv[idx + 1]);
2147 idx += 2;
2148 }
2149
2150 if (argc == idx + 1)
2151 /* mount <mountpont>|<device> */
2152 mnt_context_set_target(cxt, argv[idx++]);
2153
2154 else if (argc == idx + 2) {
2155 /* mount <device> <mountpoint> */
2156 mnt_context_set_source(cxt, argv[idx++]);
2157 mnt_context_set_target(cxt, argv[idx++]);
2158 }
2159
2160 /* this is unnecessary! -- libmount is able to internaly
2161 * create and manage the lock
2162 */
2163 lock = mnt_context_get_lock(cxt);
2164 if (lock)
2165 atexit(lock_fallback);
2166
2167 rc = mnt_context_mount(cxt);
2168 if (rc)
2169 printf("failed to mount: %m\n");
2170 else
2171 printf("successfully mounted\n");
2172
2173 lock = NULL; /* because we use atexit lock_fallback */
2174 mnt_free_context(cxt);
2175 return rc;
2176 }
2177
2178 int test_umount(struct libmnt_test *ts, int argc, char *argv[])
2179 {
2180 int idx = 1, rc = 0;
2181 struct libmnt_context *cxt;
2182
2183 if (argc < 2)
2184 return -EINVAL;
2185
2186 cxt = mnt_new_context();
2187 if (!cxt)
2188 return -ENOMEM;
2189
2190 if (!strcmp(argv[idx], "-t")) {
2191 mnt_context_set_fstype(cxt, argv[idx + 1]);
2192 idx += 2;
2193 }
2194
2195 if (!strcmp(argv[idx], "-f")) {
2196 mnt_context_enable_force(cxt, TRUE);
2197 idx++;
2198 }
2199
2200 if (!strcmp(argv[idx], "-l")) {
2201 mnt_context_enable_lazy(cxt, TRUE);
2202 idx++;
2203 }
2204
2205 if (!strcmp(argv[idx], "-r")) {
2206 mnt_context_enable_rdonly_umount(cxt, TRUE);
2207 idx++;
2208 }
2209
2210 if (argc == idx + 1) {
2211 /* mount <mountpont>|<device> */
2212 mnt_context_set_target(cxt, argv[idx++]);
2213 } else {
2214 rc = -EINVAL;
2215 goto err;
2216 }
2217
2218 lock = mnt_context_get_lock(cxt);
2219 if (lock)
2220 atexit(lock_fallback);
2221
2222 rc = mnt_context_umount(cxt);
2223 if (rc)
2224 printf("failed to umount\n");
2225 else
2226 printf("successfully umounted\n");
2227 err:
2228 lock = NULL; /* because we use atexit lock_fallback */
2229 mnt_free_context(cxt);
2230 return rc;
2231 }
2232
2233 int test_flags(struct libmnt_test *ts, int argc, char *argv[])
2234 {
2235 int idx = 1, rc = 0;
2236 struct libmnt_context *cxt;
2237 const char *opt = NULL;
2238 unsigned long flags = 0;
2239
2240 if (argc < 2)
2241 return -EINVAL;
2242
2243 cxt = mnt_new_context();
2244 if (!cxt)
2245 return -ENOMEM;
2246
2247 if (!strcmp(argv[idx], "-o")) {
2248 mnt_context_set_options(cxt, argv[idx + 1]);
2249 idx += 2;
2250 }
2251
2252 if (argc == idx + 1)
2253 /* mount <mountpont>|<device> */
2254 mnt_context_set_target(cxt, argv[idx++]);
2255
2256 rc = mnt_context_prepare_mount(cxt);
2257 if (rc)
2258 printf("failed to prepare mount %s\n", strerror(-rc));
2259
2260 opt = mnt_fs_get_options(cxt->fs);
2261 if (opt)
2262 fprintf(stdout, "options: %s\n", opt);
2263
2264 mnt_context_get_mflags(cxt, &flags);
2265 fprintf(stdout, "flags: %08lx\n", flags);
2266
2267 mnt_free_context(cxt);
2268 return rc;
2269 }
2270
2271 int test_mountall(struct libmnt_test *ts, int argc, char *argv[])
2272 {
2273 struct libmnt_context *cxt;
2274 struct libmnt_iter *itr;
2275 struct libmnt_fs *fs;
2276 int mntrc, ignored, idx = 1;
2277
2278 cxt = mnt_new_context();
2279 itr = mnt_new_iter(MNT_ITER_FORWARD);
2280
2281 if (!cxt || !itr)
2282 return -ENOMEM;
2283
2284 if (argc > 2) {
2285 if (!strcmp(argv[idx], "-O")) {
2286 mnt_context_set_options_pattern(cxt, argv[idx + 1]);
2287 idx += 2;
2288 }
2289 if (!strcmp(argv[idx], "-t")) {
2290 mnt_context_set_fstype_pattern(cxt, argv[idx + 1]);
2291 idx += 2;
2292 }
2293 }
2294
2295 while (mnt_context_next_mount(cxt, itr, &fs, &mntrc, &ignored) == 0) {
2296
2297 const char *tgt = mnt_fs_get_target(fs);
2298
2299 if (ignored == 1)
2300 printf("%s: ignored: not match\n", tgt);
2301 else if (ignored == 2)
2302 printf("%s: ignored: already mounted\n", tgt);
2303
2304 else if (!mnt_context_get_status(cxt)) {
2305 if (mntrc > 0) {
2306 errno = mntrc;
2307 warn("%s: mount failed", tgt);
2308 } else
2309 warnx("%s: mount failed", tgt);
2310 } else
2311 printf("%s: successfully mounted\n", tgt);
2312 }
2313
2314 mnt_free_context(cxt);
2315 return 0;
2316 }
2317
2318 int main(int argc, char *argv[])
2319 {
2320 struct libmnt_test tss[] = {
2321 { "--mount", test_mount, "[-o <opts>] [-t <type>] <spec>|<src> <target>" },
2322 { "--umount", test_umount, "[-t <type>] [-f][-l][-r] <src>|<target>" },
2323 { "--mount-all", test_mountall, "[-O <pattern>] [-t <pattern] mount all filesystems from fstab" },
2324 { "--flags", test_flags, "[-o <opts>] <spec>" },
2325 { NULL }};
2326
2327 umask(S_IWGRP|S_IWOTH); /* to be compatible with mount(8) */
2328
2329 return mnt_run_test(tss, argc, argv);
2330 }
2331
2332 #endif /* TEST_PROGRAM */