summaryrefslogtreecommitdiffstats
path: root/utils/mount/parse_dev.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/mount/parse_dev.c')
-rw-r--r--utils/mount/parse_dev.c233
1 files changed, 233 insertions, 0 deletions
diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
new file mode 100644
index 0000000..2ade5d5
--- /dev/null
+++ b/utils/mount/parse_dev.c
@@ -0,0 +1,233 @@
+/*
+ * parse_dev.c -- parse device name into hostname and export path
+ *
+ * Copyright (C) 2008 Oracle. All rights reserved.
+ *
+ * This program 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 of the License, or (at your option) any later version.
+ *
+ * This program 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.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 0211-1301 USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "xcommon.h"
+#include "nls.h"
+#include "parse_dev.h"
+
+#ifndef NFS_MAXHOSTNAME
+#define NFS_MAXHOSTNAME (255)
+#endif
+
+#ifndef NFS_MAXPATHNAME
+#define NFS_MAXPATHNAME (1024)
+#endif
+
+extern char *progname;
+extern int verbose;
+
+static int nfs_pdn_no_devname_err(void)
+{
+ nfs_error(_("%s: no device name was provided"), progname);
+ return 0;
+}
+
+static int nfs_pdn_hostname_too_long_err(void)
+{
+ nfs_error(_("%s: server hostname is too long"), progname);
+ return 0;
+}
+
+static int nfs_pdn_pathname_too_long_err(void)
+{
+ nfs_error(_("%s: export pathname is too long"), progname);
+ return 0;
+}
+
+static int nfs_pdn_bad_format_err(void)
+{
+ nfs_error(_("%s: remote share not in 'host:dir' format"), progname);
+ return 0;
+}
+
+static int nfs_pdn_nomem_err(void)
+{
+ nfs_error(_("%s: no memory available to parse devname"), progname);
+ return 0;
+}
+
+static int nfs_pdn_missing_brace_err(void)
+{
+ nfs_error(_("%s: closing bracket missing from server address"),
+ progname);
+ return 0;
+}
+
+/*
+ * Standard hostname:path format
+ */
+static int nfs_parse_simple_hostname(const char *dev,
+ char **hostname, char **pathname)
+{
+ size_t host_len, path_len;
+ char *colon, *comma;
+
+ /* Must have a colon */
+ colon = strchr(dev, ':');
+ if (colon == NULL)
+ return nfs_pdn_bad_format_err();
+ *colon = '\0';
+ host_len = colon - dev;
+
+ if (host_len > NFS_MAXHOSTNAME)
+ return nfs_pdn_hostname_too_long_err();
+
+ /* If there's a comma before the colon, take only the
+ * first name in list */
+ comma = strchr(dev, ',');
+ if (comma != NULL) {
+ *comma = '\0';
+ host_len = comma - dev;
+ nfs_error(_("%s: warning: multiple hostnames not supported"),
+ progname);
+ } else
+
+ colon++;
+ path_len = strlen(colon);
+ if (path_len > NFS_MAXPATHNAME)
+ return nfs_pdn_pathname_too_long_err();
+
+ if (hostname) {
+ *hostname = strndup(dev, host_len);
+ if (*hostname == NULL)
+ return nfs_pdn_nomem_err();
+ }
+ if (pathname) {
+ *pathname = strndup(colon, path_len);
+ if (*pathname == NULL) {
+ if (hostname)
+ free(*hostname);
+ return nfs_pdn_nomem_err();
+ }
+ }
+ return 1;
+}
+
+/*
+ * To handle raw IPv6 addresses (which contain colons), the
+ * server's address is enclosed in square brackets. Return
+ * what's between the brackets.
+ *
+ * There could be anything in between the brackets, but we'll
+ * let DNS resolution sort it out later.
+ */
+static int nfs_parse_square_bracket(const char *dev,
+ char **hostname, char **pathname)
+{
+ size_t host_len, path_len;
+ char *cbrace;
+
+ dev++;
+
+ /* Must have a closing square bracket */
+ cbrace = strchr(dev, ']');
+ if (cbrace == NULL)
+ return nfs_pdn_missing_brace_err();
+ *cbrace = '\0';
+ host_len = cbrace - dev;
+
+ /* Must have a colon just after the closing bracket */
+ cbrace++;
+ if (*cbrace != ':')
+ return nfs_pdn_bad_format_err();
+
+ if (host_len > NFS_MAXHOSTNAME)
+ return nfs_pdn_hostname_too_long_err();
+
+ cbrace++;
+ path_len = strlen(cbrace);
+ if (path_len > NFS_MAXPATHNAME)
+ return nfs_pdn_pathname_too_long_err();
+
+ if (hostname) {
+ *hostname = strndup(dev, host_len);
+ if (*hostname == NULL)
+ return nfs_pdn_nomem_err();
+ }
+ if (pathname) {
+ *pathname = strndup(cbrace, path_len);
+ if (*pathname == NULL) {
+ if (hostname)
+ free(*hostname);
+ return nfs_pdn_nomem_err();
+ }
+ }
+ return 1;
+}
+
+/*
+ * RFC 2224 says an NFS client must grok "public file handles" to
+ * support NFS URLs. Linux doesn't do that yet. Print a somewhat
+ * helpful error message in this case instead of pressing forward
+ * with the mount request and failing with a cryptic error message
+ * later.
+ */
+static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
+ __attribute__((unused)) char **hostname,
+ __attribute__((unused)) char **pathname)
+{
+ nfs_error(_("%s: NFS URLs are not supported"), progname);
+ return 0;
+}
+
+/**
+ * nfs_parse_devname - Determine the server's hostname by looking at "devname".
+ * @devname: pointer to mounted device name (first argument of mount command)
+ * @hostname: OUT: pointer to server's hostname
+ * @pathname: OUT: pointer to export path on server
+ *
+ * Returns 1 if succesful, or zero if some error occurred. On success,
+ * @hostname and @pathname point to dynamically allocated buffers containing
+ * the hostname of the server and the export pathname (both '\0'-terminated).
+ *
+ * @hostname or @pathname may be NULL if caller doesn't want a copy of those
+ * parts of @devname.
+ *
+ * Note that this will not work if @devname is a wide-character string.
+ */
+int nfs_parse_devname(const char *devname,
+ char **hostname, char **pathname)
+{
+ char *dev;
+ int result;
+
+ if (devname == NULL)
+ return nfs_pdn_no_devname_err();
+
+ /* Parser is destructive, so operate on a copy of the device name. */
+ dev = strdup(devname);
+ if (dev == NULL)
+ return nfs_pdn_nomem_err();
+ if (*dev == '[')
+ result = nfs_parse_square_bracket(dev, hostname, pathname);
+ else if (strncmp(dev, "nfs://", 6) == 0)
+ result = nfs_parse_nfs_url(dev, hostname, pathname);
+ else
+ result = nfs_parse_simple_hostname(dev, hostname, pathname);
+
+ free(dev);
+ return result;
+}