| /* |
| * Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com> |
| * |
| * This file may be redistributed under the terms of the |
| * GNU Lesser General Public License. |
| */ |
| |
| /** |
| * SECTION: fs |
| * @title: Filesystem |
| * @short_description: represents one entry from fstab, mtab, or mountinfo file |
| * |
| */ |
| #include <ctype.h> |
| #include <blkid.h> |
| #include <stddef.h> |
| |
| #include "mountP.h" |
| #include "strutils.h" |
| |
| /** |
| * mnt_new_fs: |
| * |
| * The initial refcount is 1, and needs to be decremented to |
| * release the resources of the filesystem. |
| * |
| * Returns: newly allocated struct libmnt_fs. |
| */ |
| struct libmnt_fs *mnt_new_fs(void) |
| { |
| struct libmnt_fs *fs = calloc(1, sizeof(*fs)); |
| if (!fs) |
| return NULL; |
| |
| fs->refcount = 1; |
| INIT_LIST_HEAD(&fs->ents); |
| /*DBG(FS, ul_debugobj(fs, "alloc"));*/ |
| return fs; |
| } |
| |
| /** |
| * mnt_free_fs: |
| * @fs: fs pointer |
| * |
| * Deallocates the fs. This function does not care about reference count. Don't |
| * use this function directly -- it's better to use mnt_unref_fs(). |
| * |
| * The reference counting is supported since util-linux v2.24. |
| */ |
| void mnt_free_fs(struct libmnt_fs *fs) |
| { |
| if (!fs) |
| return; |
| |
| DBG(FS, ul_debugobj(fs, "free [refcount=%d]", fs->refcount)); |
| |
| mnt_reset_fs(fs); |
| free(fs); |
| } |
| |
| /** |
| * mnt_reset_fs: |
| * @fs: fs pointer |
| * |
| * Resets (zeroize) @fs. |
| */ |
| void mnt_reset_fs(struct libmnt_fs *fs) |
| { |
| int ref; |
| |
| if (!fs) |
| return; |
| |
| ref = fs->refcount; |
| |
| list_del(&fs->ents); |
| free(fs->source); |
| free(fs->bindsrc); |
| free(fs->tagname); |
| free(fs->tagval); |
| free(fs->root); |
| free(fs->swaptype); |
| free(fs->target); |
| free(fs->fstype); |
| free(fs->optstr); |
| free(fs->vfs_optstr); |
| free(fs->fs_optstr); |
| free(fs->user_optstr); |
| free(fs->attrs); |
| free(fs->opt_fields); |
| free(fs->comment); |
| |
| memset(fs, 0, sizeof(*fs)); |
| INIT_LIST_HEAD(&fs->ents); |
| fs->refcount = ref; |
| } |
| |
| /** |
| * mnt_ref_fs: |
| * @fs: fs pointer |
| * |
| * Increments reference counter. |
| */ |
| void mnt_ref_fs(struct libmnt_fs *fs) |
| { |
| if (fs) { |
| fs->refcount++; |
| /*DBG(FS, ul_debugobj(fs, "ref=%d", fs->refcount));*/ |
| } |
| } |
| |
| /** |
| * mnt_unref_fs: |
| * @fs: fs pointer |
| * |
| * De-increments reference counter, on zero the @fs is automatically |
| * deallocated by mnt_free_fs(). |
| */ |
| void mnt_unref_fs(struct libmnt_fs *fs) |
| { |
| if (fs) { |
| fs->refcount--; |
| /*DBG(FS, ul_debugobj(fs, "unref=%d", fs->refcount));*/ |
| if (fs->refcount <= 0) |
| mnt_free_fs(fs); |
| } |
| } |
| |
| static inline int update_str(char **dest, const char *src) |
| { |
| size_t sz; |
| char *x; |
| |
| assert(dest); |
| |
| if (!src) { |
| free(*dest); |
| *dest = NULL; |
| return 0; /* source (old) is empty */ |
| } |
| |
| sz = strlen(src) + 1; |
| x = realloc(*dest, sz); |
| if (!x) |
| return -ENOMEM; |
| *dest = x; |
| memcpy(*dest, src, sz); |
| return 0; |
| } |
| |
| static inline int cpy_str_at_offset(void *new, const void *old, size_t offset) |
| { |
| char **o = (char **) ((char *) old + offset); |
| char **n = (char **) ((char *) new + offset); |
| |
| if (*n) |
| return 0; /* already set, don't overwrite */ |
| |
| return update_str(n, *o); |
| } |
| |
| /** |
| * mnt_copy_fs: |
| * @dest: destination FS |
| * @src: source FS |
| * |
| * If @dest is NULL, then a new FS is allocated, if any @dest field is already |
| * set, then the field is NOT overwritten. |
| * |
| * This function does not copy userdata (se mnt_fs_set_userdata()). A new copy is |
| * not linked with any existing mnt_tab. |
| * |
| * Returns: @dest or NULL in case of error |
| */ |
| struct libmnt_fs *mnt_copy_fs(struct libmnt_fs *dest, |
| const struct libmnt_fs *src) |
| { |
| const struct libmnt_fs *org = dest; |
| |
| if (!src) |
| return NULL; |
| if (!dest) { |
| dest = mnt_new_fs(); |
| if (!dest) |
| return NULL; |
| } |
| |
| dest->id = src->id; |
| dest->parent = src->parent; |
| dest->devno = src->devno; |
| dest->tid = src->tid; |
| |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, source))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagname))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, tagval))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, root))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, swaptype))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, target))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fstype))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, optstr))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, vfs_optstr))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, fs_optstr))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, user_optstr))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, attrs))) |
| goto err; |
| if (cpy_str_at_offset(dest, src, offsetof(struct libmnt_fs, bindsrc))) |
| goto err; |
| |
| dest->freq = src->freq; |
| dest->passno = src->passno; |
| dest->flags = src->flags; |
| dest->size = src->size; |
| dest->usedsize = src->usedsize; |
| dest->priority = src->priority; |
| |
| return dest; |
| err: |
| if (!org) |
| mnt_free_fs(dest); |
| return NULL; |
| } |
| |
| /* |
| * This function copies all @fs description except information that does not |
| * belong to /etc/mtab (e.g. VFS and userspace mount options with MNT_NOMTAB |
| * mask). |
| * |
| * Returns: copy of @fs. |
| */ |
| struct libmnt_fs *mnt_copy_mtab_fs(const struct libmnt_fs *fs) |
| { |
| struct libmnt_fs *n = mnt_new_fs(); |
| |
| assert(fs); |
| if (!n) |
| return NULL; |
| |
| if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, source))) |
| goto err; |
| if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, target))) |
| goto err; |
| if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, fstype))) |
| goto err; |
| |
| if (fs->vfs_optstr) { |
| char *p = NULL; |
| mnt_optstr_get_options(fs->vfs_optstr, &p, |
| mnt_get_builtin_optmap(MNT_LINUX_MAP), |
| MNT_NOMTAB); |
| n->vfs_optstr = p; |
| } |
| |
| if (fs->user_optstr) { |
| char *p = NULL; |
| mnt_optstr_get_options(fs->user_optstr, &p, |
| mnt_get_builtin_optmap(MNT_USERSPACE_MAP), |
| MNT_NOMTAB); |
| n->user_optstr = p; |
| } |
| |
| if (cpy_str_at_offset(n, fs, offsetof(struct libmnt_fs, fs_optstr))) |
| goto err; |
| |
| /* we cannot copy original optstr, the new optstr has to be without |
| * non-mtab options -- so, let's generate a new string */ |
| n->optstr = mnt_fs_strdup_options(n); |
| |
| n->freq = fs->freq; |
| n->passno = fs->passno; |
| n->flags = fs->flags; |
| |
| return n; |
| err: |
| mnt_free_fs(n); |
| return NULL; |
| |
| } |
| |
| /** |
| * mnt_fs_get_userdata: |
| * @fs: struct libmnt_file instance |
| * |
| * Returns: private data set by mnt_fs_set_userdata() or NULL. |
| */ |
| void *mnt_fs_get_userdata(struct libmnt_fs *fs) |
| { |
| if (!fs) |
| return NULL; |
| return fs->userdata; |
| } |
| |
| /** |
| * mnt_fs_set_userdata: |
| * @fs: struct libmnt_file instance |
| * @data: user data |
| * |
| * The "userdata" are library independent data. |
| * |
| * Returns: 0 or negative number in case of error (if @fs is NULL). |
| */ |
| int mnt_fs_set_userdata(struct libmnt_fs *fs, void *data) |
| { |
| if (!fs) |
| return -EINVAL; |
| fs->userdata = data; |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_get_srcpath: |
| * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs |
| * |
| * The mount "source path" is: |
| * - a directory for 'bind' mounts (in fstab or mtab only) |
| * - a device name for standard mounts |
| * |
| * See also mnt_fs_get_tag() and mnt_fs_get_source(). |
| * |
| * Returns: mount source path or NULL in case of error or when the path |
| * is not defined. |
| */ |
| const char *mnt_fs_get_srcpath(struct libmnt_fs *fs) |
| { |
| if (!fs) |
| return NULL; |
| |
| /* fstab-like fs */ |
| if (fs->tagname) |
| return NULL; /* the source contains a "NAME=value" */ |
| return fs->source; |
| } |
| |
| /** |
| * mnt_fs_get_source: |
| * @fs: struct libmnt_file (fstab/mtab/mountinfo) fs |
| * |
| * Returns: mount source. Note that the source could be unparsed TAG |
| * (LABEL/UUID). See also mnt_fs_get_srcpath() and mnt_fs_get_tag(). |
| */ |
| const char *mnt_fs_get_source(struct libmnt_fs *fs) |
| { |
| return fs ? fs->source : NULL; |
| } |
| |
| /* |
| * Used by the parser ONLY (@source has to be freed on error) |
| */ |
| int __mnt_fs_set_source_ptr(struct libmnt_fs *fs, char *source) |
| { |
| char *t = NULL, *v = NULL; |
| |
| assert(fs); |
| |
| if (source && blkid_parse_tag_string(source, &t, &v) == 0 && |
| !mnt_valid_tagname(t)) { |
| /* parsable but unknown tag -- ignore */ |
| free(t); |
| free(v); |
| t = v = NULL; |
| } |
| |
| if (fs->source != source) |
| free(fs->source); |
| |
| free(fs->tagname); |
| free(fs->tagval); |
| |
| fs->source = source; |
| fs->tagname = t; |
| fs->tagval = v; |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_set_source: |
| * @fs: fstab/mtab/mountinfo entry |
| * @source: new source |
| * |
| * This function creates a private copy (strdup()) of @source. |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_source(struct libmnt_fs *fs, const char *source) |
| { |
| char *p = NULL; |
| int rc; |
| |
| if (!fs) |
| return -EINVAL; |
| |
| if (source) { |
| p = strdup(source); |
| if (!p) |
| return -ENOMEM; |
| } |
| |
| rc = __mnt_fs_set_source_ptr(fs, p); |
| if (rc) |
| free(p); |
| return rc; |
| } |
| |
| /** |
| * mnt_fs_streq_srcpath: |
| * @fs: fs |
| * @path: source path |
| * |
| * Compares @fs source path with @path. The redundant slashes are ignored. |
| * This function compares strings and does not canonicalize the paths. |
| * See also more heavy and generic mnt_fs_match_source(). |
| * |
| * Returns: 1 if @fs source path equal to @path, otherwise 0. |
| */ |
| int mnt_fs_streq_srcpath(struct libmnt_fs *fs, const char *path) |
| { |
| const char *p; |
| |
| if (!fs) |
| return 0; |
| |
| p = mnt_fs_get_srcpath(fs); |
| |
| if (!mnt_fs_is_pseudofs(fs)) |
| return streq_paths(p, path); |
| |
| if (!p && !path) |
| return 1; |
| |
| return p && path && strcmp(p, path) == 0; |
| } |
| |
| /** |
| * mnt_fs_streq_target: |
| * @fs: fs |
| * @path: mount point |
| * |
| * Compares @fs target path with @path. The redundant slashes are ignored. |
| * This function compares strings and does not canonicalize the paths. |
| * See also more generic mnt_fs_match_target(). |
| * |
| * Returns: 1 if @fs target path equal to @path, otherwise 0. |
| */ |
| int mnt_fs_streq_target(struct libmnt_fs *fs, const char *path) |
| { |
| return fs && streq_paths(mnt_fs_get_target(fs), path); |
| } |
| |
| /** |
| * mnt_fs_get_tag: |
| * @fs: fs |
| * @name: returns pointer to NAME string |
| * @value: returns pointer to VALUE string |
| * |
| * "TAG" is NAME=VALUE (e.g. LABEL=foo) |
| * |
| * The TAG is the first column in the fstab file. The TAG or "srcpath" always has |
| * to be set for all entries. |
| * |
| * See also mnt_fs_get_source(). |
| * |
| * <informalexample> |
| * <programlisting> |
| * char *src; |
| * struct libmnt_fs *fs = mnt_table_find_target(tb, "/home", MNT_ITER_FORWARD); |
| * |
| * if (!fs) |
| * goto err; |
| * |
| * src = mnt_fs_get_srcpath(fs); |
| * if (!src) { |
| * char *tag, *val; |
| * if (mnt_fs_get_tag(fs, &tag, &val) == 0) |
| * printf("%s: %s\n", tag, val); // LABEL or UUID |
| * } else |
| * printf("device: %s\n", src); // device or bind path |
| * </programlisting> |
| * </informalexample> |
| * |
| * Returns: 0 on success or negative number in case a TAG is not defined. |
| */ |
| int mnt_fs_get_tag(struct libmnt_fs *fs, const char **name, const char **value) |
| { |
| if (fs == NULL || !fs->tagname) |
| return -EINVAL; |
| if (name) |
| *name = fs->tagname; |
| if (value) |
| *value = fs->tagval; |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_get_target: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * |
| * Returns: pointer to mountpoint path or NULL |
| */ |
| const char *mnt_fs_get_target(struct libmnt_fs *fs) |
| { |
| return fs ? fs->target : NULL; |
| } |
| |
| /** |
| * mnt_fs_set_target: |
| * @fs: fstab/mtab/mountinfo entry |
| * @tgt: mountpoint |
| * |
| * This function creates a private copy (strdup()) of @tgt. |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_target(struct libmnt_fs *fs, const char *tgt) |
| { |
| return strdup_to_struct_member(fs, target, tgt); |
| } |
| |
| static int mnt_fs_get_flags(struct libmnt_fs *fs) |
| { |
| return fs ? fs->flags : 0; |
| } |
| |
| /** |
| * mnt_fs_get_propagation: |
| * @fs: mountinfo entry |
| * @flags: returns propagation MS_* flags as present in the mountinfo file |
| * |
| * Note that this function sets @flags to zero if no propagation flags are found |
| * in the mountinfo file. The kernel default is MS_PRIVATE, this flag is not stored |
| * in the mountinfo file. |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_get_propagation(struct libmnt_fs *fs, unsigned long *flags) |
| { |
| if (!fs || !flags) |
| return -EINVAL; |
| |
| *flags = 0; |
| |
| if (!fs->opt_fields) |
| return 0; |
| |
| /* |
| * The optional fields format is incompatible with mount options |
| * ... we have to parse the field here. |
| */ |
| *flags |= strstr(fs->opt_fields, "shared:") ? MS_SHARED : MS_PRIVATE; |
| |
| if (strstr(fs->opt_fields, "master:")) |
| *flags |= MS_SLAVE; |
| if (strstr(fs->opt_fields, "unbindable")) |
| *flags |= MS_UNBINDABLE; |
| |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_is_kernel: |
| * @fs: filesystem |
| * |
| * Returns: 1 if the filesystem description is read from kernel e.g. /proc/mounts. |
| */ |
| int mnt_fs_is_kernel(struct libmnt_fs *fs) |
| { |
| return mnt_fs_get_flags(fs) & MNT_FS_KERNEL; |
| } |
| |
| /** |
| * mnt_fs_is_swaparea: |
| * @fs: filesystem |
| * |
| * Returns: 1 if the filesystem uses "swap" as a type |
| */ |
| int mnt_fs_is_swaparea(struct libmnt_fs *fs) |
| { |
| return mnt_fs_get_flags(fs) & MNT_FS_SWAP; |
| } |
| |
| /** |
| * mnt_fs_is_pseudofs: |
| * @fs: filesystem |
| * |
| * Returns: 1 if the filesystem is a pseudo fs type (proc, cgroups) |
| */ |
| int mnt_fs_is_pseudofs(struct libmnt_fs *fs) |
| { |
| return mnt_fs_get_flags(fs) & MNT_FS_PSEUDO; |
| } |
| |
| /** |
| * mnt_fs_is_netfs: |
| * @fs: filesystem |
| * |
| * Returns: 1 if the filesystem is a network filesystem |
| */ |
| int mnt_fs_is_netfs(struct libmnt_fs *fs) |
| { |
| return mnt_fs_get_flags(fs) & MNT_FS_NET; |
| } |
| |
| /** |
| * mnt_fs_get_fstype: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * |
| * Returns: pointer to filesystem type. |
| */ |
| const char *mnt_fs_get_fstype(struct libmnt_fs *fs) |
| { |
| return fs ? fs->fstype : NULL; |
| } |
| |
| /* Used by the struct libmnt_file parser only */ |
| int __mnt_fs_set_fstype_ptr(struct libmnt_fs *fs, char *fstype) |
| { |
| assert(fs); |
| |
| if (fstype != fs->fstype) |
| free(fs->fstype); |
| |
| fs->fstype = fstype; |
| fs->flags &= ~MNT_FS_PSEUDO; |
| fs->flags &= ~MNT_FS_NET; |
| fs->flags &= ~MNT_FS_SWAP; |
| |
| /* save info about pseudo filesystems */ |
| if (fs->fstype) { |
| if (mnt_fstype_is_pseudofs(fs->fstype)) |
| fs->flags |= MNT_FS_PSEUDO; |
| else if (mnt_fstype_is_netfs(fs->fstype)) |
| fs->flags |= MNT_FS_NET; |
| else if (!strcmp(fs->fstype, "swap")) |
| fs->flags |= MNT_FS_SWAP; |
| } |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_set_fstype: |
| * @fs: fstab/mtab/mountinfo entry |
| * @fstype: filesystem type |
| * |
| * This function creates a private copy (strdup()) of @fstype. |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_fstype(struct libmnt_fs *fs, const char *fstype) |
| { |
| char *p = NULL; |
| |
| if (!fs) |
| return -EINVAL; |
| if (fstype) { |
| p = strdup(fstype); |
| if (!p) |
| return -ENOMEM; |
| } |
| return __mnt_fs_set_fstype_ptr(fs, p); |
| } |
| |
| /* |
| * Merges @vfs and @fs options strings into a new string. |
| * This function cares about 'ro/rw' options. The 'ro' is |
| * always used if @vfs or @fs is read-only. |
| * For example: |
| * |
| * mnt_merge_optstr("rw,noexec", "ro,journal=update") |
| * |
| * returns: "ro,noexec,journal=update" |
| * |
| * mnt_merge_optstr("rw,noexec", "rw,journal=update") |
| * |
| * returns: "rw,noexec,journal=update" |
| */ |
| static char *merge_optstr(const char *vfs, const char *fs) |
| { |
| char *res, *p; |
| size_t sz; |
| int ro = 0, rw = 0; |
| |
| if (!vfs && !fs) |
| return NULL; |
| if (!vfs || !fs) |
| return strdup(fs ? fs : vfs); |
| if (!strcmp(vfs, fs)) |
| return strdup(vfs); /* e.g. "aaa" and "aaa" */ |
| |
| /* leave space for the leading "r[ow],", "," and the trailing zero */ |
| sz = strlen(vfs) + strlen(fs) + 5; |
| res = malloc(sz); |
| if (!res) |
| return NULL; |
| p = res + 3; /* make a room for rw/ro flag */ |
| |
| snprintf(p, sz - 3, "%s,%s", vfs, fs); |
| |
| /* remove 'rw' flags */ |
| rw += !mnt_optstr_remove_option(&p, "rw"); /* from vfs */ |
| rw += !mnt_optstr_remove_option(&p, "rw"); /* from fs */ |
| |
| /* remove 'ro' flags if necessary */ |
| if (rw != 2) { |
| ro += !mnt_optstr_remove_option(&p, "ro"); |
| if (ro + rw < 2) |
| ro += !mnt_optstr_remove_option(&p, "ro"); |
| } |
| |
| if (!strlen(p)) |
| memcpy(res, ro ? "ro" : "rw", 3); |
| else |
| memcpy(res, ro ? "ro," : "rw,", 3); |
| return res; |
| } |
| |
| /** |
| * mnt_fs_strdup_options: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * |
| * Merges all mount options (VFS, FS and userspace) to one options string |
| * and returns the result. This function does not modify @fs. |
| * |
| * Returns: pointer to string (can be freed by free(3)) or NULL in case of error. |
| */ |
| char *mnt_fs_strdup_options(struct libmnt_fs *fs) |
| { |
| char *res; |
| |
| if (!fs) |
| return NULL; |
| |
| errno = 0; |
| if (fs->optstr) |
| return strdup(fs->optstr); |
| |
| res = merge_optstr(fs->vfs_optstr, fs->fs_optstr); |
| if (!res && errno) |
| return NULL; |
| if (fs->user_optstr && |
| mnt_optstr_append_option(&res, fs->user_optstr, NULL)) { |
| free(res); |
| res = NULL; |
| } |
| return res; |
| } |
| |
| /** |
| * mnt_fs_get_options: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * |
| * Returns: pointer to string or NULL in case of error. |
| */ |
| const char *mnt_fs_get_options(struct libmnt_fs *fs) |
| { |
| return fs ? fs->optstr : NULL; |
| } |
| |
| /** |
| * mnt_fs_get_optional_fields |
| * @fs: mountinfo entry pointer |
| * |
| * Returns: pointer to string with mountinfo optional fields |
| * or NULL in case of error. |
| */ |
| const char *mnt_fs_get_optional_fields(struct libmnt_fs *fs) |
| { |
| return fs ? fs->opt_fields : NULL; |
| } |
| |
| /** |
| * mnt_fs_set_options: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * @optstr: options string |
| * |
| * Splits @optstr to VFS, FS and userspace mount options and updates relevant |
| * parts of @fs. |
| * |
| * Returns: 0 on success, or negative number in case of error. |
| */ |
| int mnt_fs_set_options(struct libmnt_fs *fs, const char *optstr) |
| { |
| char *v = NULL, *f = NULL, *u = NULL, *n = NULL; |
| |
| if (!fs) |
| return -EINVAL; |
| if (optstr) { |
| int rc = mnt_split_optstr(optstr, &u, &v, &f, 0, 0); |
| if (rc) |
| return rc; |
| n = strdup(optstr); |
| if (!n) { |
| free(u); |
| free(v); |
| free(f); |
| return -ENOMEM; |
| } |
| } |
| |
| free(fs->fs_optstr); |
| free(fs->vfs_optstr); |
| free(fs->user_optstr); |
| free(fs->optstr); |
| |
| fs->fs_optstr = f; |
| fs->vfs_optstr = v; |
| fs->user_optstr = u; |
| fs->optstr = n; |
| |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_append_options: |
| * @fs: fstab/mtab/mountinfo entry |
| * @optstr: mount options |
| * |
| * Parses (splits) @optstr and appends results to VFS, FS and userspace lists |
| * of options. |
| * |
| * If @optstr is NULL, then @fs is not modified and 0 is returned. |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_append_options(struct libmnt_fs *fs, const char *optstr) |
| { |
| char *v = NULL, *f = NULL, *u = NULL; |
| int rc; |
| |
| if (!fs) |
| return -EINVAL; |
| if (!optstr) |
| return 0; |
| |
| rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0); |
| if (rc) |
| return rc; |
| |
| if (!rc && v) |
| rc = mnt_optstr_append_option(&fs->vfs_optstr, v, NULL); |
| if (!rc && f) |
| rc = mnt_optstr_append_option(&fs->fs_optstr, f, NULL); |
| if (!rc && u) |
| rc = mnt_optstr_append_option(&fs->user_optstr, u, NULL); |
| if (!rc) |
| rc = mnt_optstr_append_option(&fs->optstr, optstr, NULL); |
| |
| free(v); |
| free(f); |
| free(u); |
| |
| return rc; |
| } |
| |
| /** |
| * mnt_fs_prepend_options: |
| * @fs: fstab/mtab/mountinfo entry |
| * @optstr: mount options |
| * |
| * Parses (splits) @optstr and prepends the results to VFS, FS and userspace lists |
| * of options. |
| * |
| * If @optstr is NULL, then @fs is not modified and 0 is returned. |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_prepend_options(struct libmnt_fs *fs, const char *optstr) |
| { |
| char *v = NULL, *f = NULL, *u = NULL; |
| int rc; |
| |
| if (!fs) |
| return -EINVAL; |
| if (!optstr) |
| return 0; |
| |
| rc = mnt_split_optstr((char *) optstr, &u, &v, &f, 0, 0); |
| if (rc) |
| return rc; |
| |
| if (!rc && v) |
| rc = mnt_optstr_prepend_option(&fs->vfs_optstr, v, NULL); |
| if (!rc && f) |
| rc = mnt_optstr_prepend_option(&fs->fs_optstr, f, NULL); |
| if (!rc && u) |
| rc = mnt_optstr_prepend_option(&fs->user_optstr, u, NULL); |
| if (!rc) |
| rc = mnt_optstr_prepend_option(&fs->optstr, optstr, NULL); |
| |
| free(v); |
| free(f); |
| free(u); |
| |
| return rc; |
| } |
| |
| /* |
| * mnt_fs_get_fs_options: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * |
| * Returns: pointer to superblock (fs-depend) mount option string or NULL. |
| */ |
| const char *mnt_fs_get_fs_options(struct libmnt_fs *fs) |
| { |
| return fs ? fs->fs_optstr : NULL; |
| } |
| |
| /** |
| * mnt_fs_get_vfs_options: |
| * @fs: fstab/mtab entry pointer |
| * |
| * Returns: pointer to fs-independent (VFS) mount option string or NULL. |
| */ |
| const char *mnt_fs_get_vfs_options(struct libmnt_fs *fs) |
| { |
| return fs ? fs->vfs_optstr : NULL; |
| } |
| |
| /** |
| * mnt_fs_get_user_options: |
| * @fs: fstab/mtab entry pointer |
| * |
| * Returns: pointer to userspace mount option string or NULL. |
| */ |
| const char *mnt_fs_get_user_options(struct libmnt_fs *fs) |
| { |
| return fs ? fs->user_optstr : NULL; |
| } |
| |
| /** |
| * mnt_fs_get_attributes: |
| * @fs: fstab/mtab entry pointer |
| * |
| * Returns: pointer to attributes string or NULL. |
| */ |
| const char *mnt_fs_get_attributes(struct libmnt_fs *fs) |
| { |
| return fs ? fs->attrs : NULL; |
| } |
| |
| /** |
| * mnt_fs_set_attributes: |
| * @fs: fstab/mtab/mountinfo entry |
| * @optstr: options string |
| * |
| * Sets mount attributes. The attributes are mount(2) and mount(8) independent |
| * options, these options are not sent to the kernel and are not interpreted by |
| * libmount. The attributes are stored in /run/mount/utab only. |
| * |
| * The attributes are managed by libmount in userspace only. It's possible |
| * that information stored in userspace will not be available for libmount |
| * after CLONE_FS unshare. Be careful, and don't use attributes if possible. |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_attributes(struct libmnt_fs *fs, const char *optstr) |
| { |
| return strdup_to_struct_member(fs, attrs, optstr); |
| } |
| |
| /** |
| * mnt_fs_append_attributes |
| * @fs: fstab/mtab/mountinfo entry |
| * @optstr: options string |
| * |
| * Appends mount attributes. (See mnt_fs_set_attributes()). |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_append_attributes(struct libmnt_fs *fs, const char *optstr) |
| { |
| if (!fs) |
| return -EINVAL; |
| if (!optstr) |
| return 0; |
| return mnt_optstr_append_option(&fs->attrs, optstr, NULL); |
| } |
| |
| /** |
| * mnt_fs_prepend_attributes |
| * @fs: fstab/mtab/mountinfo entry |
| * @optstr: options string |
| * |
| * Prepends mount attributes. (See mnt_fs_set_attributes()). |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_prepend_attributes(struct libmnt_fs *fs, const char *optstr) |
| { |
| if (!fs) |
| return -EINVAL; |
| if (!optstr) |
| return 0; |
| return mnt_optstr_prepend_option(&fs->attrs, optstr, NULL); |
| } |
| |
| |
| /** |
| * mnt_fs_get_freq: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * |
| * Returns: dump frequency in days. |
| */ |
| int mnt_fs_get_freq(struct libmnt_fs *fs) |
| { |
| return fs ? fs->freq : 0; |
| } |
| |
| /** |
| * mnt_fs_set_freq: |
| * @fs: fstab/mtab entry pointer |
| * @freq: dump frequency in days |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_freq(struct libmnt_fs *fs, int freq) |
| { |
| if (!fs) |
| return -EINVAL; |
| fs->freq = freq; |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_get_passno: |
| * @fs: fstab/mtab entry pointer |
| * |
| * Returns: "pass number on parallel fsck". |
| */ |
| int mnt_fs_get_passno(struct libmnt_fs *fs) |
| { |
| return fs ? fs->passno: 0; |
| } |
| |
| /** |
| * mnt_fs_set_passno: |
| * @fs: fstab/mtab entry pointer |
| * @passno: pass number |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_passno(struct libmnt_fs *fs, int passno) |
| { |
| if (!fs) |
| return -EINVAL; |
| fs->passno = passno; |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_get_root: |
| * @fs: /proc/self/mountinfo entry |
| * |
| * Returns: root of the mount within the filesystem or NULL |
| */ |
| const char *mnt_fs_get_root(struct libmnt_fs *fs) |
| { |
| return fs ? fs->root : NULL; |
| } |
| |
| /** |
| * mnt_fs_set_root: |
| * @fs: mountinfo entry |
| * @path: root path |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_root(struct libmnt_fs *fs, const char *path) |
| { |
| return strdup_to_struct_member(fs, root, path); |
| } |
| |
| /** |
| * mnt_fs_get_swaptype: |
| * @fs: /proc/swaps entry |
| * |
| * Returns: swap type or NULL |
| */ |
| const char *mnt_fs_get_swaptype(struct libmnt_fs *fs) |
| { |
| return fs ? fs->swaptype : NULL; |
| } |
| |
| /** |
| * mnt_fs_get_size: |
| * @fs: /proc/swaps entry |
| * |
| * Returns: size |
| */ |
| off_t mnt_fs_get_size(struct libmnt_fs *fs) |
| { |
| return fs ? fs->size : 0; |
| } |
| |
| /** |
| * mnt_fs_get_usedsize: |
| * @fs: /proc/swaps entry |
| * |
| * Returns: used size |
| */ |
| off_t mnt_fs_get_usedsize(struct libmnt_fs *fs) |
| { |
| return fs ? fs->usedsize : 0; |
| } |
| |
| /** |
| * mnt_fs_get_priority: |
| * @fs: /proc/swaps entry |
| * |
| * Returns: priority |
| */ |
| int mnt_fs_get_priority(struct libmnt_fs *fs) |
| { |
| return fs ? fs->priority : 0; |
| } |
| |
| /** |
| * mnt_fs_set_priority: |
| * @fs: /proc/swaps entry |
| * @prio: priority |
| * |
| * Since: 2.28 |
| * |
| * Returns: 0 or -1 in case of error |
| */ |
| int mnt_fs_set_priority(struct libmnt_fs *fs, int prio) |
| { |
| if (!fs) |
| return -EINVAL; |
| fs->priority = prio; |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_get_bindsrc: |
| * @fs: /run/mount/utab entry |
| * |
| * Returns: full path that was used for mount(2) on MS_BIND |
| */ |
| const char *mnt_fs_get_bindsrc(struct libmnt_fs *fs) |
| { |
| return fs ? fs->bindsrc : NULL; |
| } |
| |
| /** |
| * mnt_fs_set_bindsrc: |
| * @fs: filesystem |
| * @src: path |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_set_bindsrc(struct libmnt_fs *fs, const char *src) |
| { |
| return strdup_to_struct_member(fs, bindsrc, src); |
| } |
| |
| /** |
| * mnt_fs_get_id: |
| * @fs: /proc/self/mountinfo entry |
| * |
| * Returns: mount ID (unique identifier of the mount) or negative number in case of error. |
| */ |
| int mnt_fs_get_id(struct libmnt_fs *fs) |
| { |
| return fs ? fs->id : -EINVAL; |
| } |
| |
| /** |
| * mnt_fs_get_parent_id: |
| * @fs: /proc/self/mountinfo entry |
| * |
| * Returns: parent mount ID or negative number in case of error. |
| */ |
| int mnt_fs_get_parent_id(struct libmnt_fs *fs) |
| { |
| return fs ? fs->parent : -EINVAL; |
| } |
| |
| /** |
| * mnt_fs_get_devno: |
| * @fs: /proc/self/mountinfo entry |
| * |
| * Returns: value of st_dev for files on filesystem or 0 in case of error. |
| */ |
| dev_t mnt_fs_get_devno(struct libmnt_fs *fs) |
| { |
| return fs ? fs->devno : 0; |
| } |
| |
| /** |
| * mnt_fs_get_tid: |
| * @fs: /proc/tid/mountinfo entry |
| * |
| * Returns: TID (task ID) for filesystems read from the mountinfo file |
| */ |
| pid_t mnt_fs_get_tid(struct libmnt_fs *fs) |
| { |
| return fs ? fs->tid : 0; |
| } |
| |
| /** |
| * mnt_fs_get_option: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * @name: option name |
| * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL |
| * @valsz: returns size of options value or 0 |
| * |
| * Returns: 0 on success, 1 when @name not found or negative number in case of error. |
| */ |
| int mnt_fs_get_option(struct libmnt_fs *fs, const char *name, |
| char **value, size_t *valsz) |
| { |
| char rc = 1; |
| |
| if (!fs) |
| return -EINVAL; |
| if (fs->fs_optstr) |
| rc = mnt_optstr_get_option(fs->fs_optstr, name, value, valsz); |
| if (rc == 1 && fs->vfs_optstr) |
| rc = mnt_optstr_get_option(fs->vfs_optstr, name, value, valsz); |
| if (rc == 1 && fs->user_optstr) |
| rc = mnt_optstr_get_option(fs->user_optstr, name, value, valsz); |
| return rc; |
| } |
| |
| /** |
| * mnt_fs_get_attribute: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * @name: option name |
| * @value: returns pointer to the beginning of the value (e.g. name=VALUE) or NULL |
| * @valsz: returns size of options value or 0 |
| * |
| * Returns: 0 on success, 1 when @name not found or negative number in case of error. |
| */ |
| int mnt_fs_get_attribute(struct libmnt_fs *fs, const char *name, |
| char **value, size_t *valsz) |
| { |
| char rc = 1; |
| |
| if (!fs) |
| return -EINVAL; |
| if (fs->attrs) |
| rc = mnt_optstr_get_option(fs->attrs, name, value, valsz); |
| return rc; |
| } |
| |
| /** |
| * mnt_fs_get_comment: |
| * @fs: fstab/mtab/mountinfo entry pointer |
| * |
| * Returns: 0 on success, 1 when not found the @name or negative number in case of error. |
| */ |
| const char *mnt_fs_get_comment(struct libmnt_fs *fs) |
| { |
| if (!fs) |
| return NULL; |
| return fs->comment; |
| } |
| |
| /** |
| * mnt_fs_set_comment: |
| * @fs: fstab entry pointer |
| * @comm: comment string |
| * |
| * Note that the comment has to be terminated by '\n' (new line), otherwise |
| * the whole filesystem entry will be written as a comment to the tabfile (e.g. |
| * fstab). |
| * |
| * Returns: 0 on success or <0 in case of error. |
| */ |
| int mnt_fs_set_comment(struct libmnt_fs *fs, const char *comm) |
| { |
| return strdup_to_struct_member(fs, comment, comm); |
| } |
| |
| /** |
| * mnt_fs_append_comment: |
| * @fs: fstab entry pointer |
| * @comm: comment string |
| * |
| * See also mnt_fs_set_comment(). |
| * |
| * Returns: 0 on success or <0 in case of error. |
| */ |
| int mnt_fs_append_comment(struct libmnt_fs *fs, const char *comm) |
| { |
| if (!fs) |
| return -EINVAL; |
| |
| return append_string(&fs->comment, comm); |
| } |
| |
| /** |
| * mnt_fs_match_target: |
| * @fs: filesystem |
| * @target: mountpoint path |
| * @cache: tags/paths cache or NULL |
| * |
| * Possible are three attempts: |
| * 1) compare @target with @fs->target |
| * |
| * 2) realpath(@target) with @fs->target |
| * |
| * 3) realpath(@target) with realpath(@fs->target) if @fs is not from |
| * /proc/self/mountinfo. |
| * |
| * However, if mnt_cache_set_targets(cache, mtab) was called, and the |
| * path @target or @fs->target is found in the @mtab, the canonicalization is |
| * is not performed (see mnt_resolve_target()). |
| * |
| * The 2nd and 3rd attempts are not performed when @cache is NULL. |
| * |
| * Returns: 1 if @fs target is equal to @target, else 0. |
| */ |
| int mnt_fs_match_target(struct libmnt_fs *fs, const char *target, |
| struct libmnt_cache *cache) |
| { |
| int rc = 0; |
| |
| if (!fs || !target || !fs->target) |
| return 0; |
| |
| /* 1) native paths */ |
| rc = mnt_fs_streq_target(fs, target); |
| |
| if (!rc && cache) { |
| /* 2) - canonicalized and non-canonicalized */ |
| char *cn = mnt_resolve_target(target, cache); |
| rc = (cn && mnt_fs_streq_target(fs, cn)); |
| |
| /* 3) - canonicalized and canonicalized */ |
| if (!rc && cn && !mnt_fs_is_kernel(fs) && !mnt_fs_is_swaparea(fs)) { |
| char *tcn = mnt_resolve_target(fs->target, cache); |
| rc = (tcn && strcmp(cn, tcn) == 0); |
| } |
| } |
| |
| return rc; |
| } |
| |
| /** |
| * mnt_fs_match_source: |
| * @fs: filesystem |
| * @source: tag or path (device or so) or NULL |
| * @cache: tags/paths cache or NULL |
| * |
| * Four attempts are possible: |
| * 1) compare @source with @fs->source |
| * 2) compare realpath(@source) with @fs->source |
| * 3) compare realpath(@source) with realpath(@fs->source) |
| * 4) compare realpath(@source) with evaluated tag from @fs->source |
| * |
| * The 2nd, 3rd and 4th attempts are not performed when @cache is NULL. The |
| * 2nd and 3rd attempts are not performed if @fs->source is tag. |
| * |
| * Returns: 1 if @fs source is equal to @source, else 0. |
| */ |
| int mnt_fs_match_source(struct libmnt_fs *fs, const char *source, |
| struct libmnt_cache *cache) |
| { |
| char *cn; |
| const char *src, *t, *v; |
| |
| if (!fs) |
| return 0; |
| |
| /* 1) native paths... */ |
| if (mnt_fs_streq_srcpath(fs, source) == 1) |
| return 1; |
| |
| if (!source || !fs->source) |
| return 0; |
| |
| /* ... and tags */ |
| if (fs->tagname && strcmp(source, fs->source) == 0) |
| return 1; |
| |
| if (!cache) |
| return 0; |
| if (fs->flags & (MNT_FS_NET | MNT_FS_PSEUDO)) |
| return 0; |
| |
| cn = mnt_resolve_spec(source, cache); |
| if (!cn) |
| return 0; |
| |
| /* 2) canonicalized and native */ |
| src = mnt_fs_get_srcpath(fs); |
| if (src && mnt_fs_streq_srcpath(fs, cn)) |
| return 1; |
| |
| /* 3) canonicalized and canonicalized */ |
| if (src) { |
| src = mnt_resolve_path(src, cache); |
| if (src && !strcmp(cn, src)) |
| return 1; |
| } |
| if (src || mnt_fs_get_tag(fs, &t, &v)) |
| /* src path does not match and the tag is not defined */ |
| return 0; |
| |
| /* read @source's tags to the cache */ |
| if (mnt_cache_read_tags(cache, cn) < 0) { |
| if (errno == EACCES) { |
| /* we don't have permissions to read TAGs from |
| * @source, but can translate the @fs tag to devname. |
| * |
| * (because libblkid uses udev symlinks and this is |
| * accessible for non-root uses) |
| */ |
| char *x = mnt_resolve_tag(t, v, cache); |
| if (x && !strcmp(x, cn)) |
| return 1; |
| } |
| return 0; |
| } |
| |
| /* 4) has the @source a tag that matches with the tag from @fs ? */ |
| if (mnt_cache_device_has_tag(cache, cn, t, v)) |
| return 1; |
| |
| return 0; |
| } |
| |
| /** |
| * mnt_fs_match_fstype: |
| * @fs: filesystem |
| * @types: filesystem name or comma delimited list of filesystems |
| * |
| * For more details see mnt_match_fstype(). |
| * |
| * Returns: 1 if @fs type is matching to @types, else 0. The function returns |
| * 0 when types is NULL. |
| */ |
| int mnt_fs_match_fstype(struct libmnt_fs *fs, const char *types) |
| { |
| return mnt_match_fstype(fs->fstype, types); |
| } |
| |
| /** |
| * mnt_fs_match_options: |
| * @fs: filesystem |
| * @options: comma delimited list of options (and nooptions) |
| * |
| * For more details see mnt_match_options(). |
| * |
| * Returns: 1 if @fs type is matching to @options, else 0. The function returns |
| * 0 when types is NULL. |
| */ |
| int mnt_fs_match_options(struct libmnt_fs *fs, const char *options) |
| { |
| return mnt_match_options(mnt_fs_get_options(fs), options); |
| } |
| |
| /** |
| * mnt_fs_print_debug |
| * @fs: fstab/mtab/mountinfo entry |
| * @file: file stream |
| * |
| * Returns: 0 on success or negative number in case of error. |
| */ |
| int mnt_fs_print_debug(struct libmnt_fs *fs, FILE *file) |
| { |
| if (!fs || !file) |
| return -EINVAL; |
| fprintf(file, "------ fs:\n"); |
| fprintf(file, "source: %s\n", mnt_fs_get_source(fs)); |
| fprintf(file, "target: %s\n", mnt_fs_get_target(fs)); |
| fprintf(file, "fstype: %s\n", mnt_fs_get_fstype(fs)); |
| |
| if (mnt_fs_get_options(fs)) |
| fprintf(file, "optstr: %s\n", mnt_fs_get_options(fs)); |
| if (mnt_fs_get_vfs_options(fs)) |
| fprintf(file, "VFS-optstr: %s\n", mnt_fs_get_vfs_options(fs)); |
| if (mnt_fs_get_fs_options(fs)) |
| fprintf(file, "FS-opstr: %s\n", mnt_fs_get_fs_options(fs)); |
| if (mnt_fs_get_user_options(fs)) |
| fprintf(file, "user-optstr: %s\n", mnt_fs_get_user_options(fs)); |
| if (mnt_fs_get_optional_fields(fs)) |
| fprintf(file, "optional-fields: '%s'\n", mnt_fs_get_optional_fields(fs)); |
| if (mnt_fs_get_attributes(fs)) |
| fprintf(file, "attributes: %s\n", mnt_fs_get_attributes(fs)); |
| |
| if (mnt_fs_get_root(fs)) |
| fprintf(file, "root: %s\n", mnt_fs_get_root(fs)); |
| |
| if (mnt_fs_get_swaptype(fs)) |
| fprintf(file, "swaptype: %s\n", mnt_fs_get_swaptype(fs)); |
| if (mnt_fs_get_size(fs)) |
| fprintf(file, "size: %jd\n", mnt_fs_get_size(fs)); |
| if (mnt_fs_get_usedsize(fs)) |
| fprintf(file, "usedsize: %jd\n", mnt_fs_get_usedsize(fs)); |
| if (mnt_fs_get_priority(fs)) |
| fprintf(file, "priority: %d\n", mnt_fs_get_priority(fs)); |
| |
| if (mnt_fs_get_bindsrc(fs)) |
| fprintf(file, "bindsrc: %s\n", mnt_fs_get_bindsrc(fs)); |
| if (mnt_fs_get_freq(fs)) |
| fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs)); |
| if (mnt_fs_get_passno(fs)) |
| fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs)); |
| if (mnt_fs_get_id(fs)) |
| fprintf(file, "id: %d\n", mnt_fs_get_id(fs)); |
| if (mnt_fs_get_parent_id(fs)) |
| fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs)); |
| if (mnt_fs_get_devno(fs)) |
| fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)), |
| minor(mnt_fs_get_devno(fs))); |
| if (mnt_fs_get_tid(fs)) |
| fprintf(file, "tid: %d\n", mnt_fs_get_tid(fs)); |
| if (mnt_fs_get_comment(fs)) |
| fprintf(file, "comment: '%s'\n", mnt_fs_get_comment(fs)); |
| |
| return 0; |
| } |
| |
| /** |
| * mnt_free_mntent: |
| * @mnt: mount entry |
| * |
| * Deallocates the "mntent.h" mount entry. |
| */ |
| void mnt_free_mntent(struct mntent *mnt) |
| { |
| if (mnt) { |
| free(mnt->mnt_fsname); |
| free(mnt->mnt_dir); |
| free(mnt->mnt_type); |
| free(mnt->mnt_opts); |
| free(mnt); |
| } |
| } |
| |
| /** |
| * mnt_fs_to_mntent: |
| * @fs: filesystem |
| * @mnt: mount description (as described in mntent.h) |
| * |
| * Copies the information from @fs to struct mntent @mnt. If @mnt is already set, |
| * then the struct mntent items are reallocated and updated. See also |
| * mnt_free_mntent(). |
| * |
| * Returns: 0 on success and a negative number in case of error. |
| */ |
| int mnt_fs_to_mntent(struct libmnt_fs *fs, struct mntent **mnt) |
| { |
| int rc; |
| struct mntent *m; |
| |
| if (!fs || !mnt) |
| return -EINVAL; |
| |
| m = *mnt; |
| if (!m) { |
| m = calloc(1, sizeof(*m)); |
| if (!m) |
| return -ENOMEM; |
| } |
| |
| if ((rc = update_str(&m->mnt_fsname, mnt_fs_get_source(fs)))) |
| goto err; |
| if ((rc = update_str(&m->mnt_dir, mnt_fs_get_target(fs)))) |
| goto err; |
| if ((rc = update_str(&m->mnt_type, mnt_fs_get_fstype(fs)))) |
| goto err; |
| |
| errno = 0; |
| m->mnt_opts = mnt_fs_strdup_options(fs); |
| if (!m->mnt_opts && errno) { |
| rc = -errno; |
| goto err; |
| } |
| |
| m->mnt_freq = mnt_fs_get_freq(fs); |
| m->mnt_passno = mnt_fs_get_passno(fs); |
| |
| if (!m->mnt_fsname) { |
| m->mnt_fsname = strdup("none"); |
| if (!m->mnt_fsname) |
| goto err; |
| } |
| *mnt = m; |
| |
| return 0; |
| err: |
| if (m != *mnt) |
| mnt_free_mntent(m); |
| return rc; |
| } |