aboutsummaryrefslogtreecommitdiff
path: root/sutils/fstab.c
diff options
context:
space:
mode:
Diffstat (limited to 'sutils/fstab.c')
-rw-r--r--sutils/fstab.c479
1 files changed, 432 insertions, 47 deletions
diff --git a/sutils/fstab.c b/sutils/fstab.c
index 6c8e0f81..b66e5195 100644
--- a/sutils/fstab.c
+++ b/sutils/fstab.c
@@ -1,6 +1,6 @@
/* Fstab filesystem frobbing
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
Written by Miles Bader <miles@gnu.ai.mit.edu>
@@ -27,6 +27,8 @@
#include <fcntl.h>
#include <error.h>
#include <argz.h>
+#include <argp.h>
+#include <fnmatch.h>
#include <hurd/fsys.h>
@@ -34,7 +36,7 @@
extern error_t fsys_set_readonly (fsys_t fsys, int readonly);
extern error_t fsys_get_readonly (fsys_t fsys, int *readonly);
-extern error_t fsys_remount (fsys_t fsys);
+extern error_t fsys_update (fsys_t fsys);
extern file_t file_name_lookup_carefully (const char *file,
int flags, mode_t mode);
@@ -66,7 +68,7 @@ fstab_free (struct fstab *fstab)
/* Return a new fstypes structure in TYPES. SEARCH_FMTS is copied. */
error_t
-fstypes_create (char *search_fmts, size_t search_fmts_len,
+fstypes_create (const char *search_fmts, size_t search_fmts_len,
struct fstypes **types)
{
struct fstypes *new = malloc (sizeof (struct fstypes));
@@ -94,11 +96,12 @@ fstypes_create (char *search_fmts, size_t search_fmts_len,
one is found, it is added to TYPES, otherwise an new entry is created
with a NULL PROGRAM field. */
error_t
-fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
+fstypes_get (struct fstypes *types, const char *name, struct fstype **fstype)
{
char *fmts, *fmt;
size_t fmts_len;
struct fstype *type;
+ char *program = 0;
for (type = types->entries; type; type = type->next)
if (strcasecmp (type->name, name) == 0)
@@ -108,14 +111,6 @@ fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
}
/* No existing entry, make a new one. */
- type = malloc (sizeof (struct fstype));
- if (! type)
- return ENOMEM;
-
- type->name = strdup (name);
- type->program = 0;
- type->next = types->entries;
- types->entries = type;
fmts = types->program_search_fmts;
fmts_len = types->program_search_fmts_len;
@@ -123,7 +118,6 @@ fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
{
int fd;
- char *program;
asprintf (&program, fmt, name);
fd = open (program, O_EXEC);
@@ -144,23 +138,109 @@ fstypes_get (struct fstypes *types, char *name, struct fstype **fstype)
close (fd);
if (rv < 0)
- return errno;
-
- if (stat.st_mode & S_IXUSR)
- /* Yup execute bit is set. This must a program... */
{
- type->program = program;
- break;
+ free (program);
+ return errno;
}
+
+ if (stat.st_mode & S_IXUSR)
+ /* Yup execute bit is set. This must be a program... */
+ break;
+
+ free (program);
}
+
+ program = 0;
+ }
+
+ type = malloc (sizeof (struct fstype));
+ if (! type)
+ {
+ free (program);
+ return ENOMEM;
}
+ type->name = strdup (name);
+ if (type->name == 0)
+ {
+ free (type);
+ return ENOMEM;
+ }
+ type->program = program;
+ type->next = types->entries;
+ types->entries = type;
+
+ *fstype = type;
+
return 0;
}
+
+#if 0
+/* XXX nice idea, but not that useful since scanf's %s always eats all
+ non-ws, and it seems a bit overkill to convert it to a .+ regexp match */
+error_t
+fstypes_find_program (struct fstypes *types, const char *program,
+ struct fstype **fstype)
+{
+ char *fmts, *fmt;
+ size_t fmts_len;
+ struct fstype *type;
+ char *typename;
+
+ /* First see if a known type matches this program. */
+ for (type = types->entries; type; type = type->next)
+ if (type->program && !strcmp (type->program, program))
+ {
+ *fstype = type;
+ return 0;
+ }
+
+ /* No existing entry, see if we can make a new one. */
+
+ typename = alloca (strlen (program) + 1);
+
+ fmts = types->program_search_fmts;
+ fmts_len = types->program_search_fmts_len;
+ for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt))
+ /* XXX this only works for trailing %s */
+ if (sscanf (program, fmt, typename) == 1)
+ {
+ /* This format matches the program and yields the type name.
+ Create a new entry for this type. */
+
+ type = malloc (sizeof (struct fstype));
+ if (! type)
+ return ENOMEM;
+ type->name = strdup (typename);
+ if (type->name == 0)
+ {
+ free (type);
+ return ENOMEM;
+ }
+ type->program = strdup (program);
+ if (type->program == 0)
+ {
+ free (type->name);
+ free (type);
+ return ENOMEM;
+ }
+ type->next = types->entries;
+ types->entries = type;
+
+ *fstype = type;
+ return 0;
+ }
+
+ /* We could find no program search format that could have yielded this
+ program name. */
+ *fstype = 0;
+ return 0;
+}
+#endif
/* Copy MNTENT into FS, copying component strings as well. */
error_t
-fs_set_mntent (struct fs *fs, struct mntent *mntent)
+fs_set_mntent (struct fs *fs, const struct mntent *mntent)
{
char *end;
size_t needed = 0;
@@ -180,7 +260,8 @@ fs_set_mntent (struct fs *fs, struct mntent *mntent)
if (! fs->storage)
return ENOMEM;
- if (strcmp (fs->mntent.mnt_dir, mntent->mnt_dir) != 0)
+ if (!fs->mntent.mnt_dir || !mntent->mnt_dir
+ || strcmp (fs->mntent.mnt_dir, mntent->mnt_dir) != 0)
{
fs->mounted = fs->readonly = -1;
if (fs->fsys != MACH_PORT_NULL)
@@ -194,20 +275,28 @@ fs_set_mntent (struct fs *fs, struct mntent *mntent)
/* Copy each mntent field from MNTENT into FS's version. */
end = fs->storage;
#define STORE(field) \
- fs->mntent.field = end; end = stpcpy (end, mntent->field) + 1
+ if (mntent->field) \
+ { \
+ fs->mntent.field = end; \
+ end = stpcpy (end, mntent->field) + 1; \
+ } \
+ else \
+ fs->mntent.field = 0;
STORE (mnt_fsname);
STORE (mnt_dir);
STORE (mnt_type);
STORE (mnt_opts);
#undef STORE
- if (fs->type && strcasecmp (fs->type->name, mntent->mnt_type) != 0)
+ if (fs->type
+ && (!mntent->mnt_type
+ || strcasecmp (fs->type->name, mntent->mnt_type) != 0))
fs->type = 0; /* Type is different. */
return 0;
}
-/* Returns an fstype for FS in TYPE, trying to fillin FS's type field if
+/* Returns an fstype for FS in TYPE, trying to fill in FS's type field if
necessary. */
error_t
fs_type (struct fs *fs, struct fstype **type)
@@ -257,7 +346,7 @@ _fs_check_mounted (struct fs *fs)
the mntent, but oh well, nothing we can do about that.] */
{
err = file_get_translator_cntl (mount_point, &fs->fsys);
- if (err == EINVAL || err == EOPNOTSUPP)
+ if (err == EINVAL || err == EOPNOTSUPP || err == ENXIO)
/* Either the mount point doesn't exist, or wasn't mounted. */
{
fs->fsys = MACH_PORT_NULL;
@@ -318,10 +407,12 @@ fs_readonly (struct fs *fs, int *readonly)
err = fs_fsys (fs, &fsys);
if (! err)
- if (fsys == MACH_PORT_NULL)
- fs->readonly = 1;
- else
- err = fsys_get_readonly (fsys, &fs->readonly);
+ {
+ if (fsys == MACH_PORT_NULL)
+ fs->readonly = 1;
+ else
+ err = fsys_get_readonly (fsys, &fs->readonly);
+ }
}
if (!err && readonly)
@@ -354,7 +445,7 @@ fs_set_readonly (struct fs *fs, int readonly)
return err;
}
-/* If FS is currently mounted tell lit to remount the device. XXX If FS is
+/* If FS is currently mounted tell it to remount the device. XXX If FS is
not mounted at all, then nothing is done. */
error_t
fs_remount (struct fs *fs)
@@ -362,14 +453,14 @@ fs_remount (struct fs *fs)
fsys_t fsys;
error_t err = fs_fsys (fs, &fsys);
if (!err && fsys != MACH_PORT_NULL) /* XXX What to do if not mounted? */
- err = fsys_remount (fsys);
+ err = fsys_update (fsys);
return err;
}
/* Returns the FS entry in FSTAB with the device field NAME (there can only
be one such entry). */
inline struct fs *
-fstab_find_device (struct fstab *fstab, char *name)
+fstab_find_device (const struct fstab *fstab, const char *name)
{
struct fs *fs;
for (fs = fstab->entries; fs; fs = fs->next)
@@ -381,9 +472,20 @@ fstab_find_device (struct fstab *fstab, char *name)
/* Returns the FS entry in FSTAB with the mount point NAME (there can only
be one such entry). */
inline struct fs *
-fstab_find_mount (struct fstab *fstab, char *name)
+fstab_find_mount (const struct fstab *fstab, const char *name)
{
struct fs *fs;
+
+ /* Don't count "none" or "-" as matching any other mount point.
+ It is canonical to use "none" for swap partitions, and multiple
+ such do not in fact conflict with each other. Likewise, the
+ special device name "ignore" is used for things that should not
+ be processed automatically. */
+ if (!strcmp (name, "-")
+ || !strcmp (name, "none")
+ || !strcmp (name, "ignore"))
+ return 0;
+
for (fs = fstab->entries; fs; fs = fs->next)
if (strcmp (fs->mntent.mnt_dir, name) == 0)
return fs;
@@ -393,9 +495,31 @@ fstab_find_mount (struct fstab *fstab, char *name)
/* Returns the FS entry in FSTAB with the device or mount point NAME (there
can only be one such entry). */
inline struct fs *
-fstab_find (struct fstab *fstab, char *name)
+fstab_find (const struct fstab *fstab, const char *name)
{
- return fstab_find_device (fstab, name) ?: fstab_find_mount (fstab, name);
+ struct fs *ret;
+ const char *real_name;
+
+ ret = fstab_find_device (fstab, name);
+ if (ret)
+ return ret;
+
+ ret = fstab_find_mount (fstab, name);
+ if (ret)
+ return ret;
+
+ real_name = realpath (name, NULL);
+
+ ret = fstab_find_device (fstab, real_name);
+ if (ret) {
+ free (real_name);
+ return ret;
+ }
+
+ ret = fstab_find_mount (fstab, real_name);
+ free (real_name);
+
+ return ret;
}
/* Cons FS onto the beginning of FSTAB's entry list. */
@@ -426,7 +550,7 @@ fs_free (struct fs *fs)
conflict (in either the device or mount point). If RESULT is non-zero, the
new entry is returne in it. */
error_t
-fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
+fstab_add_mntent (struct fstab *const fstab, const struct mntent *mntent,
struct fs **result)
{
int new = 0; /* True if we didn't overwrite an old entry. */
@@ -441,7 +565,7 @@ fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
fs = mounted_fs;
mounted_fs = 0;
}
-
+
if (! fs)
/* No old entry, make a new one. */
{
@@ -462,15 +586,17 @@ fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
err = fs_set_mntent (fs, mntent);
if (new)
- if (! err)
- _fstab_add (fstab, fs);
- else if (fs)
- free (fs);
+ {
+ if (! err)
+ _fstab_add (fstab, fs);
+ else if (fs)
+ free (fs);
+ }
- if (!err && mounted_fs)
+ if (!err && mounted_fs && mounted_fs != fs)
/* Get rid of the conflicting entry MOUNTED_FS. */
fs_free (mounted_fs);
-
+
if (!err && result)
*result = fs;
@@ -481,7 +607,7 @@ fstab_add_mntent (struct fstab *fstab, struct mntent *mntent,
DST. If DST & SRC have different TYPES fields, EINVAL is returned. If
COPY is non-zero, the copy is returned in it. */
error_t
-fstab_add_fs (struct fstab *dst, struct fs *fs, struct fs **copy)
+fstab_add_fs (struct fstab *dst, const struct fs *fs, struct fs **copy)
{
error_t err;
struct fs *new;
@@ -525,7 +651,7 @@ fstab_merge (struct fstab *dst, struct fstab *src)
if (old_fs)
fs_free (old_fs);
}
-
+
/* Now that we know there are no conflicts, steal all SRC's entries and
cons them onto DST. */
for (fs = src->entries; fs; fs = fs->next)
@@ -540,7 +666,7 @@ fstab_merge (struct fstab *dst, struct fstab *src)
/* Reads fstab-format entries into FSTAB from the file NAME. Any entries
duplicating one already in FS_LIST supersede the existing entry. */
error_t
-fstab_read (struct fstab *fstab, char *name)
+fstab_read (struct fstab *fstab, const char *name)
{
error_t err;
/* Used to hold entries from the file, before merging with FSTAB at the
@@ -583,7 +709,7 @@ fstab_read (struct fstab *fstab, char *name)
/* Return the next pass number that applies to any filesystem in FSTAB that
is greater than PASS, or -1 if there isn't any. */
-int fstab_next_pass (struct fstab *fstab, int pass)
+int fstab_next_pass (const struct fstab *fstab, int pass)
{
int next_pass = -1;
struct fs *fs;
@@ -597,3 +723,262 @@ int fstab_next_pass (struct fstab *fstab, int pass)
}
return next_pass;
}
+
+
+static const struct argp_option options[] =
+{
+ {"all", 'a', 0, 0, "Do all filesystems in " _PATH_MNTTAB},
+ {0, 'A', 0, OPTION_ALIAS },
+ {"fstab", 'F', "FILE", 0, "File to use instead of " _PATH_MNTTAB},
+ {"fstype", 't', "TYPE", 0, "Do only filesystems of given type(s)"},
+ {"exclude-root",'R',0, 0,
+ "Exclude root (/) filesystem from " _PATH_MNTTAB " list"},
+ {"exclude", 'X', "PATTERN", 0, "Exclude directories matching PATTERN"},
+
+ {"search-fmts",'S', "FMTS", 0,
+ "`:' separated list of formats to use for finding"
+ " filesystem-specific programs"},
+
+ {0, 0}
+};
+
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
+{
+ error_t err;
+ struct fstab_argp_params *params = state->input;
+
+ switch (key)
+ {
+ case ARGP_KEY_INIT:
+ /* Initialize our parsing state. */
+ if (! params)
+ return EINVAL; /* Need at least a way to return a result. */
+ bzero (params, sizeof *params);
+ break;
+
+ case 'A':
+ case 'a':
+ params->do_all = 1;
+ break;
+
+ case 'F':
+ params->fstab_path = arg;
+ break;
+
+ case 'S':
+ argz_create_sep (arg, ':',
+ &params->program_search_fmts,
+ &params->program_search_fmts_len);
+ break;
+
+ case 'R':
+ arg = "/";
+ /* FALLTHROUGH */
+ case 'X':
+ err = argz_add (&params->exclude, &params->exclude_len, arg);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+ case 't':
+ err = argz_add_sep (&params->types, &params->types_len, arg, ',');
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case ARGP_KEY_ARG:
+ err = argz_add (&params->names, &params->names_len, arg);
+ if (err)
+ argp_failure (state, 100, ENOMEM, "%s", arg);
+ break;
+
+ case ARGP_KEY_END:
+ /* Check for bogus combinations of arguments. */
+ if (params->names)
+ {
+ if (params->do_all)
+ argp_error (state, "filesystem arguments not allowed with --all");
+ if (params->exclude)
+ argp_error (state,
+ "--exclude not allowed with filesystem arguments");
+ if (params->types)
+ argp_error (state,
+ "--fstype not allowed with filesystem arguments");
+ }
+ break;
+
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+
+ return 0;
+}
+
+const struct argp fstab_argp = {options, parse_opt, 0, 0};
+
+struct fstab *
+fstab_argp_create (struct fstab_argp_params *params,
+ const char *default_search_fmts,
+ size_t default_search_fmts_len)
+{
+ error_t err;
+ struct fstab *fstab, *check;
+ struct fstypes *types;
+
+ if (params->fstab_path == 0)
+ params->fstab_path = _PATH_MNTTAB;
+ if (params->program_search_fmts == 0)
+ {
+ params->program_search_fmts = (char *) default_search_fmts;
+ params->program_search_fmts_len = default_search_fmts_len;
+ }
+
+ err = fstypes_create (params->program_search_fmts,
+ params->program_search_fmts_len,
+ &types);
+ if (err)
+ error (102, err, "fstypes_create");
+
+ err = fstab_create (types, &fstab);
+ if (err)
+ error (101, err, "fstab_create");
+
+ err = fstab_read (fstab, params->fstab_path);
+ if (err)
+ error (103, err, "%s", params->fstab_path);
+
+ if (params->names)
+ {
+ /* Process specified filesystems; also look at /var/run/mtab. */
+ const char *name;
+
+ err = fstab_read (fstab, _PATH_MOUNTED);
+ if (err && err != ENOENT)
+ error (104, err, "%s", _PATH_MOUNTED);
+
+ err = fstab_create (types, &check);
+ if (err)
+ error (105, err, "fstab_create");
+
+ for (name = params->names; name; name = argz_next (params->names,
+ params->names_len,
+ name))
+ {
+ struct fs *fs = fstab_find (fstab, name);
+ if (! fs)
+ error (106, 0, "%s: Unknown device or filesystem", name);
+ fstab_add_fs (check, fs, 0);
+ }
+
+ /* fstab_free (fstab); XXX */
+ }
+ else
+ {
+ /* Process everything in /etc/fstab. */
+
+ if (params->exclude == 0 && params->types == 0)
+ check = fstab;
+ else
+ {
+ struct fs *fs;
+ const char *tn;
+ unsigned int nonexclude_types;
+
+ err = fstab_create (types, &check);
+ if (err)
+ error (105, err, "fstab_create");
+
+ /* For each excluded type (i.e. `-t notype'), clobber the
+ fstype entry's program with an empty string to mark it. */
+ nonexclude_types = 0;
+ for (tn = params->types; tn;
+ tn = argz_next (params->types, params->types_len, tn))
+ {
+ if (!strncasecmp (tn, "no", 2))
+ {
+ struct fstype *type;
+ err = fstypes_get (types, &tn[2], &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ free (type->program);
+ type->program = strdup ("");
+ }
+ else
+ ++nonexclude_types;
+ }
+
+ if (nonexclude_types != 0)
+ {
+ const char *tn;
+ struct fstypes *wanttypes;
+
+ /* We will copy the types we want to include into a fresh
+ list in WANTTYPES. Since we specify no search formats,
+ `fstypes_get' applied to WANTTYPES can only create
+ elements with a null `program' field. */
+ err = fstypes_create (0, 0, &wanttypes);
+ if (err)
+ error (102, err, "fstypes_create");
+
+ for (tn = params->types; tn;
+ tn = argz_next (params->types, params->types_len, tn))
+ if (strncasecmp (tn, "no", 2))
+ {
+ struct fstype *type;
+ err = fstypes_get (types, tn, &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ if (type->program == 0)
+ error (0, 0,
+ "requested filesystem type `%s' unknown", tn);
+ else
+ {
+ struct fstype *newtype = malloc (sizeof *newtype);
+ newtype->name = strdup (type->name);
+ newtype->program = strdup (type->program);
+ newtype->next = wanttypes->entries;
+ wanttypes->entries = newtype;
+ }
+ }
+
+ /* fstypes_free (types); */
+ types = wanttypes;
+ }
+
+ for (fs = fstab->entries; fs; fs = fs->next)
+ {
+ const char *ptn;
+ struct fstype *type;
+
+ err = fs_type (fs, &type);
+ if (err || nonexclude_types)
+ {
+ err = fstypes_get (types, fs->mntent.mnt_type, &type);
+ if (err)
+ error (106, err, "fstypes_get");
+ if (params->types != 0)
+ continue;
+ }
+ if (nonexclude_types && type->program == 0)
+ continue; /* Freshly created, was not in WANTTYPES. */
+ if (type->program != 0 && type->program[0] == '\0')
+ continue; /* This type is marked as excluded. */
+
+ for (ptn = params->exclude; ptn;
+ ptn = argz_next (params->exclude, params->exclude_len, ptn))
+ if (fnmatch (ptn, fs->mntent.mnt_dir, 0) == 0)
+ break;
+ if (ptn) /* An exclude pattern matched. */
+ continue;
+
+ err = fstab_add_fs (check, fs, 0);
+ if (err)
+ error (107, err, "fstab_add_fs");
+ }
+
+ /* fstab_free (fstab); XXX */
+ }
+ }
+
+ return check;
+}