diff options
Diffstat (limited to 'sutils/fstab.c')
-rw-r--r-- | sutils/fstab.c | 956 |
1 files changed, 956 insertions, 0 deletions
diff --git a/sutils/fstab.c b/sutils/fstab.c new file mode 100644 index 00000000..4574d41d --- /dev/null +++ b/sutils/fstab.c @@ -0,0 +1,956 @@ +/* Fstab filesystem frobbing + + Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc. + + Written by Miles Bader <miles@gnu.ai.mit.edu> + + This file is part of the GNU Hurd. + + The GNU Hurd is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2, or (at + your option) any later version. + + The GNU Hurd is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include <stdlib.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> +#include <fcntl.h> +#include <error.h> +#include <argz.h> +#include <argp.h> +#include <fnmatch.h> + +#include <hurd/fsys.h> + +#include "fstab.h" + +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_update (fsys_t fsys); + +extern file_t file_name_lookup_carefully (const char *file, + int flags, mode_t mode); + +/* Return a new fstab in FSTAB. */ +error_t +fstab_create (struct fstypes *types, struct fstab **fstab) +{ + struct fstab *new = malloc (sizeof (struct fstab)); + if (new) + { + new->entries = 0; + new->types = types; + *fstab = new; + return 0; + } + else + return ENOMEM; +} + +/* Free FSTAB and all of its entries. */ +void +fstab_free (struct fstab *fstab) +{ + while (fstab->entries) + fs_free (fstab->entries); + free (fstab); +} + +/* Return a new fstypes structure in TYPES. SEARCH_FMTS is copied. */ +error_t +fstypes_create (const char *search_fmts, size_t search_fmts_len, + struct fstypes **types) +{ + struct fstypes *new = malloc (sizeof (struct fstypes)); + if (new) + { + new->entries = 0; + new->program_search_fmts = malloc (search_fmts_len); + new->program_search_fmts_len = search_fmts_len; + if (! new->program_search_fmts) + { + free (types); + return ENOMEM; + } + bcopy (search_fmts, new->program_search_fmts, search_fmts_len); + *types = new; + return 0; + } + else + return ENOMEM; +} + +/* Return an fstype entry in TYPES called NAME, in FSTYPE. If there is no + existing entry, an attempt to find a fsck program with the given type, + using the alternatives in the FSCK_SEARCH_FMTS field in TYPES. If + 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, 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) + { + *fstype = type; + return 0; + } + + /* No existing entry, make a new one. */ + + fmts = types->program_search_fmts; + fmts_len = types->program_search_fmts_len; + + for (fmt = fmts; fmt; fmt = argz_next (fmts, fmts_len, fmt)) + { + int fd; + + asprintf (&program, fmt, name); + fd = open (program, O_EXEC); + if (fd < 0) + { + free (program); /* Failed. */ + if (errno != ENOENT && errno != EACCES) + /* The program's there but something went wrong; fail. */ + return errno; + } + else + /* We can open for exec, but check the stat info too (e.g. root can + open everything). */ + { + struct stat stat; + int rv = fstat (fd, &stat); + + close (fd); + + if (rv < 0) + { + 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, const struct mntent *mntent) +{ + char *end; + size_t needed = 0; + + if (fs->storage) + free (fs->storage); + + /* Allocate space for all string mntent fields in FS. */ +#define COUNT(field) if (mntent->field) needed += strlen (mntent->field) + 1; + COUNT (mnt_fsname); + COUNT (mnt_dir); + COUNT (mnt_type); + COUNT (mnt_opts); +#undef COUNT + + fs->storage = malloc (needed); + if (! fs->storage) + return ENOMEM; + + 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) + mach_port_deallocate (mach_task_self (), fs->fsys); + fs->fsys = MACH_PORT_NULL; + } + + /* Copy MNTENT into FS; string-valued fields will be fixed up next. */ + fs->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 + STORE (mnt_fsname); + STORE (mnt_dir); + STORE (mnt_type); + STORE (mnt_opts); +#undef STORE + + 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 fill in FS's type field if + necessary. */ +error_t +fs_type (struct fs *fs, struct fstype **type) +{ + error_t err = 0; + if (! fs->type) + err = fstypes_get (fs->fstab->types, fs->mntent.mnt_type, &fs->type); + if (! err) + *type = fs->type; + return err; +} + +/* Looks to see if FS is currently mounted, being very careful to avoid + mounting anything that's not already, and fills in the fsys & mounted + fields in FS. */ +static error_t +_fs_check_mounted (struct fs *fs) +{ + error_t err = 0; + + if (fs->mounted < 0) + /* The mounted field in FS is -1 if we're not sure. */ + { + if (fs->fsys != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), fs->fsys); + + if (strcmp (fs->mntent.mnt_dir, "/") == 0) + /* The root is always mounted. Get its control port. */ + { + file_t root = getcrdir (); + if (root == MACH_PORT_NULL) + err = errno; + else + { + err = file_getcontrol (root, &fs->fsys); + mach_port_deallocate (mach_task_self (), root); + } + } + else + { + file_t mount_point = + file_name_lookup_carefully (fs->mntent.mnt_dir, O_NOTRANS, 0); + + if (mount_point != MACH_PORT_NULL) + /* The node exists. Is it the root of an active translator? + [Note that it could be a different translator than the one in + 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 || err == ENXIO) + /* Either the mount point doesn't exist, or wasn't mounted. */ + { + fs->fsys = MACH_PORT_NULL; + err = 0; + } + } + else if (errno == ENXIO) + /* Ran into an inactive passive translator. FS can't be mounted. */ + { + fs->fsys = MACH_PORT_NULL; + err = 0; + } + } + + if (! err) + fs->mounted = (fs->fsys != MACH_PORT_NULL); + } + + return err; +} + +/* Looks to see if FS is currently mounted, being very careful to avoid + mounting anything that's not already, and returns the control port for the + mounted filesystem (MACH_PORT_NULL if not mounted). */ +error_t +fs_fsys (struct fs *fs, fsys_t *fsys) +{ + error_t err = _fs_check_mounted (fs); + if (!err && fsys) + *fsys = fs->fsys; + return err; +} + +/* Looks to see if FS is currently mounted, being very careful to avoid + mounting anything that's not already, and returns the boolean MOUNTED. */ +error_t +fs_mounted (struct fs *fs, int *mounted) +{ + error_t err = _fs_check_mounted (fs); + if (!err && mounted) + *mounted = fs->mounted; + return err; +} + +/* Looks to see if FS is currently mounted readonly, being very careful to + avoid mounting anything that's not already, and returns the boolean + READONLY. If FS isn't mounted at all, READONLY is set to 1 (it's not + going to write anything!). */ +error_t +fs_readonly (struct fs *fs, int *readonly) +{ + error_t err = 0; + + if (fs->readonly < 0) + /* Unknown. */ + { + fsys_t fsys; + + err = fs_fsys (fs, &fsys); + if (! err) + { + if (fsys == MACH_PORT_NULL) + fs->readonly = 1; + else + err = fsys_get_readonly (fsys, &fs->readonly); + } + } + + if (!err && readonly) + *readonly = fs->readonly; + + return err; +} + +/* If FS is currently mounted writable, try to make it readonly. XXX If FS + is not mounted at all, then nothing is done. */ +error_t +fs_set_readonly (struct fs *fs, int readonly) +{ + int currently_readonly; + error_t err = fs_readonly (fs, ¤tly_readonly); + + readonly = !!readonly; + + if (!err && readonly != currently_readonly) + /* We have to try and change the readonly state. */ + { + fsys_t fsys; + err = fs_fsys (fs, &fsys); + if (!err && fsys != MACH_PORT_NULL) /* XXX What to do if not mounted? */ + err = fsys_set_readonly (fsys, readonly); + if (! err) + fs->readonly = readonly; + } + + return err; +} + +/* 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) +{ + 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_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 (const struct fstab *fstab, const char *name) +{ + struct fs *fs; + for (fs = fstab->entries; fs; fs = fs->next) + if (strcmp (fs->mntent.mnt_fsname, name) == 0) + return fs; + return 0; +} + +/* Returns the FS entry in FSTAB with the mount point NAME (there can only + be one such entry). */ +inline struct fs * +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; + return 0; +} + +/* 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 (const struct fstab *fstab, const char *name) +{ + return fstab_find_device (fstab, name) ?: fstab_find_mount (fstab, name); +} + +/* Cons FS onto the beginning of FSTAB's entry list. */ +static void +_fstab_add (struct fstab *fstab, struct fs *fs) +{ + fs->fstab = fstab; + fs->next = fstab->entries; + fs->self = &fstab->entries; + if (fstab->entries) + fstab->entries->self = &fs->next; + fstab->entries = fs; +} + +/* Destroy FS, removing it from its containing FSTAB. */ +void +fs_free (struct fs *fs) +{ + *fs->self = fs->next; /* unlink from chain */ + if (fs->storage) + free (fs->storage); + if (fs->fsys != MACH_PORT_NULL) + mach_port_deallocate (mach_task_self (), fs->fsys); + free (fs); +} + +/* Add an entry for MNTENT to FSTAB, removing any existing entries that + 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 *const fstab, const struct mntent *mntent, + struct fs **result) +{ + int new = 0; /* True if we didn't overwrite an old entry. */ + error_t err = 0; + struct fs *fs = fstab_find_device (fstab, mntent->mnt_fsname); + struct fs *mounted_fs = fstab_find_mount (fstab, mntent->mnt_dir); + + if (! fs) + /* No old entry with the same device; see if there's one with the same + mount point. */ + { + fs = mounted_fs; + mounted_fs = 0; + } + + if (! fs) + /* No old entry, make a new one. */ + { + fs = malloc (sizeof (struct fs)); + if (fs) + { + bzero (fs, sizeof (struct fs)); + fs->mounted = fs->readonly = -1; + fs->fsys = MACH_PORT_NULL; + new = 1; + } + else + err = ENOMEM; + } + + if (! err) + /* Try and fill in FS's mntent. */ + err = fs_set_mntent (fs, mntent); + + if (new) + { + if (! err) + _fstab_add (fstab, fs); + else if (fs) + free (fs); + } + + if (!err && mounted_fs) + /* Get rid of the conflicting entry MOUNTED_FS. */ + fs_free (mounted_fs); + + if (!err && result) + *result = fs; + + return err; +} + +/* Copy the entry FS (which should belong to another fstab than DST) into + 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, const struct fs *fs, struct fs **copy) +{ + error_t err; + struct fs *new; + struct fstab *src = fs->fstab; + + if (dst->types != src->types) + return EINVAL; + + err = fstab_add_mntent (dst, &fs->mntent, &new); + if (err) + return err; + + new->type = fs->type; + + if (copy) + *copy = new; + + return 0; +} + +/* Merge SRC into DST, as if by calling fstab_add_fs on DST with every + entry in SRC, and then deallocating SRC. If DST & SRC have different + TYPES fields, EINVAL is returned. */ +error_t +fstab_merge (struct fstab *dst, struct fstab *src) +{ + struct fs *fs; + + if (dst->types != src->types) + return EINVAL; + + /* Remove entries in DST which conflict with those in SRC. */ + for (fs = src->entries; fs; fs = fs->next) + { + struct fs *old_fs; + + old_fs = fstab_find_device (dst, fs->mntent.mnt_fsname); + if (old_fs) + fs_free (old_fs); + old_fs = fstab_find_mount (dst, fs->mntent.mnt_dir); + 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) + _fstab_add (dst, fs); + + /* Now all entries from SRC should be in DST, so just deallocate SRC. */ + free (src); + + return 0; +} + +/* 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, const char *name) +{ + error_t err; + /* Used to hold entries from the file, before merging with FSTAB at the + end. */ + struct fstab *contents; + FILE *stream = setmntent (name, "r"); + + if (! stream) + return errno; + + err = fstab_create (fstab->types, &contents); + if (! err) + { + while (!err && !feof (stream)) + { + struct mntent *mntent = getmntent (stream); + + if (! mntent) + err = errno; + else if (fstab_find_device (fstab, mntent->mnt_fsname)) + error (0, 0, "%s: Warning: duplicate entry for device %s (%s)", + name, mntent->mnt_fsname, mntent->mnt_dir); + else if (fstab_find_mount (fstab, mntent->mnt_dir)) + error (0, 0, "%s: Warning: duplicate entry for mount point %s (%s)", + name, mntent->mnt_dir, mntent->mnt_fsname); + else + err = fstab_add_mntent (fstab, mntent, 0); + } + + if (! err) + fstab_merge (fstab, contents); + else + fstab_free (contents); + } + + endmntent (stream); + + return err; +} + +/* 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 (const struct fstab *fstab, int pass) +{ + int next_pass = -1; + struct fs *fs; + for (fs = fstab->entries; fs; fs = fs->next) + if (fs->mntent.mnt_passno > pass) + if (next_pass < 0 || fs->mntent.mnt_passno < next_pass) + { + next_pass = fs->mntent.mnt_passno; + if (next_pass == pass + 1) + break; /* Only possible answer. */ + } + 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, ':', + ¶ms->program_search_fmts, + ¶ms->program_search_fmts_len); + break; + + case 'R': + arg = "/"; + /* FALLTHROUGH */ + case 'X': + err = argz_add (¶ms->exclude, ¶ms->exclude_len, arg); + if (err) + argp_failure (state, 100, ENOMEM, "%s", arg); + break; + case 't': + err = argz_add_sep (¶ms->types, ¶ms->types_len, arg, ','); + if (err) + argp_failure (state, 100, ENOMEM, "%s", arg); + break; + + case ARGP_KEY_ARG: + err = argz_add (¶ms->names, ¶ms->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; +} |