]> git.decadent.org.uk Git - nfs-utils.git/blob - utils/mount/parse_dev.c
supress socket error when address family is not supported
[nfs-utils.git] / utils / mount / parse_dev.c
1 /*
2  * parse_dev.c -- parse device name into hostname and export path
3  *
4  * Copyright (C) 2008 Oracle.  All rights reserved.
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public
17  * License along with this program; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 021110-1307, USA.
20  *
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include <config.h>
25 #endif
26
27 #include "xcommon.h"
28 #include "nls.h"
29 #include "parse_dev.h"
30
31 #ifndef NFS_MAXHOSTNAME
32 #define NFS_MAXHOSTNAME         (255)
33 #endif
34
35 #ifndef NFS_MAXPATHNAME
36 #define NFS_MAXPATHNAME         (1024)
37 #endif
38
39 extern char *progname;
40 extern int verbose;
41
42 static int nfs_pdn_no_devname_err(void)
43 {
44         nfs_error(_("%s: no device name was provided"), progname);
45         return 0;
46 }
47
48 static int nfs_pdn_hostname_too_long_err(void)
49 {
50         nfs_error(_("%s: server hostname is too long"), progname);
51         return 0;
52 }
53
54 static int nfs_pdn_pathname_too_long_err(void)
55 {
56         nfs_error(_("%s: export pathname is too long"), progname);
57         return 0;
58 }
59
60 static int nfs_pdn_bad_format_err(void)
61 {
62         nfs_error(_("%s: remote share not in 'host:dir' format"), progname);
63         return 0;
64 }
65
66 static int nfs_pdn_nomem_err(void)
67 {
68         nfs_error(_("%s: no memory available to parse devname"), progname);
69         return 0;
70 }
71
72 static int nfs_pdn_missing_brace_err(void)
73 {
74         nfs_error(_("%s: closing bracket missing from server address"),
75                                 progname);
76         return 0;
77 }
78
79 /*
80  * Standard hostname:path format
81  */
82 static int nfs_parse_simple_hostname(const char *dev,
83                                      char **hostname, char **pathname)
84 {
85         size_t host_len, path_len;
86         char *colon, *comma;
87
88         /* Must have a colon */
89         colon = strchr(dev, ':');
90         if (colon == NULL)
91                 return nfs_pdn_bad_format_err();
92         *colon = '\0';
93         host_len = colon - dev;
94
95         if (host_len > NFS_MAXHOSTNAME)
96                 return nfs_pdn_hostname_too_long_err();
97
98         /* If there's a comma before the colon, take only the
99          * first name in list */
100         comma = strchr(dev, ',');
101         if (comma != NULL) {
102                 *comma = '\0';
103                 host_len = comma - dev;
104                 nfs_error(_("%s: warning: multiple hostnames not supported"),
105                                 progname);
106         } else
107
108         colon++;
109         path_len = strlen(colon);
110         if (path_len > NFS_MAXPATHNAME)
111                 return nfs_pdn_pathname_too_long_err();
112
113         if (hostname) {
114                 *hostname = strndup(dev, host_len);
115                 if (*hostname == NULL)
116                         return nfs_pdn_nomem_err();
117         }
118         if (pathname) {
119                 *pathname = strndup(colon, path_len);
120                 if (*pathname == NULL) {
121                         free(*hostname);
122                         return nfs_pdn_nomem_err();
123                 }
124         }
125         return 1;
126 }
127
128 /*
129  * To handle raw IPv6 addresses (which contain colons), the
130  * server's address is enclosed in square brackets.  Return
131  * what's between the brackets.
132  *
133  * There could be anything in between the brackets, but we'll
134  * let DNS resolution sort it out later.
135  */
136 static int nfs_parse_square_bracket(const char *dev,
137                                     char **hostname, char **pathname)
138 {
139         size_t host_len, path_len;
140         char *cbrace;
141
142         dev++;
143
144         /* Must have a closing square bracket */
145         cbrace = strchr(dev, ']');
146         if (cbrace == NULL)
147                 return nfs_pdn_missing_brace_err();
148         *cbrace = '\0';
149         host_len = cbrace - dev;
150
151         /* Must have a colon just after the closing bracket */
152         cbrace++;
153         if (*cbrace != ':')
154                 return nfs_pdn_bad_format_err();
155
156         if (host_len > NFS_MAXHOSTNAME)
157                 return nfs_pdn_hostname_too_long_err();
158
159         cbrace++;
160         path_len = strlen(cbrace);
161         if (path_len > NFS_MAXPATHNAME)
162                 return nfs_pdn_pathname_too_long_err();
163
164         if (hostname) {
165                 *hostname = strndup(dev, host_len);
166                 if (*hostname == NULL)
167                         return nfs_pdn_nomem_err();
168         }
169         if (pathname) {
170                 *pathname = strndup(cbrace, path_len);
171                 if (*pathname == NULL) {
172                         free(*hostname);
173                         return nfs_pdn_nomem_err();
174                 }
175         }
176         return 1;
177 }
178
179 /*
180  * RFC 2224 says an NFS client must grok "public file handles" to
181  * support NFS URLs.  Linux doesn't do that yet.  Print a somewhat
182  * helpful error message in this case instead of pressing forward
183  * with the mount request and failing with a cryptic error message
184  * later.
185  */
186 static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
187                              __attribute__((unused)) char **hostname,
188                              __attribute__((unused)) char **pathname)
189 {
190         nfs_error(_("%s: NFS URLs are not supported"), progname);
191         return 0;
192 }
193
194 /**
195  * nfs_parse_devname - Determine the server's hostname by looking at "devname".
196  * @devname: pointer to mounted device name (first argument of mount command)
197  * @hostname: OUT: pointer to server's hostname
198  * @pathname: OUT: pointer to export path on server
199  *
200  * Returns 1 if succesful, or zero if some error occurred.  On success,
201  * @hostname and @pathname point to dynamically allocated buffers containing
202  * the hostname of the server and the export pathname (both '\0'-terminated).
203  *
204  * @hostname or @pathname may be NULL if caller doesn't want a copy of those
205  * parts of @devname.
206  *
207  * Note that this will not work if @devname is a wide-character string.
208  */
209 int nfs_parse_devname(const char *devname,
210                       char **hostname, char **pathname)
211 {
212         char *dev;
213         int result;
214
215         if (devname == NULL)
216                 return nfs_pdn_no_devname_err();
217
218         /* Parser is destructive, so operate on a copy of the device name. */
219         dev = strdup(devname);
220         if (dev == NULL)
221                 return nfs_pdn_nomem_err();
222         if (*dev == '[')
223                 result = nfs_parse_square_bracket(dev, hostname, pathname);
224         else if (strncmp(dev, "nfs://", 6) == 0)
225                 result = nfs_parse_nfs_url(dev, hostname, pathname);
226         else
227                 result = nfs_parse_simple_hostname(dev, hostname, pathname);
228
229         free(dev);
230         return result;
231 }