/** * mnt_context_prepare_umount: * @cxt: mount context * * Prepare context for umounting, unnecessary for mnt_context_umount(). * * Returns: 0 on success, and negative number in case of error. */ int mnt_context_prepare_umount(struct libmnt_context *cxt) { int rc; assert(cxt); assert(cxt->fs); assert(cxt->helper_exec_status == 1); assert(cxt->syscall_status == 1); if (!cxt || !cxt->fs || mnt_fs_is_swaparea(cxt->fs)) return -EINVAL; if (!mnt_context_get_source(cxt) && !mnt_context_get_target(cxt)) return -EINVAL; if (cxt->flags & MNT_FL_PREPARED) return 0; free(cxt->helper); /* be paranoid */ cxt->helper = NULL; cxt->action = MNT_ACT_UMOUNT; rc = lookup_umount_fs(cxt); if (!rc) rc = mnt_context_merge_mflags(cxt); if (!rc) rc = evaluate_permissions(cxt); if (!rc && !cxt->helper) { if (cxt->user_mountflags & MNT_MS_HELPER) /* on helper= mount option based helper */ rc = prepare_helper_from_options(cxt, "helper"); if (!rc && !cxt->helper) /* on fstype based helper */ rc = mnt_context_prepare_helper(cxt, "umount", NULL); } if (!rc && (cxt->flags & MNT_FL_LOOPDEL) && cxt->fs) { const char *src = mnt_fs_get_srcpath(cxt->fs); if (src && (!is_loopdev(src) || loopdev_is_autoclear(src))) cxt->flags &= ~MNT_FL_LOOPDEL; } if (rc) { DBG(CXT, mnt_debug_h(cxt, "umount: preparing failed")); return rc; } cxt->flags |= MNT_FL_PREPARED; return rc; }
/** * mnt_context_prepare_mount: * @cxt: context * * Prepare context for mounting, unnecessary for mnt_context_mount(). * * Returns: negative number on error, zero on success */ int mnt_context_prepare_mount(struct libmnt_context *cxt) { int rc = -EINVAL; assert(cxt); assert(cxt->fs); assert(cxt->helper_exec_status == 1); assert(cxt->syscall_status == 1); if (!cxt || !cxt->fs || mnt_fs_is_swaparea(cxt->fs)) return -EINVAL; if (!mnt_fs_get_source(cxt->fs) && !mnt_fs_get_target(cxt->fs)) return -EINVAL; if (cxt->flags & MNT_FL_PREPARED) return 0; cxt->action = MNT_ACT_MOUNT; DBG(CXT, mnt_debug_h(cxt, "mount: preparing")); /* TODO: fstab is unnecessary for MS_{MOVE,BIND,STARED,...} */ rc = mnt_context_apply_fstab(cxt); if (!rc) rc = mnt_context_merge_mflags(cxt); if (!rc) rc = evaluate_permissions(cxt); if (!rc) rc = fix_optstr(cxt); if (!rc) rc = mnt_context_prepare_srcpath(cxt); if (!rc) rc = mnt_context_prepare_target(cxt); if (!rc) rc = mnt_context_guess_fstype(cxt); if (!rc) rc = mnt_context_prepare_helper(cxt, "mount", NULL); if (rc) { DBG(CXT, mnt_debug_h(cxt, "mount: preparing failed")); return rc; } cxt->flags |= MNT_FL_PREPARED; return rc; }
/** * mnt_resolve_target: * @path: "native" path, a potential mount point * @cache: cache for results or NULL. * * Like mnt_resolve_path(), unless @cache is not NULL and * mnt_cache_set_targets(cache, mtab) was called: if @path is found in the * cached @mtab and the matching entry was provided by the kernel, assume that * @path is already canonicalized. By avoiding a call to realpath(2) on * known mount points, there is a lower risk of stepping on a stale mount * point, which can result in an application freeze. This is also faster in * general, as stat(2) on a mount point is slower than on a regular file. * * Returns: absolute path or NULL in case of error. The result has to be * deallocated by free() if @cache is NULL. */ char *mnt_resolve_target(const char *path, struct libmnt_cache *cache) { char *p = NULL; /*DBG(CACHE, ul_debugobj(cache, "resolving target %s", path));*/ if (!cache || !cache->mtab) return mnt_resolve_path(path, cache); p = (char *) cache_find_path(cache, path); if (p) return p; else { struct libmnt_iter itr; struct libmnt_fs *fs = NULL; mnt_reset_iter(&itr, MNT_ITER_BACKWARD); while (mnt_table_next_fs(cache->mtab, &itr, &fs) == 0) { if (!mnt_fs_is_kernel(fs) || mnt_fs_is_swaparea(fs) || !mnt_fs_streq_target(fs, path)) continue; p = strdup(path); if (!p) return NULL; /* ENOMEM */ if (cache_add_entry(cache, p, p, MNT_CACHE_ISPATH)) { free(p); return NULL; /* ENOMEM */ } break; } } if (!p) p = canonicalize_path_and_cache(path, cache); return p; }
/** * mnt_context_next_mount: * @cxt: context * @itr: iterator * @fs: returns the current filesystem * @mntrc: returns the return code from mnt_context_mount() * @ignored: returns 1 for not matching and 2 for already mounted filesystems * * This function tries to mount the next filesystem from fstab (as returned by * mnt_context_get_fstab()). See also mnt_context_set_fstab(). * * You can filter out filesystems by: * mnt_context_set_options_pattern() to simulate mount -a -O pattern * mnt_context_set_fstype_pattern() to simulate mount -a -t pattern * * If the filesystem is already mounted or does not match defined criteria, * then the mnt_context_next_mount() function returns zero, but the @ignored is * non-zero. Note that the root filesystem and filesystems with "noauto" option * are always ignored. * * If mount(2) syscall or mount.type helper failed, then the * mnt_context_next_mount() function returns zero, but the @mntrc is non-zero. * Use also mnt_context_get_status() to check if the filesystem was * successfully mounted. * * Returns: 0 on success, * <0 in case of error (!= mount(2) errors) * 1 at the end of the list. */ int mnt_context_next_mount(struct libmnt_context *cxt, struct libmnt_iter *itr, struct libmnt_fs **fs, int *mntrc, int *ignored) { struct libmnt_table *fstab, *mtab; const char *o, *tgt; int rc, mounted = 0; if (ignored) *ignored = 0; if (mntrc) *mntrc = 0; if (!cxt || !fs || !itr) return -EINVAL; mtab = cxt->mtab; cxt->mtab = NULL; /* do not reset mtab */ mnt_reset_context(cxt); cxt->mtab = mtab; rc = mnt_context_get_fstab(cxt, &fstab); if (rc) return rc; rc = mnt_table_next_fs(fstab, itr, fs); if (rc != 0) return rc; /* more filesystems (or error) */ o = mnt_fs_get_user_options(*fs); tgt = mnt_fs_get_target(*fs); DBG(CXT, mnt_debug_h(cxt, "next-mount: trying %s", tgt)); /* ignore swap */ if (mnt_fs_is_swaparea(*fs) || /* ignore root filesystem */ (tgt && (strcmp(tgt, "/") == 0 || strcmp(tgt, "root") == 0)) || /* ignore noauto filesystems */ (o && mnt_optstr_get_option(o, "noauto", NULL, NULL) == 0) || /* ignore filesystems not match with options patterns */ (cxt->fstype_pattern && !mnt_fs_match_fstype(*fs, cxt->fstype_pattern)) || /* ignore filesystems not match with type patterns */ (cxt->optstr_pattern && !mnt_fs_match_options(*fs, cxt->optstr_pattern))) { if (ignored) *ignored = 1; DBG(CXT, mnt_debug_h(cxt, "next-mount: not-match " "[fstype: %s, t-pattern: %s, options: %s, O-pattern: %s]", mnt_fs_get_fstype(*fs), cxt->fstype_pattern, mnt_fs_get_options(*fs), cxt->optstr_pattern)); return 0; } /* ignore already mounted filesystems */ rc = mnt_context_is_fs_mounted(cxt, *fs, &mounted); if (rc) return rc; if (mounted) { if (ignored) *ignored = 2; return 0; } if (mnt_context_is_fork(cxt)) { rc = mnt_fork_context(cxt); if (rc) return rc; /* fork error */ if (mnt_context_is_parent(cxt)) { return 0; /* parent */ } } /* child or non-forked */ rc = mnt_context_set_fs(cxt, *fs); if (!rc) { rc = mnt_context_mount(cxt); if (mntrc) *mntrc = rc; } if (mnt_context_is_child(cxt)) { DBG(CXT, mnt_debug_h(cxt, "next-mount: child exit [rc=%d]", rc)); DBG_FLUSH; exit(rc); } return 0; }