| /* |
| * 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 <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) { |
| 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(__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; |
| } |