/*
* Copyright (C) 2008-2009 Karel Zak <kzak@redhat.com>
*
* This file may be redistributed under the terms of the
* GNU Lesser General Public License.
*
* The mnt_fs is representation of one line in a fstab / mtab / mountinfo.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <blkid/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_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
* - NULL when path is not set (for example when TAG
* (LABEL/UUID) is defined)
*
* 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;
}
/**
* @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
*
* 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().
*
* Example:
* char *src;
* mnt_fs *fs = mnt_file_find_target(mf, "/home");
*
* 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
*
* 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
*
* 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
*
* 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
*
* Returns 0 on success or -1 in case of error.
*/
int mnt_fs_set_optstr(mnt_fs *fs, const char *optstr)
{
assert(fs);
if (!fs || !optstr)
return -1;
free(fs->optstr);
free(fs->fs_optstr);
free(fs->vfs_optstr);
fs->fs_optstr = fs->vfs_optstr = NULL;
fs->optstr = strdup(optstr);
return fs->optstr ? 0 : -1;
}
/**
* 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/mountinfo 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/mountinfo 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/mountinfo 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/mountinfo 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_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;
}
/* 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_MFILE_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
*
* 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_MFILE_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));
return 0;
}