diff options
Diffstat (limited to 'shlibs/mount/src/fs.c')
-rw-r--r-- | shlibs/mount/src/fs.c | 787 |
1 files changed, 787 insertions, 0 deletions
diff --git a/shlibs/mount/src/fs.c b/shlibs/mount/src/fs.c new file mode 100644 index 00000000..63da2f20 --- /dev/null +++ b/shlibs/mount/src/fs.c @@ -0,0 +1,787 @@ +/* + * 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: mnt_fs represents one entry in fstab/mtab/mountinfo + * + */ +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#include <errno.h> +#include <blkid.h> + +#include "nls.h" +#include "mountP.h" + +/** + * mnt_new_fs: + * + * Returns: newly allocated mnt_file fs. + */ +mnt_fs *mnt_new_fs(void) +{ + mnt_fs *fs = calloc(1, sizeof(struct _mnt_fs)); + if (!fs) + return NULL; + + INIT_LIST_HEAD(&fs->ents); + return fs; +} + +/** + * mnt_free_fs: + * @fs: fs pointer + * + * Deallocates the fs. + */ +void mnt_free_fs(mnt_fs *fs) +{ + if (!fs) + return; + list_del(&fs->ents); + + free(fs->source); + free(fs->tagname); + free(fs->tagval); + free(fs->mntroot); + free(fs->target); + free(fs->fstype); + free(fs->optstr); + free(fs->vfs_optstr); + free(fs->fs_optstr); + + free(fs); +} + +/** + * mnt_fs_get_userdata: + * @fs: mnt_file instance + * + * Returns: private data set by mnt_fs_set_userdata() or NULL. + */ +void *mnt_fs_get_userdata(mnt_fs *fs) +{ + return fs ? fs->userdata : NULL; +} + +/** + * mnt_fs_set_userdata: + * @fs: mnt_file instance + * + * The "userdata" are library independent data. + * + * Returns: 0 or -1 in case of error (if @fs is NULL). + */ +int mnt_fs_set_userdata(mnt_fs *fs, void *data) +{ + if (!fs) + return -1; + fs->userdata = data; + return 0; +} + +/** + * mnt_fs_get_srcpath: + * @fs: mnt_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(mnt_fs *fs) +{ + assert(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: mnt_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(mnt_fs *fs) +{ + return fs ? fs->source : NULL; +} + +/* Used by parser mnt_file ONLY (@source has to be allocated) */ +int __mnt_fs_set_source(mnt_fs *fs, char *source) +{ + assert(fs); + + if (!source) + return -1; + + if (strchr(source, '=')) { + char *name, *val; + + if (blkid_parse_tag_string(source, &name, &val) != 0) + return -1; + + fs->tagval = val; + fs->tagname = name; + } + + fs->source = source; + 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 -1 in case of error. + */ +int mnt_fs_set_source(mnt_fs *fs, const char *source) +{ + char *p; + + if (!fs && !source) + return -1; + + p = strdup(source); + if (!p) + return -1; + + free(fs->tagval); + free(fs->tagname); + free(fs->source); + fs->tagval = fs->tagname = fs->source = NULL; + + return __mnt_fs_set_source(fs, p); +} + +/** + * 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" has to + * be always set for all entries. + * + * See also mnt_fs_get_source(). + * + * <informalexample> + * <programlisting> + * char *src; + * mnt_fs *fs = mnt_tab_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 -1 in case that a TAG is not defined. + */ +int mnt_fs_get_tag(mnt_fs *fs, const char **name, const char **value) +{ + if (fs == NULL || !fs->tagname) + return -1; + 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(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->target : NULL; +} + +/** + * mnt_fs_set_target: + * @fs: fstab/mtab/mountinfo entry + * @target: mountpoint + * + * This function creates a private copy (strdup()) of @target. + * + * Returns: 0 on success or -1 in case of error. + */ +int mnt_fs_set_target(mnt_fs *fs, const char *target) +{ + char *p; + + assert(fs); + + if (!fs || !target) + return -1; + + p = strdup(target); + if (!p) + return -1; + free(fs->target); + fs->target = p; + + return 0; +} + +/** + * mnt_fs_get_fstype: + * @fs: fstab/mtab/mountinfo entry pointer + * + * Returns: pointer to filesystem type. + */ +const char *mnt_fs_get_fstype(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->fstype : NULL; +} + +/* Used by mnt_file parser only */ +int __mnt_fs_set_fstype(mnt_fs *fs, char *fstype) +{ + assert(fs); + + if (!fstype) + return -1; + + fs->fstype = fstype; + fs->flags &= ~MNT_FS_PSEUDO; + fs->flags &= ~MNT_FS_NET; + + /* save info about pseudo filesystems */ + 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; + + 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 -1 in case of error. + */ +int mnt_fs_set_fstype(mnt_fs *fs, const char *fstype) +{ + char *p; + + if (!fs || !fstype) + return -1; + + p = strdup(fstype); + if (!p) + return -1; + free(fs->fstype); + + return __mnt_fs_set_fstype(fs, p); +} + +/** + * mnt_fs_get_optstr: + * @fs: fstab/mtab/mountinfo entry pointer + * + * Returns: pointer to mount option string with all options (FS and VFS) + */ +const char *mnt_fs_get_optstr(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->optstr : NULL; +} + +/** + * mnt_fs_set_optstr: + * @fs: fstab/mtab/mountinfo entry + * @optstr: options string + * + * This function creates a private copy (strdup()) of @optstr. + * + * Returns: 0 on success or -1 in case of error. + */ +int mnt_fs_set_optstr(mnt_fs *fs, const char *optstr) +{ + char *p; + + assert(fs); + + if (!fs || !optstr) + return -1; + p = strdup(optstr); + if (!p) + return -1; + + free(fs->optstr); + free(fs->fs_optstr); + free(fs->vfs_optstr); + fs->fs_optstr = fs->vfs_optstr = NULL; + + /* TODO: it would be possible to use built-in maps of options + * and differentiate between VFS and FS options, then we can + * set fs_optstr and vfs_optstr */ + + fs->optstr = p; + + return 0; +} + +/** + * mnt_fs_get_fs_optstr: + * @fs: fstab/mtab/mountinfo entry pointer + * + * This function works for "mountinfo" files only. + * + * Returns: pointer to superblock (fs-depend) mount option string or NULL. + */ +const char *mnt_fs_get_fs_optstr(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->fs_optstr : NULL; +} + +/** + * mnt_fs_get_vfs_optstr: + * @fs: fstab/mtab entry pointer + * + * This function works for "mountinfo" files only. + * + * Returns: pointer to fs-independent (VFS) mount option string or NULL. + */ +const char *mnt_fs_get_vfs_optstr(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->vfs_optstr : NULL; +} + + +/** + * mnt_fs_get_freq: + * @fs: fstab/mtab/mountinfo entry pointer + * + * Returns: dump frequency in days. + */ +int mnt_fs_get_freq(mnt_fs *fs) +{ + assert(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 -1 in case of error. + */ +int mnt_fs_set_freq(mnt_fs *fs, int freq) +{ + assert(fs); + if (!fs) + return -1; + 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(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->passno: 0; +} + +/** + * mnt_fs_set_passno: + * @fs: fstab/mtab entry pointer + * @passno: pass number + * + * Returns: 0 on success or -1 in case of error. + */ +int mnt_fs_set_passno(mnt_fs *fs, int passno) +{ + assert(fs); + if (!fs) + return -1; + fs->passno = passno; + return 0; +} + +/** + * mnt_fs_get_id: + * @fs: /proc/self/mountinfo entry + * + * Returns: mount ID (unique identifier of the mount) or -1 if ID undefined + * (for example if @fs is not mountinfo entry). + */ +int mnt_fs_get_id(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->id : -1; +} + +/** + * mnt_fs_get_parent_id: + * @fs: /proc/self/mountinfo entry + * + * Returns: parent mount ID or -1 if ID undefined (for example if @fs is not + * mountinfo entry). + */ +int mnt_fs_get_parent_id(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->parent : -1; +} + +/** + * mnt_fs_get_devno: + * @fs: /proc/self/mountinfo + * + * Returns: value of st_dev for files on filesystem or 0 in case of error. + */ +dev_t mnt_fs_get_devno(mnt_fs *fs) +{ + assert(fs); + return fs ? fs->devno : 0; +} + +/** + * mnt_fs_get_option: + * @fs: fstab/mtab/mountinfo entry pointer + * @name: option name + * @value: returns pointer to the begin of the value (e.g. name=VALUE) or NULL + * @valsz: returns size of options value or 0 + * + * Returns: 0 on success, 1 when not found the @name or -1 in case of error. + */ +int mnt_fs_get_option(mnt_fs *fs, const char *name, + char **value, size_t *valsz) +{ + char *optstr = (char *) mnt_fs_get_optstr(fs); + return optstr ? mnt_optstr_get_option(optstr, name, value, valsz) : 1; +} + +/** + * 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). + * + * 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(mnt_fs *fs, const char *target, mnt_cache *cache) +{ + int rc = 0; + + if (!fs || !target || !fs->target) + return 0; + + /* 1) native paths */ + rc = !strcmp(target, fs->target); + + if (!rc && cache) { + /* 2) - canonicalized and non-canonicalized */ + char *cn = mnt_resolve_path(target, cache); + rc = (cn && strcmp(cn, fs->target) == 0); + + /* 3) - canonicalized and canonicalized */ + if (!rc && cn) { + char *tcn = mnt_resolve_path(fs->target, cache); + rc = (tcn && strcmp(cn, tcn) == 0); + } + } + + return rc; +} + +/** + * mnt_fs_match_source: + * @fs: filesystem + * @source: tag or path (device or so) + * @cache: tags/paths cache or NULL + * + * Possible are four attempts: + * 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(mnt_fs *fs, const char *source, mnt_cache *cache) +{ + char *cn; + const char *src, *t, *v; + + if (!fs || !source || !fs->source) + return 0; + + /* 1) native paths/tags */ + if (!strcmp(source, fs->source)) + 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 && !strcmp(cn, src)) + 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 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 @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 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(mnt_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(mnt_fs *fs, const char *options) +{ + return mnt_match_options(fs->optstr, options); +} + +/* Unfortunately the classical Unix /etc/mtab and /etc/fstab + do not handle directory names containing spaces. + Here we mangle them, replacing a space by \040. + What do other Unices do? */ + +static unsigned char need_escaping[] = { ' ', '\t', '\n', '\\' }; + +static char *mangle(const char *s) +{ + char *ss, *sp; + int n; + + n = strlen(s); + ss = sp = malloc(4*n+1); + if (!sp) + return NULL; + while(1) { + for (n = 0; n < sizeof(need_escaping); n++) { + if (*s == need_escaping[n]) { + *sp++ = '\\'; + *sp++ = '0' + ((*s & 0300) >> 6); + *sp++ = '0' + ((*s & 070) >> 3); + *sp++ = '0' + (*s & 07); + goto next; + } + } + *sp++ = *s; + if (*s == 0) + break; + next: + s++; + } + return ss; +} + +/** + * mnt_fprintf_line: + * @f: FILE + * @fmt: printf-like format string (see MNT_TAB_PRINTFMT) + * @source: (spec) device name or tag=value + * @target: mountpoint + * @fstype: filesystem type + * @options: mount options + * @freq: dump frequency in days + * @passno: pass number on parallel fsck + * + * It's recommended to use this function rather than directly call fprintf() to + * write an entry to mtab/fstab. All data in these files has to be properly + * formatted (for example space within paths/tags has to be escaped, see + * fstab(5) for more details). + * + * Returns: return value from fprintf(). + */ +int mnt_fprintf_line( FILE *f, + const char *fmt, + const char *source, + const char *target, + const char *fstype, + const char *options, + int freq, + int passno) +{ + char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL; + int rc = -1; + + if (!f || !fmt || !source || !target || !fstype || !options) + return -1; + + m1 = mangle(source); + m2 = mangle(target); + m3 = mangle(fstype); + m4 = mangle(options); + + if (!m1 || !m2 || !m3 || !m4) + goto done; + + rc = fprintf(f, fmt, m1, m2, m3, m4, freq, passno); +done: + free(m1); + free(m2); + free(m3); + free(m4); + + return rc; +} + +/** + * mnt_fs_fprintf: + * @fs: fstab/mtab/mountinfo entry + * @f: FILE + * @fmt: printf-like format string (see MNT_TAB_PRINTFMT) + * + * Returns: return value from fprintf(). + */ +int mnt_fs_fprintf(mnt_fs *fs, FILE *f, const char *fmt) +{ + assert(fs); + assert(f); + assert(fmt); + + if (!fs || !f) + return -1; + + return mnt_fprintf_line(f, fmt, + mnt_fs_get_source(fs), + mnt_fs_get_target(fs), + mnt_fs_get_fstype(fs), + mnt_fs_get_optstr(fs), + mnt_fs_get_freq(fs), + mnt_fs_get_passno(fs)); +} + +/** + * mnt_fs_print_debug + * @fs: fstab/mtab/mountinfo entry + * @file: output + * + * Returns: 0 on success or -1 in case of error. + */ +int mnt_fs_print_debug(mnt_fs *fs, FILE *file) +{ + if (!fs) + return -1; + fprintf(file, "------ fs: %p\n", fs); + 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)); + fprintf(file, "optstr: %s\n", mnt_fs_get_optstr(fs)); + fprintf(file, "freq: %d\n", mnt_fs_get_freq(fs)); + fprintf(file, "pass: %d\n", mnt_fs_get_passno(fs)); + fprintf(file, "id: %d\n", mnt_fs_get_id(fs)); + fprintf(file, "parent: %d\n", mnt_fs_get_parent_id(fs)); + fprintf(file, "devno: %d:%d\n", major(mnt_fs_get_devno(fs)), + minor(mnt_fs_get_devno(fs))); + + + return 0; +} |