/* * 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 #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; }