X-Git-Url: https://git.decadent.org.uk/gitweb/?p=nfs-utils.git;a=blobdiff_plain;f=utils%2Fmount%2Fparse_dev.c;fp=utils%2Fmount%2Fparse_dev.c;h=c0a8e18ecece9fae0900c9b9a92cd819521a2adf;hp=0000000000000000000000000000000000000000;hb=1d61a1116198714f50b081daecc663625124403d;hpb=586a66451679e25c47cb8cd65a0c6a0c44148920 diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c new file mode 100644 index 0000000..c0a8e18 --- /dev/null +++ b/utils/mount/parse_dev.c @@ -0,0 +1,230 @@ +/* + * 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., 59 Temple Place - Suite 330, + * Boston, MA 021110-1307, USA. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#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) { + 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) { + 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(const char *dev, + char **hostname, 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; +}