]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - libmount/src/context_umount.c
2 * Copyright (C) 2010 Karel Zak <kzak@redhat.com>
4 * This file may be redistributed under the terms of the
5 * GNU Lesser General Public License.
9 * SECTION: context-umount
10 * @title: Umount context
11 * @short_description: high-level API to umount operation.
15 #include <sys/mount.h>
17 #include "pathnames.h"
26 # define MNT_FORCE 0x00000001 /* Attempt to forcibly umount */
30 # define MNT_DETACH 0x00000002 /* Just detach from the tree */
33 #ifndef UMOUNT_NOFOLLOW
34 # define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
38 # define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
42 * mnt_context_find_umount_fs:
44 * @tgt: mountpoint, device, ...
45 * @pfs: returns point to filesystem
47 * Returns: 0 on success, <0 on error, 1 if target filesystem not found
49 int mnt_context_find_umount_fs(struct libmnt_context
*cxt
,
51 struct libmnt_fs
**pfs
)
54 struct libmnt_table
*mtab
= NULL
;
61 if (!cxt
|| !tgt
|| !pfs
)
64 DBG(CXT
, ul_debugobj(cxt
, "umount: lookup FS for '%s'", tgt
));
67 return 1; /* empty string is not an error */
70 * The mount table may be huge, and on systems with utab we have to merge
71 * userspace mount options into /proc/self/mountinfo. This all is
72 * expensive. The tab filter allows to filter out entries, then
73 * a mount table and utab are very tiny files.
75 * *but*... the filter uses mnt_fs_streq_{target,srcpath} functions
76 * where LABEL, UUID or symlinks are canonicalized. It means that
77 * it's usable only for canonicalized stuff (e.g. kernel mountinfo).
79 if (!mnt_context_mtab_writable(cxt
) && *tgt
== '/' &&
80 !mnt_context_is_force(cxt
) && !mnt_context_is_lazy(cxt
))
81 rc
= mnt_context_get_mtab_for_target(cxt
, &mtab
, tgt
);
83 rc
= mnt_context_get_mtab(cxt
, &mtab
);
86 DBG(CXT
, ul_debugobj(cxt
, "umount: failed to read mtab"));
90 if (mnt_table_get_nents(mtab
) == 0) {
91 DBG(CXT
, ul_debugobj(cxt
, "umount: mtab empty"));
96 fs
= mnt_table_find_target(mtab
, tgt
, MNT_ITER_BACKWARD
);
97 if (!fs
&& mnt_context_is_swapmatch(cxt
)) {
99 * Maybe the option is source rather than target (sometimes
100 * people use e.g. "umount /dev/sda1")
102 fs
= mnt_table_find_source(mtab
, tgt
, MNT_ITER_BACKWARD
);
105 struct libmnt_fs
*fs1
= mnt_table_find_target(mtab
,
106 mnt_fs_get_target(fs
),
109 DBG(CXT
, ul_debugobj(cxt
, "mtab is broken?!?!"));
114 /* Something was stacked over `file' on the
115 * same mount point. */
116 DBG(CXT
, ul_debugobj(cxt
,
117 "umount: %s: %s is mounted "
118 "over it on the same point",
119 tgt
, mnt_fs_get_source(fs1
)));
126 if (!fs
&& !loopdev
&& mnt_context_is_swapmatch(cxt
)) {
128 * Maybe the option is /path/file.img, try to convert to /dev/loopN
132 if (mnt_stat_mountpoint(tgt
, &st
) == 0 && S_ISREG(st
.st_mode
)) {
134 struct libmnt_cache
*cache
= mnt_context_get_cache(cxt
);
135 const char *bf
= cache
? mnt_resolve_path(tgt
, cache
) : tgt
;
137 count
= loopdev_count_by_backing_file(bf
, &loopdev
);
139 DBG(CXT
, ul_debugobj(cxt
,
140 "umount: %s --> %s (retry)", tgt
, loopdev
));
144 } else if (count
> 1)
145 DBG(CXT
, ul_debugobj(cxt
,
146 "umount: warning: %s is associated "
147 "with more than one loopdev", tgt
));
155 DBG(CXT
, ul_debugobj(cxt
, "umount fs: %s", fs
? mnt_fs_get_target(fs
) :
163 /* Check if there is something important in the utab file. The parsed utab is
164 * stored in context->utab and deallocated by mnt_free_context().
166 * This function exists to avoid (if possible) /proc/self/mountinfo usage, so
167 * don't use things like mnt_resolve_target(), mnt_context_get_mtab() etc here.
168 * See lookup_umount_fs() for more details.
170 static int has_utab_entry(struct libmnt_context
*cxt
, const char *target
)
172 struct libmnt_cache
*cache
= NULL
;
173 struct libmnt_fs
*fs
;
174 struct libmnt_iter itr
;
181 const char *path
= mnt_get_utab_path();
183 if (!path
|| is_file_empty(path
))
185 cxt
->utab
= mnt_new_table();
188 cxt
->utab
->fmt
= MNT_FMT_UTAB
;
189 if (mnt_table_parse_file(cxt
->utab
, path
))
193 /* paths in utab are canonicalized */
194 cache
= mnt_context_get_cache(cxt
);
195 cn
= mnt_resolve_path(target
, cache
);
196 mnt_reset_iter(&itr
, MNT_ITER_BACKWARD
);
198 while (mnt_table_next_fs(cxt
->utab
, &itr
, &fs
) == 0) {
199 if (mnt_fs_streq_target(fs
, cn
)) {
211 /* this is umount replacement to mnt_context_apply_fstab(), use
212 * mnt_context_tab_applied() to check result.
214 static int lookup_umount_fs(struct libmnt_context
*cxt
)
218 struct libmnt_fs
*fs
= NULL
;
224 tgt
= mnt_fs_get_target(cxt
->fs
);
226 DBG(CXT
, ul_debugobj(cxt
, "umount: undefined target"));
231 * Let's try to avoid mountinfo usage at all to minimize performance
232 * degradation. Don't forget that kernel has to compose *whole*
233 * mountinfo about all mountpoints although we look for only one entry.
235 * All we need is fstype and to check if there is no userspace mount
236 * options for the target (e.g. helper=udisks to call /sbin/umount.udisks).
238 * So, let's use statfs() if possible (it's bad idea for --lazy/--force
239 * umounts as target is probably unreachable NFS, also for --detach-loop
240 * as this additionally needs to know the name of the loop device).
242 if (!mnt_context_is_restricted(cxt
)
244 && !(cxt
->flags
& MNT_FL_HELPER
)
245 && !mnt_context_mtab_writable(cxt
)
246 && !mnt_context_is_force(cxt
)
247 && !mnt_context_is_lazy(cxt
)
248 && !mnt_context_is_loopdel(cxt
)
249 && mnt_stat_mountpoint(tgt
, &st
) == 0 && S_ISDIR(st
.st_mode
)
250 && !has_utab_entry(cxt
, tgt
)) {
252 const char *type
= mnt_fs_get_fstype(cxt
->fs
);
254 /* !mnt_context_mtab_writable(cxt) && has_utab_entry() verified that there
255 * is no stuff in utab, so disable all mtab/utab related actions */
256 mnt_context_disable_mtab(cxt
, TRUE
);
260 if (statfs(tgt
, &vfs
) == 0)
261 type
= mnt_statfs_get_fstype(&vfs
);
263 rc
= mnt_fs_set_fstype(cxt
->fs
, type
);
269 DBG(CXT
, ul_debugobj(cxt
,
270 "umount: mountinfo unnecessary [type=%s]", type
));
275 rc
= mnt_context_find_umount_fs(cxt
, tgt
, &fs
);
279 if (rc
== 1 || !fs
) {
280 DBG(CXT
, ul_debugobj(cxt
, "umount: cannot find '%s' in mtab", tgt
));
281 return 0; /* this is correct! */
285 /* copy from mtab to our FS description
287 mnt_fs_set_source(cxt
->fs
, NULL
);
288 mnt_fs_set_target(cxt
->fs
, NULL
);
290 if (!mnt_copy_fs(cxt
->fs
, fs
)) {
291 DBG(CXT
, ul_debugobj(cxt
, "umount: failed to copy FS"));
294 DBG(CXT
, ul_debugobj(cxt
, "umount: mtab applied"));
297 cxt
->flags
|= MNT_FL_TAB_APPLIED
;
301 /* check if @devname is loopdev and if the device is associated
302 * with a source from @fstab_fs
304 static int is_associated_fs(const char *devname
, struct libmnt_fs
*fs
)
306 uintmax_t offset
= 0;
312 /* check if it begins with /dev/loop */
313 if (strncmp(devname
, _PATH_DEV_LOOP
, sizeof(_PATH_DEV_LOOP
) - 1))
316 src
= mnt_fs_get_srcpath(fs
);
320 /* check for the offset option in @fs */
321 optstr
= (char *) mnt_fs_get_user_options(fs
);
324 mnt_optstr_get_option(optstr
, "offset", &val
, &valsz
) == 0) {
325 flags
|= LOOPDEV_FL_OFFSET
;
327 if (mnt_parse_offset(val
, valsz
, &offset
) != 0)
331 return loopdev_is_used(devname
, src
, offset
, flags
);
334 static int prepare_helper_from_options(struct libmnt_context
*cxt
,
341 if (mnt_context_is_nohelpers(cxt
))
344 opts
= mnt_fs_get_user_options(cxt
->fs
);
348 if (mnt_optstr_get_option(opts
, name
, &suffix
, &valsz
))
351 suffix
= strndup(suffix
, valsz
);
355 DBG(CXT
, ul_debugobj(cxt
, "umount: umount.%s %s requested", suffix
, name
));
357 return mnt_context_prepare_helper(cxt
, "umount", suffix
);
361 * Note that cxt->fs contains relevant mtab entry!
363 static int evaluate_permissions(struct libmnt_context
*cxt
)
365 struct libmnt_table
*fstab
;
366 unsigned long u_flags
= 0;
367 const char *tgt
, *src
, *optstr
;
369 struct libmnt_fs
*fs
;
373 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
375 if (!mnt_context_is_restricted(cxt
))
376 return 0; /* superuser mount */
378 DBG(CXT
, ul_debugobj(cxt
, "umount: evaluating permissions"));
380 if (!mnt_context_tab_applied(cxt
)) {
381 DBG(CXT
, ul_debugobj(cxt
,
382 "cannot find %s in mtab and you are not root",
383 mnt_fs_get_target(cxt
->fs
)));
387 if (cxt
->user_mountflags
& MNT_MS_UHELPER
) {
388 /* on uhelper= mount option based helper */
389 rc
= prepare_helper_from_options(cxt
, "uhelper");
393 return 0; /* we'll call /sbin/umount.<uhelper> */
397 * User mounts have to be in /etc/fstab
399 rc
= mnt_context_get_fstab(cxt
, &fstab
);
403 tgt
= mnt_fs_get_target(cxt
->fs
);
404 src
= mnt_fs_get_source(cxt
->fs
);
406 if (mnt_fs_get_bindsrc(cxt
->fs
)) {
407 src
= mnt_fs_get_bindsrc(cxt
->fs
);
408 DBG(CXT
, ul_debugobj(cxt
,
409 "umount: using bind source: %s", src
));
412 /* If fstab contains the two lines
413 * /dev/sda1 /mnt/zip auto user,noauto 0 0
414 * /dev/sda4 /mnt/zip auto user,noauto 0 0
415 * then "mount /dev/sda4" followed by "umount /mnt/zip" used to fail.
416 * So, we must not look for the file, but for the pair (dev,file) in fstab.
418 fs
= mnt_table_find_pair(fstab
, src
, tgt
, MNT_ITER_FORWARD
);
421 * It's possible that there is /path/file.img in fstab and
422 * /dev/loop0 in mtab -- then we have to check the relation
423 * between loopdev and the file.
425 fs
= mnt_table_find_target(fstab
, tgt
, MNT_ITER_FORWARD
);
427 struct libmnt_cache
*cache
= mnt_context_get_cache(cxt
);
428 const char *sp
= mnt_fs_get_srcpath(cxt
->fs
); /* devname from mtab */
429 const char *dev
= sp
&& cache
? mnt_resolve_path(sp
, cache
) : sp
;
431 if (!dev
|| !is_associated_fs(dev
, fs
))
435 DBG(CXT
, ul_debugobj(cxt
,
436 "umount %s: mtab disagrees with fstab",
443 * User mounting and unmounting is allowed only if fstab contains one
444 * of the options `user', `users' or `owner' or `group'.
446 * The option `users' allows arbitrary users to mount and unmount -
447 * this may be a security risk.
449 * The options `user', `owner' and `group' only allow unmounting by the
450 * user that mounted (visible in mtab).
452 optstr
= mnt_fs_get_user_options(fs
); /* FSTAB mount options! */
456 if (mnt_optstr_get_flags(optstr
, &u_flags
,
457 mnt_get_builtin_optmap(MNT_USERSPACE_MAP
)))
460 if (u_flags
& MNT_MS_USERS
) {
461 DBG(CXT
, ul_debugobj(cxt
,
462 "umount: promiscuous setting ('users') in fstab"));
466 * Check user=<username> setting from mtab if there is a user, owner or
467 * group option in /etc/fstab
469 if (u_flags
& (MNT_MS_USER
| MNT_MS_OWNER
| MNT_MS_GROUP
)) {
471 char *curr_user
= NULL
;
472 char *mtab_user
= NULL
;
475 DBG(CXT
, ul_debugobj(cxt
,
476 "umount: checking user=<username> from mtab"));
478 curr_user
= mnt_get_username(getuid());
481 DBG(CXT
, ul_debugobj(cxt
, "umount %s: cannot "
482 "convert %d to username", tgt
, getuid()));
486 /* get options from mtab */
487 optstr
= mnt_fs_get_user_options(cxt
->fs
);
488 if (optstr
&& !mnt_optstr_get_option(optstr
,
489 "user", &mtab_user
, &sz
) && sz
)
490 ok
= !strncmp(curr_user
, mtab_user
, sz
);
496 DBG(CXT
, ul_debugobj(cxt
, "umount %s is allowed", tgt
));
500 DBG(CXT
, ul_debugobj(cxt
, "umount is not allowed for you"));
504 static int exec_helper(struct libmnt_context
*cxt
)
511 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
512 assert(cxt
->helper_exec_status
== 1);
514 if (mnt_context_is_fake(cxt
)) {
515 DBG(CXT
, ul_debugobj(cxt
, "fake mode: does not execute helper"));
516 cxt
->helper_exec_status
= rc
= 0;
525 const char *args
[10], *type
;
528 if (setgid(getgid()) < 0)
531 if (setuid(getuid()) < 0)
534 type
= mnt_fs_get_fstype(cxt
->fs
);
536 args
[i
++] = cxt
->helper
; /* 1 */
537 args
[i
++] = mnt_fs_get_target(cxt
->fs
); /* 2 */
539 if (mnt_context_is_nomtab(cxt
))
540 args
[i
++] = "-n"; /* 3 */
541 if (mnt_context_is_lazy(cxt
))
542 args
[i
++] = "-l"; /* 4 */
543 if (mnt_context_is_force(cxt
))
544 args
[i
++] = "-f"; /* 5 */
545 if (mnt_context_is_verbose(cxt
))
546 args
[i
++] = "-v"; /* 6 */
547 if (mnt_context_is_rdonly_umount(cxt
))
548 args
[i
++] = "-r"; /* 7 */
551 && !endswith(cxt
->helper
, type
)) {
552 args
[i
++] = "-t"; /* 8 */
553 args
[i
++] = (char *) type
; /* 9 */
556 args
[i
] = NULL
; /* 10 */
557 for (i
= 0; args
[i
]; i
++)
558 DBG(CXT
, ul_debugobj(cxt
, "argv[%d] = \"%s\"",
561 execv(cxt
->helper
, (char * const *) args
);
568 cxt
->helper_status
= WIFEXITED(st
) ? WEXITSTATUS(st
) : -1;
570 DBG(CXT
, ul_debugobj(cxt
, "%s executed [status=%d]",
571 cxt
->helper
, cxt
->helper_status
));
572 cxt
->helper_exec_status
= rc
= 0;
577 cxt
->helper_exec_status
= rc
= -errno
;
578 DBG(CXT
, ul_debugobj(cxt
, "fork() failed"));
586 * mnt_context_helper_setopt() backend.
588 * This function applies umount.type command line option (for example parsed
589 * by getopt() or getopt_long()) to @cxt. All unknown options are ignored and
590 * then 1 is returned.
592 * Returns: negative number on error, 1 if @c is unknown option, 0 on success.
594 int mnt_context_umount_setopt(struct libmnt_context
*cxt
, int c
, char *arg
)
599 assert(cxt
->action
== MNT_ACT_UMOUNT
);
603 rc
= mnt_context_disable_mtab(cxt
, TRUE
);
606 rc
= mnt_context_enable_lazy(cxt
, TRUE
);
609 rc
= mnt_context_enable_force(cxt
, TRUE
);
612 rc
= mnt_context_enable_verbose(cxt
, TRUE
);
615 rc
= mnt_context_enable_rdonly_umount(cxt
, TRUE
);
619 rc
= mnt_context_set_fstype(cxt
, arg
);
629 /* Check whether the kernel supports the UMOUNT_NOFOLLOW flag */
630 static int umount_nofollow_support(void)
632 int res
= umount2("", UMOUNT_UNUSED
);
633 if (res
!= -1 || errno
!= EINVAL
)
636 res
= umount2("", UMOUNT_NOFOLLOW
);
637 if (res
!= -1 || errno
!= ENOENT
)
643 static int do_umount(struct libmnt_context
*cxt
)
645 int rc
= 0, flags
= 0;
646 const char *src
, *target
;
651 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
652 assert(cxt
->syscall_status
== 1);
655 return exec_helper(cxt
);
657 src
= mnt_fs_get_srcpath(cxt
->fs
);
658 target
= mnt_fs_get_target(cxt
->fs
);
663 DBG(CXT
, ul_debugobj(cxt
, "do umount"));
665 if (cxt
->restricted
&& !mnt_context_is_fake(cxt
)) {
667 * extra paranoia for non-root users
668 * -- chdir to the parent of the mountpoint and use NOFOLLOW
669 * flag to avoid races and symlink attacks.
671 if (umount_nofollow_support())
672 flags
|= UMOUNT_NOFOLLOW
;
674 rc
= mnt_chdir_to_parent(target
, &tgtbuf
);
680 if (mnt_context_is_lazy(cxt
))
683 else if (mnt_context_is_force(cxt
))
686 DBG(CXT
, ul_debugobj(cxt
, "umount(2) [target='%s', flags=0x%08x]%s",
688 mnt_context_is_fake(cxt
) ? " (FAKE)" : ""));
690 if (mnt_context_is_fake(cxt
))
693 rc
= flags
? umount2(target
, flags
) : umount(target
);
695 cxt
->syscall_status
= -errno
;
700 * try remount read-only
703 && cxt
->syscall_status
== -EBUSY
704 && mnt_context_is_rdonly_umount(cxt
)
707 mnt_context_set_mflags(cxt
, (cxt
->mountflags
|
708 MS_REMOUNT
| MS_RDONLY
));
709 mnt_context_enable_loopdel(cxt
, FALSE
);
711 DBG(CXT
, ul_debugobj(cxt
,
712 "umount(2) failed [errno=%d] -- trying to remount read-only",
713 -cxt
->syscall_status
));
715 rc
= mount(src
, mnt_fs_get_target(cxt
->fs
), NULL
,
716 MS_MGC_VAL
| MS_REMOUNT
| MS_RDONLY
, NULL
);
718 cxt
->syscall_status
= -errno
;
719 DBG(CXT
, ul_debugobj(cxt
,
720 "read-only re-mount(2) failed [errno=%d]",
721 -cxt
->syscall_status
));
723 return -cxt
->syscall_status
;
725 cxt
->syscall_status
= 0;
726 DBG(CXT
, ul_debugobj(cxt
, "read-only re-mount(2) success"));
731 DBG(CXT
, ul_debugobj(cxt
, "umount(2) failed [errno=%d]",
732 -cxt
->syscall_status
));
733 return -cxt
->syscall_status
;
736 cxt
->syscall_status
= 0;
737 DBG(CXT
, ul_debugobj(cxt
, "umount(2) success"));
742 * mnt_context_prepare_umount:
743 * @cxt: mount context
745 * Prepare context for umounting, unnecessary for mnt_context_umount().
747 * Returns: 0 on success, and negative number in case of error.
749 int mnt_context_prepare_umount(struct libmnt_context
*cxt
)
753 if (!cxt
|| !cxt
->fs
|| mnt_fs_is_swaparea(cxt
->fs
))
755 if (!mnt_context_get_source(cxt
) && !mnt_context_get_target(cxt
))
757 if (cxt
->flags
& MNT_FL_PREPARED
)
760 assert(cxt
->helper_exec_status
== 1);
761 assert(cxt
->syscall_status
== 1);
763 free(cxt
->helper
); /* be paranoid */
765 cxt
->action
= MNT_ACT_UMOUNT
;
767 rc
= lookup_umount_fs(cxt
);
769 rc
= mnt_context_merge_mflags(cxt
);
771 rc
= evaluate_permissions(cxt
);
773 if (!rc
&& !cxt
->helper
) {
775 if (cxt
->user_mountflags
& MNT_MS_HELPER
)
776 /* on helper= mount option based helper */
777 rc
= prepare_helper_from_options(cxt
, "helper");
779 if (!rc
&& !cxt
->helper
)
780 /* on fstype based helper */
781 rc
= mnt_context_prepare_helper(cxt
, "umount", NULL
);
784 if (!rc
&& (cxt
->user_mountflags
& MNT_MS_LOOP
))
785 /* loop option explicitly specified in mtab, detach this loop */
786 mnt_context_enable_loopdel(cxt
, TRUE
);
788 if (!rc
&& mnt_context_is_loopdel(cxt
) && cxt
->fs
) {
789 const char *src
= mnt_fs_get_srcpath(cxt
->fs
);
791 if (src
&& (!is_loopdev(src
) || loopdev_is_autoclear(src
)))
792 mnt_context_enable_loopdel(cxt
, FALSE
);
796 DBG(CXT
, ul_debugobj(cxt
, "umount: preparing failed"));
799 cxt
->flags
|= MNT_FL_PREPARED
;
804 * mnt_context_do_umount:
805 * @cxt: mount context
807 * Umount filesystem by umount(2) or fork()+exec(/sbin/umount.type).
808 * Unnecessary for mnt_context_umount().
810 * See also mnt_context_disable_helpers().
812 * WARNING: non-zero return code does not mean that umount(2) syscall or
813 * umount.type helper wasn't successfully called.
815 * Check mnt_context_get_status() after error!
817 * Returns: 0 on success;
818 * >0 in case of umount(2) error (returns syscall errno),
819 * <0 in case of other errors.
821 int mnt_context_do_umount(struct libmnt_context
*cxt
)
827 assert(cxt
->helper_exec_status
== 1);
828 assert(cxt
->syscall_status
== 1);
829 assert((cxt
->flags
& MNT_FL_PREPARED
));
830 assert((cxt
->action
== MNT_ACT_UMOUNT
));
831 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
837 if (mnt_context_get_status(cxt
) && !mnt_context_is_fake(cxt
)) {
839 * Umounted, do some post-umount operations
841 * - refresh in-memory mtab stuff if remount rather than
842 * umount has been performed
844 if (mnt_context_is_loopdel(cxt
)
845 && !(cxt
->mountflags
& MS_REMOUNT
))
846 rc
= mnt_context_delete_loopdev(cxt
);
848 if (!mnt_context_is_nomtab(cxt
)
849 && mnt_context_get_status(cxt
)
851 && mnt_context_is_rdonly_umount(cxt
)
852 && (cxt
->mountflags
& MS_REMOUNT
)) {
854 /* use "remount" instead of "umount" in /etc/mtab */
855 if (!rc
&& cxt
->update
&& mnt_context_mtab_writable(cxt
))
856 rc
= mnt_update_set_fs(cxt
->update
,
857 cxt
->mountflags
, NULL
, cxt
->fs
);
864 * mnt_context_finalize_umount:
867 * Mtab update, etc. Unnecessary for mnt_context_umount(), but should be called
868 * after mnt_context_do_umount(). See also mnt_context_set_syscall_status().
870 * Returns: negative number on error, 0 on success.
872 int mnt_context_finalize_umount(struct libmnt_context
*cxt
)
878 assert((cxt
->flags
& MNT_FL_PREPARED
));
879 assert((cxt
->flags
& MNT_FL_MOUNTFLAGS_MERGED
));
881 rc
= mnt_context_prepare_update(cxt
);
883 rc
= mnt_context_update_tabs(cxt
);;
889 * mnt_context_umount:
890 * @cxt: umount context
892 * High-level, umounts filesystem by umount(2) or fork()+exec(/sbin/umount.type).
894 * This is similar to:
896 * mnt_context_prepare_umount(cxt);
897 * mnt_context_do_umount(cxt);
898 * mnt_context_finalize_umount(cxt);
900 * See also mnt_context_disable_helpers().
902 * WARNING: non-zero return code does not mean that umount(2) syscall or
903 * umount.type helper wasn't successfully called.
905 * Check mnt_context_get_status() after error!
907 * Returns: 0 on success;
908 * >0 in case of umount(2) error (returns syscall errno),
909 * <0 in case of other errors.
911 int mnt_context_umount(struct libmnt_context
*cxt
)
917 assert(cxt
->helper_exec_status
== 1);
918 assert(cxt
->syscall_status
== 1);
920 DBG(CXT
, ul_debugobj(cxt
, "umount: %s", mnt_context_get_target(cxt
)));
922 rc
= mnt_context_prepare_umount(cxt
);
924 rc
= mnt_context_prepare_update(cxt
);
926 rc
= mnt_context_do_umount(cxt
);
928 rc
= mnt_context_update_tabs(cxt
);
934 * mnt_context_next_umount:
937 * @fs: returns the current filesystem
938 * @mntrc: returns the return code from mnt_context_umount()
939 * @ignored: returns 1 for not matching
941 * This function tries to umount the next filesystem from mtab (as returned by
942 * mnt_context_get_mtab()).
944 * You can filter out filesystems by:
945 * mnt_context_set_options_pattern() to simulate umount -a -O pattern
946 * mnt_context_set_fstype_pattern() to simulate umount -a -t pattern
948 * If the filesystem is not mounted or does not match the defined criteria,
949 * then the function mnt_context_next_umount() returns zero, but the @ignored is
950 * non-zero. Note that the root filesystem is always ignored.
952 * If umount(2) syscall or umount.type helper failed, then the
953 * mnt_context_next_umount() function returns zero, but the @mntrc is non-zero.
954 * Use also mnt_context_get_status() to check if the filesystem was
955 * successfully umounted.
957 * Returns: 0 on success,
958 * <0 in case of error (!= umount(2) errors)
959 * 1 at the end of the list.
961 int mnt_context_next_umount(struct libmnt_context
*cxt
,
962 struct libmnt_iter
*itr
,
963 struct libmnt_fs
**fs
,
967 struct libmnt_table
*mtab
;
976 if (!cxt
|| !fs
|| !itr
)
979 rc
= mnt_context_get_mtab(cxt
, &mtab
);
980 cxt
->mtab
= NULL
; /* do not reset mtab */
981 mnt_reset_context(cxt
);
988 rc
= mnt_table_next_fs(mtab
, itr
, fs
);
990 return rc
; /* no more filesystems (or error) */
992 tgt
= mnt_fs_get_target(*fs
);
995 DBG(CXT
, ul_debugobj(cxt
, "next-umount: trying %s [fstype: %s, t-pattern: %s, options: %s, O-pattern: %s]", tgt
,
996 mnt_fs_get_fstype(*fs
), cxt
->fstype_pattern
, mnt_fs_get_options(*fs
), cxt
->optstr_pattern
));
998 /* ignore filesystems which don't match options patterns */
999 if ((cxt
->fstype_pattern
&& !mnt_fs_match_fstype(*fs
,
1000 cxt
->fstype_pattern
)) ||
1002 /* ignore filesystems which don't match type patterns */
1003 (cxt
->optstr_pattern
&& !mnt_fs_match_options(*fs
,
1004 cxt
->optstr_pattern
))) {
1008 DBG(CXT
, ul_debugobj(cxt
, "next-umount: not-match"));
1012 rc
= mnt_context_set_fs(cxt
, *fs
);
1015 rc
= mnt_context_umount(cxt
);