summaryrefslogtreecommitdiff
path: root/src/rc/mountinfo.c
diff options
context:
space:
mode:
authorRoy Marples <roy@marples.name>2008-01-05 19:25:55 +0000
committerRoy Marples <roy@marples.name>2008-01-05 19:25:55 +0000
commitac21d75300dabe83578e4373fcfd09d67c3a083b (patch)
treed5f8e2a16920add2277c79ff8a1b7e99ec2976df /src/rc/mountinfo.c
parent112fbde453d55c49b7999d2e35496a8758aaa7b5 (diff)
downloadopenrc-ac21d75300dabe83578e4373fcfd09d67c3a083b.tar.gz
openrc-ac21d75300dabe83578e4373fcfd09d67c3a083b.tar.bz2
openrc-ac21d75300dabe83578e4373fcfd09d67c3a083b.tar.xz
Add some .mk stubs to impersonate bsk .mk files to make writing our Makefiles easier. libeinfo, librc and rc now have their own seperate directories. More work is needed to tidy this up though.
Diffstat (limited to 'src/rc/mountinfo.c')
-rw-r--r--src/rc/mountinfo.c464
1 files changed, 464 insertions, 0 deletions
diff --git a/src/rc/mountinfo.c b/src/rc/mountinfo.c
new file mode 100644
index 0000000..05ce8dd
--- /dev/null
+++ b/src/rc/mountinfo.c
@@ -0,0 +1,464 @@
+/*
+ mountinfo.c
+ Obtains information about mounted filesystems.
+ */
+
+/*
+ * Copyright 2007 Roy Marples
+ * All rights reserved
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/types.h>
+
+#if defined(__DragonFly__) || defined(__FreeBSD__) || \
+ defined(__NetBSD__) || defined(__OpenBSD__)
+#define BSD
+#include <sys/param.h>
+#include <sys/ucred.h>
+#include <sys/mount.h>
+#elif defined (__linux__)
+#include <mntent.h>
+#endif
+
+#include <errno.h>
+#include <getopt.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <regex.h>
+
+#include "builtins.h"
+#include "einfo.h"
+#include "rc.h"
+#include "rc-misc.h"
+#include "strlist.h"
+
+static const char *applet;
+
+typedef enum {
+ mount_from,
+ mount_to,
+ mount_fstype,
+ mount_options
+} mount_type;
+
+typedef enum {
+ net_ignore,
+ net_yes,
+ net_no
+} net_opts;
+
+struct args {
+ regex_t *node_regex;
+ regex_t *skip_node_regex;
+ regex_t *fstype_regex;
+ regex_t *skip_fstype_regex;
+ regex_t *options_regex;
+ regex_t *skip_options_regex;
+ char **mounts;
+ mount_type mount_type;
+ net_opts netdev;
+};
+
+static int process_mount (char ***list, struct args *args,
+ char *from, char *to, char *fstype, char *options,
+ int netdev)
+{
+ char *p;
+
+ errno = ENOENT;
+
+#ifdef __linux__
+ /* Skip the really silly rootfs */
+ if (strcmp (fstype, "rootfs") == 0)
+ return (-1);
+#endif
+
+ if (args->netdev == net_yes && (netdev != -1 || args->mounts)) {
+ if (netdev != 0)
+ return (1);
+ } else if (args->netdev == net_no && (netdev != -1 || args->mounts)) {
+ if (netdev != 1)
+ return (1);
+ } else {
+ if (args->node_regex &&
+ regexec (args->node_regex, from, 0, NULL, 0) != 0)
+ return (1);
+ if (args->skip_node_regex &&
+ regexec (args->skip_node_regex, from, 0, NULL, 0) == 0)
+ return (1);
+
+ if (args->fstype_regex &&
+ regexec (args->fstype_regex, fstype, 0, NULL, 0) != 0)
+ return (-1);
+ if (args->skip_fstype_regex &&
+ regexec (args->skip_fstype_regex, fstype, 0, NULL, 0) == 0)
+ return (-1);
+
+ if (args->options_regex &&
+ regexec (args->options_regex, options, 0, NULL, 0) != 0)
+ return (-1);
+ if (args->skip_options_regex &&
+ regexec (args->skip_options_regex, options, 0, NULL, 0) == 0)
+ return (-1);
+ }
+
+ if (args->mounts) {
+ bool found = false;
+ int j;
+ char *mnt;
+ STRLIST_FOREACH (args->mounts, mnt, j)
+ if (strcmp (mnt, to) == 0) {
+ found = true;
+ break;
+ }
+ if (! found)
+ return (-1);
+ }
+
+ switch (args->mount_type) {
+ case mount_from:
+ p = from;
+ break;
+ case mount_to:
+ p = to;
+ break;
+ case mount_fstype:
+ p = fstype;
+ break;
+ case mount_options:
+ p = options;
+ break;
+ default:
+ p = NULL;
+ errno = EINVAL;
+ break;
+ }
+
+ if (p) {
+ errno = 0;
+ rc_strlist_addsortc (list, p);
+ return (0);
+ }
+
+ return (-1);
+}
+
+#ifdef BSD
+
+/* Translate the mounted options to english
+ * This is taken directly from FreeBSD mount.c */
+static struct opt {
+ int o_opt;
+ const char *o_name;
+} optnames[] = {
+ { MNT_ASYNC, "asynchronous" },
+ { MNT_EXPORTED, "NFS exported" },
+ { MNT_LOCAL, "local" },
+ { MNT_NOATIME, "noatime" },
+ { MNT_NOEXEC, "noexec" },
+ { MNT_NOSUID, "nosuid" },
+ { MNT_NOSYMFOLLOW, "nosymfollow" },
+ { MNT_QUOTA, "with quotas" },
+ { MNT_RDONLY, "read-only" },
+ { MNT_SYNCHRONOUS, "synchronous" },
+ { MNT_UNION, "union" },
+ { MNT_NOCLUSTERR, "noclusterr" },
+ { MNT_NOCLUSTERW, "noclusterw" },
+ { MNT_SUIDDIR, "suiddir" },
+ { MNT_SOFTDEP, "soft-updates" },
+ { MNT_MULTILABEL, "multilabel" },
+ { MNT_ACLS, "acls" },
+#ifdef MNT_GJOURNAL
+ { MNT_GJOURNAL, "gjournal" },
+#endif
+ { 0, NULL }
+};
+
+static char **find_mounts (struct args *args)
+{
+ struct statfs *mnts;
+ int nmnts;
+ int i;
+ char **list = NULL;
+ char *options = NULL;
+ int flags;
+ struct opt *o;
+
+ if ((nmnts = getmntinfo (&mnts, MNT_NOWAIT)) == 0)
+ eerrorx ("getmntinfo: %s", strerror (errno));
+
+ for (i = 0; i < nmnts; i++) {
+ int netdev = 0;
+ flags = mnts[i].f_flags & MNT_VISFLAGMASK;
+ for (o = optnames; flags && o->o_opt; o++) {
+ if (flags & o->o_opt) {
+ if (o->o_opt == MNT_LOCAL)
+ netdev = 1;
+ if (! options)
+ options = xstrdup (o->o_name);
+ else {
+ char *tmp = NULL;
+ int l = strlen (options) + strlen (o->o_name) + 2;
+ tmp = xmalloc (sizeof (char) * l);
+ snprintf (tmp, l, "%s,%s", options, o->o_name);
+ free (options);
+ options = tmp;
+ }
+ }
+ flags &= ~o->o_opt;
+ }
+
+ process_mount (&list, args,
+ mnts[i].f_mntfromname,
+ mnts[i].f_mntonname,
+ mnts[i].f_fstypename,
+ options,
+ netdev);
+
+ free (options);
+ options = NULL;
+ }
+
+ return (list);
+}
+
+#elif defined (__linux__)
+static struct mntent *getmntfile (const char *file)
+{
+ struct mntent *ent = NULL;
+ FILE *fp;
+
+ fp = setmntent ("/etc/fstab", "r");
+ while ((ent = getmntent (fp)))
+ if (strcmp (file, ent->mnt_dir) == 0)
+ break;
+ endmntent (fp);
+
+ return (ent);
+}
+
+static char **find_mounts (struct args *args)
+{
+ FILE *fp;
+ char *buffer;
+ char *p;
+ char *from;
+ char *to;
+ char *fst;
+ char *opts;
+ char **list = NULL;
+ struct mntent *ent;
+ int netdev;
+
+ if ((fp = fopen ("/proc/mounts", "r")) == NULL)
+ eerrorx ("getmntinfo: %s", strerror (errno));
+
+ buffer = xmalloc (sizeof (char) * PATH_MAX * 3);
+ while (fgets (buffer, PATH_MAX * 3, fp)) {
+ netdev = -1;
+ p = buffer;
+ from = strsep (&p, " ");
+ to = strsep (&p, " ");
+ fst = strsep (&p, " ");
+ opts = strsep (&p, " ");
+
+ if ((ent = getmntfile (to))) {
+ if (strstr (ent->mnt_opts, "_netdev"))
+ netdev = 0;
+ }
+
+ process_mount (&list, args, from, to, fst, opts, netdev);
+ }
+ free (buffer);
+ fclose (fp);
+
+ return (list);
+}
+
+#else
+# error "Operating system not supported!"
+#endif
+
+static regex_t *get_regex (const char *string)
+{
+ regex_t *reg = xmalloc (sizeof (regex_t));
+ int result;
+ char buffer[256];
+
+ if ((result = regcomp (reg, string, REG_EXTENDED | REG_NOSUB)) != 0)
+ {
+ regerror (result, reg, buffer, sizeof (buffer));
+ eerrorx ("%s: invalid regex `%s'", applet, buffer);
+ }
+
+ return (reg);
+}
+
+#include "_usage.h"
+#define extraopts "[mount1] [mount2] ..."
+#define getoptstring "f:F:n:N:o:O:p:P:ist" getoptstring_COMMON
+static struct option longopts[] = {
+ { "fstype-regex", 1, NULL, 'f'},
+ { "skip-fstype-regex", 1, NULL, 'F'},
+ { "node-regex", 1, NULL, 'n'},
+ { "skip-node-regex", 1, NULL, 'N'},
+ { "options-regex", 1, NULL, 'o'},
+ { "skip-options-regex", 1, NULL, 'O'},
+ { "point-regex", 1, NULL, 'p'},
+ { "skip-point-regex", 1, NULL, 'P'},
+ { "options", 0, NULL, 'i'},
+ { "fstype", 0, NULL, 's'},
+ { "node", 0, NULL, 't'},
+ { "netdev", 0, NULL, 'e'},
+ { "nonetdev", 0, NULL, 'E'},
+ longopts_COMMON
+};
+static const char * const longopts_help[] = {
+ "fstype regex to find",
+ "fstype regex to skip",
+ "node regex to find",
+ "node regex to skip",
+ "options regex to find",
+ "options regex to skip",
+ "point regex to find",
+ "point regex to skip",
+ "print options",
+ "print fstype",
+ "print node",
+ "is it a network device",
+ "is it not a network device",
+ longopts_help_COMMON
+};
+#include "_usage.c"
+
+int mountinfo (int argc, char **argv)
+{
+ int i;
+ struct args args;
+ regex_t *point_regex = NULL;
+ regex_t *skip_point_regex = NULL;
+ char **nodes = NULL;
+ char *n;
+ int opt;
+ int result;
+ bool quiet;
+
+ /* Ensure that we are only quiet when explicitly told to be */
+ unsetenv ("EINFO_QUIET");
+
+#define DO_REG(_var) \
+ if (_var) free (_var); \
+ _var = get_regex (optarg);
+#define REG_FREE(_var) \
+ if (_var) { regfree (_var); free (_var); }
+
+ memset (&args, 0, sizeof (struct args));
+ args.mount_type = mount_to;
+ args.netdev = net_ignore;
+
+ while ((opt = getopt_long (argc, argv, getoptstring,
+ longopts, (int *) 0)) != -1)
+ {
+ switch (opt) {
+ case 'e':
+ args.netdev = net_yes;
+ break;
+ case 'E':
+ args.netdev = net_no;
+ break;
+ case 'f':
+ DO_REG (args.fstype_regex);
+ break;
+ case 'F':
+ DO_REG (args.skip_fstype_regex);
+ break;
+ case 'n':
+ DO_REG (args.node_regex);
+ break;
+ case 'N':
+ DO_REG (args.skip_node_regex);
+ break;
+ case 'o':
+ DO_REG (args.options_regex);
+ break;
+ case 'O':
+ DO_REG (args.skip_options_regex);
+ break;
+ case 'p':
+ DO_REG (point_regex);
+ break;
+ case 'P':
+ DO_REG (skip_point_regex);
+ break;
+ case 'i':
+ args.mount_type = mount_options;
+ break;
+ case 's':
+ args.mount_type = mount_fstype;
+ break;
+ case 't':
+ args.mount_type = mount_from;
+ break;
+
+ case_RC_COMMON_GETOPT
+ }
+ }
+
+ while (optind < argc) {
+ if (argv[optind][0] != '/')
+ eerrorx ("%s: `%s' is not a mount point", argv[0], argv[optind]);
+ rc_strlist_add (&args.mounts, argv[optind++]);
+ }
+
+ nodes = find_mounts (&args);
+
+ REG_FREE (args.fstype_regex);
+ REG_FREE (args.skip_fstype_regex);
+ REG_FREE (args.node_regex);
+ REG_FREE (args.skip_node_regex);
+ REG_FREE (args.options_regex);
+ REG_FREE (args.skip_options_regex);
+
+ rc_strlist_reverse (nodes);
+
+ result = EXIT_FAILURE;
+ quiet = rc_yesno (getenv ("EINFO_QUIET"));
+ STRLIST_FOREACH (nodes, n, i) {
+ if (point_regex && regexec (point_regex, n, 0, NULL, 0) != 0)
+ continue;
+ if (skip_point_regex && regexec (skip_point_regex, n, 0, NULL, 0) == 0)
+ continue;
+ if (! quiet)
+ printf ("%s\n", n);
+ result = EXIT_SUCCESS;
+ }
+ rc_strlist_free (nodes);
+
+ REG_FREE (point_regex);
+ REG_FREE (skip_point_regex);
+
+ exit (result);
+}