pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS

Difference between
modified post 398f8 by Anonymous on Sat 2nd Nov 2024 13:39
original post b5f2185 by Anonymous on Fri 1st Nov 2024 10:59
Download diff
Show old version | new version | both versions

    
11
diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
22
index 5ff1148c..ad1d0884 100644
33
--- a/utils/mount/Makefile.am
44
+++ b/utils/mount/Makefile.am
55
@@ -13,7 +13,8 @@ sbin_PROGRAMS	= mount.nfs
66
 EXTRA_DIST = nfsmount.conf $(man8_MANS) $(man5_MANS)
77
 mount_common = error.c network.c token.c \
88
 		    parse_opt.c parse_dev.c \
99
-		    nfsmount.c nfs4mount.c stropts.c\
1010
+		    nfsmount.c nfs4mount.c \
1111
+		    urlparser1.c urlparser1.h stropts.c \
1212
 		    mount_constants.h error.h network.h token.h \
1313
 		    parse_opt.h parse_dev.h \
1414
 		    nfs4_mount.h stropts.h version.h \
1515
diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
16-
index 0fe142a7..20199f65 100644
16+
index 0fe142a7..8e4fbf30 100644
1717
--- a/utils/mount/nfs4mount.c
1818
+++ b/utils/mount/nfs4mount.c
1919
@@ -50,8 +50,10 @@
2020
 #include "mount_constants.h"
2121
 #include "nfs4_mount.h"
2222
 #include "nfs_mount.h"
2323
+#include "urlparser1.h"
2424
 #include "error.h"
2525
 #include "network.h"
2626
+#include "utils.h"
2727
2828
 #if defined(VAR_LOCK_DIR)
2929
 #define DEFAULT_DIR VAR_LOCK_DIR
30-
@@ -192,15 +194,120 @@ int nfs4mount(const char *spec, const char *node, int flags,
30+
@@ -182,7 +184,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
31+
 	int num_flavour = 0;
3633
37-
 	if (strlen(spec) >= sizeof(hostdir)) {
34+
-	char *hostname, *dirname, *old_opts;
38-
 		nfs_error(_("%s: excessively long host:dir argument\n"),
35+
+	char *hostname, *dirname, *mb_dirname = NULL, *old_opts;
39-
 				progname);
36+
 	char new_opts[1024];
40-
 		goto fail;
37+
 	char *opt, *opteq;
41-
 	}
38+
 	char *s;
42-
-	strcpy(hostdir, spec);
39+
@@ -192,15 +194,66 @@ int nfs4mount(const char *spec, const char *node, int flags,
43-
-	if (parse_devname(hostdir, &hostname, &dirname))
40+
 	int retry;
44-
-		goto fail;
41+
 	int retval = EX_FAIL;
42+
 	time_t timeout, t;
4545
+
46-
+	/*
46+
+	(void)memset(&pnu, 0, sizeof(parsed_nfs_url));
47-
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
47+
48-
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
48+
 	if (strlen(spec) >= sizeof(hostdir)) {
49-
+	 * including port support (nfs://hostname@port/path/...)
49+
 		nfs_error(_("%s: excessively long host:dir argument\n"),
50-
+	 */
50+
 				progname);
51-
+	if (!strncmp(spec, "nfs://", 6)) {
51+
 		goto fail;
52-
+		dirname = NULL;
52+
 	}
53+
-	strcpy(hostdir, spec);
5356
+
54-
+		uctx = url_parser_create_context(spec, 0);
57+
+	/*
55-
+	        if (!uctx) {
58+
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
56-
+			nfs_error(_("%s: out of memory"),
59+
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
57-
+				progname);
60+
+	 * including custom port (nfs://hostname@port/path/...)
61+
+	 * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
5866
+			goto fail;
5967
+		}
6068
+
61-
+		if (url_parser_parse(uctx) < 0) {
69+
+		/*
62-
+			nfs_error(_("%s: Error parsing nfs://-URL."),
70+
+		 * |pnu.uctx->path| is in UTF-8, but we need the data
63-
+				progname);
71+
+		 * in the current local locale's encoding, as mount(2)
64-
+			goto fail;
72+
+		 * does not have something like a |MS_UTF8_SPEC| flag
65-
+		}
73+
+		 * to indicate that the input path is in UTF-8,
66-
+		if (uctx->login.username || uctx->login.passwd) {
74+
+		 * independently of the current locale
67-
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
75+
+		 */
68-
+				progname);
76+
+		hostname = pnu.uctx->hostport.hostname;
69-
+			goto fail;
77+
+		dirname = mb_dirname = utf8str2mbstr(pnu.uctx->path);
78+
+
7085
+		}
71-
+		if (!uctx->path) {
86+
+
72-
+			nfs_error(_("%s: Path missing in nfs://-URL."),
87+
+		/*
73-
+				progname);
88+
+		 * Values added here based on URL parameters
74-
+			goto fail;
89+
+		 * should be added the front of the list of options,
90+
+		 * so users can override the nfs://-URL given default.
7599
+		}
76-
+		if (uctx->path[0] != '/') {
100+
+        } else {
77-
+			nfs_error(_("%s: Relative nfs://-URLs are not supported."),
101+
+		(void)strcpy(hostdir, spec);
81102
+
82-
+		if (uctx->hostport.port != -1) {
103+
+		if (parse_devname(hostdir, &hostname, &dirname))
83-
+			nfs_port = uctx->hostport.port;
104+
+			goto fail;
84-
+		}
105+
+	}
85-
+
106+
86-
+		hostname = uctx->hostport.hostname;
107+
 	if (fill_ipv4_sockaddr(hostname, &server_addr))
87-
+		dirname = utf8str2mbstr(uctx->path);
108+
 		goto fail;
88-
+
109+
@@ -247,7 +300,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
89-
+		(void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
110+
 	/*
90-
+			hostname, dirname);
111+
 	 * NFSv4 specifies that the default port should be 2049
91-
+		spec = hostdir;
112+
 	 */
92-
+
113+
-	server_addr.sin_port = htons(NFS_PORT);
93-
+		if (uctx->num_parameters > 0) {
114+
+	server_addr.sin_port = htons(nfs_port);
94-
+			int pi;
115+
95-
+			const char *pname;
116+
 	/* parse options */
96-
+			const char *pvalue;
117+
118+
@@ -474,8 +527,14 @@ int nfs4mount(const char *spec, const char *node, int flags,
97124
+
98-
+			/*
125+
 	return EX_SUCCESS;
99-
+			 * Values added here based on URL parameters
126+
100-
+			 * should be added the front of the list of options,
127+
 fail:
101-
+			 * so users can override the nfs://-URL given default.
128+
+	mount_free_parse_nfs_url(&pnu);
102-
+			 *
129+
+	free(mb_dirname);
108130
+
109-
+				if (!strcmp(pname, "rw")) {
131+
 	return retval;
110-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
132+
 }
111-
+						flags &= ~MS_RDONLY;
133+
diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
112-
+					}
134+
index a1c92fe8..e61d718a 100644
113-
+					else if (!strcmp(pvalue, "0")) {
135+
--- a/utils/mount/nfsmount.c
114-
+						flags |= MS_RDONLY;
136+
+++ b/utils/mount/nfsmount.c
115-
+					}
137+
@@ -63,11 +63,13 @@
116-
+					else {
138+
 #include "xcommon.h"
117-
+						nfs_error(_("%s: Unsupported nfs://-URL "
139+
 #include "mount.h"
118-
+							"parameter '%s' value '%s'."),
140+
 #include "nfs_mount.h"
119-
+							progname, pname, pvalue);
141+
+#include "urlparser1.h"
120-
+						goto fail;
142+
 #include "mount_constants.h"
121-
+					}
143+
 #include "nls.h"
122-
+				}
144+
 #include "error.h"
123-
+				else if (!strcmp(pname, "ro")) {
145+
 #include "network.h"
124-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
146+
 #include "version.h"
125-
+						flags |= MS_RDONLY;
147+
+#include "utils.h"
126-
+					}
148+
127-
+					else if (!strcmp(pvalue, "0")) {
149+
 #ifdef HAVE_RPCSVC_NFS_PROT_H
128-
+						flags &= ~MS_RDONLY;
150+
 #include <rpcsvc/nfs_prot.h>
129-
+					}
151+
@@ -493,7 +495,7 @@ nfsmount(const char *spec, const char *node, int flags,
130-
+					else {
152+
 	 char **extra_opts, int fake, int running_bg)
131-
+						nfs_error(_("%s: Unsupported nfs://-URL "
153+
 {
132-
+							"parameter '%s' value '%s'."),
154+
 	char hostdir[1024];
133-
+							progname, pname, pvalue);
155+
-	char *hostname, *dirname, *old_opts, *mounthost = NULL;
134-
+						goto fail;
156+
+	char *hostname, *dirname, *mb_dirname = NULL, *old_opts, *mounthost = NULL;
135-
+					}
157+
 	char new_opts[1024], cbuf[1024];
136-
+				}
158+
 	static struct nfs_mount_data data;
137-
+				else {
159+
 	int val;
138-
+					nfs_error(_("%s: Unsupported nfs://-URL "
160+
@@ -521,29 +523,79 @@ nfsmount(const char *spec, const char *node, int flags,
139-
+							"parameter '%s'."),
161+
 	time_t t;
140-
+						progname, pname);
162+
 	time_t prevt;
141-
+					goto fail;
163+
 	time_t timeout;
142-
+				}
164+
+	int nfsurl_port = -1;
143-
+			}
165+
+	parsed_nfs_url pnu;
147166
+
148-
+		if (parse_devname(hostdir, &hostname, &dirname))
167+
+	(void)memset(&pnu, 0, sizeof(parsed_nfs_url));
151168
152-
 	if (fill_ipv4_sockaddr(hostname, &server_addr))
169+
 	if (strlen(spec) >= sizeof(hostdir)) {
170+
 		nfs_error(_("%s: excessively long host:dir argument"),
153172
 		goto fail;
154-
@@ -247,7 +354,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
173+
 	}
155-
 	/*
174+
-	strcpy(hostdir, spec);
156-
 	 * NFSv4 specifies that the default port should be 2049
175+
-	if ((s = strchr(hostdir, ':'))) {
157-
 	 */
176+
-		hostname = hostdir;
158-
-	server_addr.sin_port = htons(NFS_PORT);
177+
-		dirname = s + 1;
159-
+	server_addr.sin_port = htons(nfs_port);
178+
-		*s = '\0';
160-
179+
-		/* Ignore all but first hostname in replicated mounts
161-
 	/* parse options */
180+
-		   until they can be fully supported. (mack@sgi.com) */
162-
181+
-		if ((s = strchr(hostdir, ','))) {
171182
+
172-
 	return EX_SUCCESS;
183+
+	/*
173-
184+
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
174-
 fail:
185+
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
175-
+	if (uctx) {
186+
+	 * including custom port (nfs://hostname@port/path/...)
176-
+		url_parser_free_context(uctx);
187+
+	 * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
177-
+		free(dirname);
188+
+	 * support
178-
+	}
189+
+	 */
190+
+	if (is_spec_nfs_url(spec)) {
179194
+
180-
 	return retval;
195+
+		/*
181-
 }
196+
+		 * |pnu.uctx->path| is in UTF-8, but we need the data
182-
diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
197+
+		 * in the current local locale's encoding, as mount(2)
183-
index a1c92fe8..1002e6e3 100644
198+
+		 * does not have something like a |MS_UTF8_SPEC| flag
184-
--- a/utils/mount/nfsmount.c
199+
+		 * to indicate that the input path is in UTF-8,
185-
+++ b/utils/mount/nfsmount.c
200+
+		 * independently of the current locale
186-
@@ -63,11 +63,13 @@
201+
+		 */
187-
 #include "xcommon.h"
202+
+		hostname = pnu.uctx->hostport.hostname;
188-
 #include "mount.h"
203+
+		dirname = mb_dirname = utf8str2mbstr(pnu.uctx->path);
189-
 #include "nfs_mount.h"
204+
+
190-
+#include "urlparser1.h"
205+
+		(void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
191-
 #include "mount_constants.h"
206+
+			hostname, dirname);
192-
 #include "nls.h"
207+
+		spec = hostdir;
193-
 #include "error.h"
208+
+
194-
 #include "network.h"
209+
+		if (pnu.uctx->hostport.port != -1) {
195-
 #include "version.h"
210+
+			nfsurl_port = pnu.uctx->hostport.port;
196-
+#include "utils.h"
211+
+		}
197-
212+
+
198-
 #ifdef HAVE_RPCSVC_NFS_PROT_H
213+
+		/*
199-
 #include <rpcsvc/nfs_prot.h>
214+
+		 * Values added here based on URL parameters
200-
@@ -521,29 +523,133 @@ nfsmount(const char *spec, const char *node, int flags,
215+
+		 * should be added the front of the list of options,
201-
 	time_t t;
216+
+		 * so users can override the nfs://-URL given default.
202-
 	time_t prevt;
217+
+		 *
203-
 	time_t timeout;
218+
+		 * FIXME: We do not do that here for |MS_RDONLY|!
204-
+	url_parser_context *uctx = NULL;
219+
+		 */
205-
+	int nfsurl_port = -1;
220+
+		if (pnu.mount_params.read_only != TRIS_BOOL_NOT_SET) {
206-
221+
+			if (pnu.mount_params.read_only)
207-
 	if (strlen(spec) >= sizeof(hostdir)) {
222+
+				flags |= MS_RDONLY;
208-
 		nfs_error(_("%s: excessively long host:dir argument"),
223+
+			else
209-
 				progname);
224+
+				flags &= ~MS_RDONLY;
210-
 		goto fail;
225+
+		}
211-
 	}
226+
+        } else {
212-
-	strcpy(hostdir, spec);
227+
+		(void)strcpy(hostdir, spec);
213-
-	if ((s = strchr(hostdir, ':'))) {
228+
+		if ((s = strchr(hostdir, ':'))) {
214-
-		hostname = hostdir;
229+
+			hostname = hostdir;
215-
-		dirname = s + 1;
230+
+			dirname = s + 1;
216-
-		*s = '\0';
231+
 			*s = '\0';
217-
-		/* Ignore all but first hostname in replicated mounts
232+
-			nfs_error(_("%s: warning: "
218-
-		   until they can be fully supported. (mack@sgi.com) */
233+
-				  "multiple hostnames not supported"),
219-
-		if ((s = strchr(hostdir, ','))) {
234+
+			/* Ignore all but first hostname in replicated mounts
220-
+
235+
+			   until they can be fully supported. (mack@sgi.com) */
221-
+	/*
236+
+			if ((s = strchr(hostdir, ','))) {
222-
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
237+
+				*s = '\0';
223-
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
238+
+				nfs_error(_("%s: warning: "
224-
+	 * including port support (nfs://hostname@port/path/...)
239+
+					"multiple hostnames not supported"),
225-
+	 */
240+
 					progname);
226-
+	if (!strncmp(spec, "nfs://", 6)) {
241+
-		}
227-
+		dirname = NULL;
242+
-	} else {
228-
+
243+
-		nfs_error(_("%s: directory to mount not in host:dir format"),
229-
+		uctx = url_parser_create_context(spec, 0);
244+
+			}
230-
+	        if (!uctx) {
245+
+		} else {
231-
+			nfs_error(_("%s: out of memory"),
246+
+			nfs_error(_("%s: directory to mount not in host:dir format"),
232-
+				progname);
247+
 				progname);
248+
-		goto fail;
233249
+			goto fail;
234250
+		}
235-
+
251+
 	}
236-
+		if (url_parser_parse(uctx) < 0) {
252+
237-
+			nfs_error(_("%s: Error parsing nfs://-URL."),
253+
 	if (!nfs_gethostbyname(hostname, nfs_saddr))
238-
+				progname);
254+
@@ -579,6 +631,14 @@ nfsmount(const char *spec, const char *node, int flags,
239-
+			goto fail;
255+
 	memset(nfs_pmap, 0, sizeof(*nfs_pmap));
240-
+		}
256+
 	nfs_pmap->pm_prog = NFS_PROGRAM;
241-
+		if (uctx->login.username || uctx->login.passwd) {
257+
242-
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
258+
+	if (nfsurl_port != -1) {
243-
+				progname);
259+
+		/*
244-
+			goto fail;
260+
+		 * Set custom TCP port defined by a nfs://-URL here,
245-
+		}
261+
+		 * so $ mount -o port ... # can be used to override
246-
+		if (!uctx->path) {
262+
+		 */
247-
+			nfs_error(_("%s: Path missing in nfs://-URL."),
263+
+		nfs_pmap->pm_port = nfsurl_port;
248-
+				progname);
264+
+	}
256265
+
257-
+		if (uctx->hostport.port != -1) {
266+
 	/* parse options */
258-
+			nfsurl_port = uctx->hostport.port;
267+
 	new_opts[0] = 0;
259-
+		}
268+
 	if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
269+
@@ -863,10 +923,13 @@ noauth_flavors:
260274
+
261-
+		hostname = uctx->hostport.hostname;
275+
 	return EX_SUCCESS;
262-
+		dirname = utf8str2mbstr(uctx->path);
276+
263-
+
277+
 	/* abort */
264-
+		(void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
278+
  fail:
265-
+			hostname, dirname);
279+
+	mount_free_parse_nfs_url(&pnu);
266-
+		spec = hostdir;
280+
 	if (fsock != -1)
267-
+
281+
 		close(fsock);
268-
+		if (uctx->num_parameters > 0) {
282+
 	return retval;
269-
+			int pi;
283+
diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
270-
+			const char *pname;
284+
index 2ade5d5d..d9f8cf59 100644
271-
+			const char *pvalue;
285+
--- a/utils/mount/parse_dev.c
272-
+
286+
+++ b/utils/mount/parse_dev.c
273-
+			/*
287+
@@ -27,6 +27,8 @@
274-
+			 * Values added here based on URL parameters
288+
 #include "xcommon.h"
275-
+			 * should be added the front of the list of options,
289+
 #include "nls.h"
276-
+			 * so users can override the nfs://-URL given default.
290+
 #include "parse_dev.h"
277-
+			 *
291+
+#include "urlparser1.h"
278-
+			 * FIXME: We do not do that here for |MS_RDONLY|!
292+
+#include "utils.h"
279-
+			 */
293+
280-
+			for (pi = 0; pi < uctx->num_parameters ; pi++) {
294+
 #ifndef NFS_MAXHOSTNAME
281-
+				pname = uctx->parameters[pi].name;
295+
 #define NFS_MAXHOSTNAME		(255)
282-
+				pvalue = uctx->parameters[pi].value;
296+
@@ -179,17 +181,62 @@ static int nfs_parse_square_bracket(const char *dev,
283-
+
297+
 }
284-
+				if (!strcmp(pname, "rw")) {
298+
285-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
299+
 /*
286-
+						flags &= ~MS_RDONLY;
300+
- * RFC 2224 says an NFS client must grok "public file handles" to
287-
+					}
301+
- * support NFS URLs.  Linux doesn't do that yet.  Print a somewhat
288-
+					else if (!strcmp(pvalue, "0")) {
302+
- * helpful error message in this case instead of pressing forward
289-
+						flags |= MS_RDONLY;
303+
- * with the mount request and failing with a cryptic error message
290-
+					}
304+
- * later.
291-
+					else {
305+
+ * Support nfs://-URLS per RFC 2224 ("NFS URL
292-
+						nfs_error(_("%s: Unsupported nfs://-URL "
306+
+ * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
293-
+							"parameter '%s' value '%s'."),
307+
+ * including port support (nfs://hostname@port/path/...)
294-
+							progname, pname, pvalue);
308+
  */
295-
+						goto fail;
309+
-static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
296-
+					}
310+
-			     __attribute__((unused)) char **hostname,
297-
+				}
311+
-			     __attribute__((unused)) char **pathname)
298-
+				else if (!strcmp(pname, "ro")) {
312+
+static int nfs_parse_nfs_url(const char *dev,
299-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
313+
+			     char **out_hostname,
300-
+						flags |= MS_RDONLY;
314+
+			     char **out_pathname)
301-
+					}
315+
 {
302-
+					else if (!strcmp(pvalue, "0")) {
316+
-	nfs_error(_("%s: NFS URLs are not supported"), progname);
303-
+						flags &= ~MS_RDONLY;
317+
+	parsed_nfs_url pnu;
304-
+					}
318+
+
305-
+					else {
319+
+	if (out_hostname)
306-
+						nfs_error(_("%s: Unsupported nfs://-URL "
320+
+		*out_hostname = NULL;
307-
+							"parameter '%s' value '%s'."),
321+
+	if (out_pathname)
308-
+							progname, pname, pvalue);
322+
+		*out_pathname = NULL;
309-
+						goto fail;
323+
+
310-
+					}
324+
+	/*
311-
+				}
325+
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
312-
+				else {
326+
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
313-
+					nfs_error(_("%s: Unsupported nfs://-URL "
327+
+	 * including custom port (nfs://hostname@port/path/...)
314-
+							"parameter '%s'."),
328+
+	 * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
315-
+						progname, pname);
329+
+	 * support
316-
+					goto fail;
330+
+	 */
317-
+				}
331+
+	if (!mount_parse_nfs_url(dev, &pnu)) {
318-
+			}
332+
+		goto fail;
319-
+		}
333+
+	}
320-
+        } else {
334+
+
321-
+		(void)strcpy(hostdir, spec);
335+
+	if (pnu.uctx->hostport.port != -1) {
322-
+		if ((s = strchr(hostdir, ':'))) {
336+
+		/* NOP here, unless we switch from hostname to hostport */
323-
+			hostname = hostdir;
337+
+	}
324-
+			dirname = s + 1;
338+
+
325-
 			*s = '\0';
339+
+	if (out_hostname)
326-
-			nfs_error(_("%s: warning: "
340+
+		*out_hostname = strdup(pnu.uctx->hostport.hostname);
327-
-				  "multiple hostnames not supported"),
341+
+	if (out_pathname)
328-
+			/* Ignore all but first hostname in replicated mounts
342+
+		*out_pathname = utf8str2mbstr(pnu.uctx->path);
329-
+			   until they can be fully supported. (mack@sgi.com) */
343+
+
330-
+			if ((s = strchr(hostdir, ','))) {
344+
+	if (((out_hostname)?(*out_hostname == NULL):0) ||
331-
+				*s = '\0';
345+
+		((out_pathname)?(*out_pathname == NULL):0)) {
332-
+				nfs_error(_("%s: warning: "
346+
+		nfs_error(_("%s: out of memory"),
333-
+					"multiple hostnames not supported"),
347+
+			progname);
334-
 					progname);
348+
+		goto fail;
335-
-		}
349+
+	}
336-
-	} else {
350+
+
337-
-		nfs_error(_("%s: directory to mount not in host:dir format"),
351+
+	mount_free_parse_nfs_url(&pnu);
338-
+			}
352+
+
339-
+		} else {
353+
+	return 1;
340-
+			nfs_error(_("%s: directory to mount not in host:dir format"),
354+
+
341-
 				progname);
355+
+fail:
342-
-		goto fail;
356+
+	mount_free_parse_nfs_url(&pnu);
343-
+			goto fail;
357+
+	if (out_hostname) {
344-
+		}
358+
+		free(*out_hostname);
359+
+		*out_hostname = NULL;
345366
 	}
346367
347-
 	if (!nfs_gethostbyname(hostname, nfs_saddr))
368+
@@ -223,7 +270,7 @@ int nfs_parse_devname(const char *devname,
348-
@@ -579,6 +685,14 @@ nfsmount(const char *spec, const char *node, int flags,
369+
 		return nfs_pdn_nomem_err();
349-
 	memset(nfs_pmap, 0, sizeof(*nfs_pmap));
370+
 	if (*dev == '[')
350-
 	nfs_pmap->pm_prog = NFS_PROGRAM;
371+
 		result = nfs_parse_square_bracket(dev, hostname, pathname);
351-
372+
-	else if (strncmp(dev, "nfs://", 6) == 0)
352-
+	if (nfsurl_port != -1) {
373+
+	else if (is_spec_nfs_url(dev))
353-
+		/*
374+
 		result = nfs_parse_nfs_url(dev, hostname, pathname);
354-
+		 * Set custom TCP port defined by a nfs://-URL here,
375+
 	else
355-
+		 * so $ mount -o port ... # can be used to override
376+
 		result = nfs_parse_simple_hostname(dev, hostname, pathname);
356-
+		 */
377+
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
357-
+		nfs_pmap->pm_port = nfsurl_port;
378+
index 2d5fa1f2..c234c1c9 100644
358-
+	}
379+
--- a/utils/mount/stropts.c
359-
+
380+
+++ b/utils/mount/stropts.c
360-
 	/* parse options */
381+
@@ -42,6 +42,7 @@
361-
 	new_opts[0] = 0;
382+
 #include "nls.h"
362-
 	if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
383+
 #include "nfsrpc.h"
363-
@@ -863,10 +977,19 @@ noauth_flavors:
384+
 #include "mount_constants.h"
364-
 		}
385+
+#include "urlparser1.h"
365-
 	}
386+
 #include "stropts.h"
387+
 #include "error.h"
366394
367-
+	if (uctx) {
395+
 #ifndef NFS_PROGRAM
368-
+		free(dirname);
396+
 #define NFS_PROGRAM	(100003)
369-
+		url_parser_free_context(uctx);
397+
@@ -643,24 +645,106 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
370-
+	}
398+
 {
371-
+
399+
 	char *options = NULL;
372-
 	return EX_SUCCESS;
400+
 	int result;
401+
+	int nfs_port = 2049;
373402
374-
 	/* abort */
403+
 	if (mi->fake)
375-
  fail:
404+
 		return 1;
376-
+	if (uctx) {
405+
377-
+		free(dirname);
406+
-	if (po_join(opts, &options) == PO_FAILED) {
378-
+		url_parser_free_context(uctx);
407+
-		errno = EIO;
379-
+	}
408+
-		return 0;
380-
 	if (fsock != -1)
409+
-	}
381-
 		close(fsock);
410+
+	/*
382-
 	return retval;
411+
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
383-
diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
412+
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
384-
index 2ade5d5d..2fe2cfc3 100644
413+
+	 * including custom port (nfs://hostname@port/path/...)
385-
--- a/utils/mount/parse_dev.c
414+
+	 * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
386-
+++ b/utils/mount/parse_dev.c
415+
+	 * support
387-
@@ -27,6 +27,8 @@
416+
+	 */
388-
 #include "xcommon.h"
417+
+	if (is_spec_nfs_url(mi->spec)) {
389-
 #include "nls.h"
418+
+		parsed_nfs_url pnu;
390-
 #include "parse_dev.h"
419+
+		char *mb_path;
391-
+#include "urlparser1.h"
420+
+		char mount_source[1024];
392-
+#include "utils.h"
421+
+
393-
422+
+		if (!mount_parse_nfs_url(mi->spec, &pnu)) {
394-
 #ifndef NFS_MAXHOSTNAME
423+
+			result = 1;
395-
 #define NFS_MAXHOSTNAME		(255)
424+
+			errno = EINVAL;
396-
@@ -179,17 +181,85 @@ static int nfs_parse_square_bracket(const char *dev,
425+
+			goto done;
397-
 }
426+
+		}
398-
427+
+
399-
 /*
428+
+		/*
400-
- * RFC 2224 says an NFS client must grok "public file handles" to
429+
+		 * |pnu.uctx->path| is in UTF-8, but we need the data
401-
- * support NFS URLs.  Linux doesn't do that yet.  Print a somewhat
430+
+		 * in the current local locale's encoding, as mount(2)
402-
- * helpful error message in this case instead of pressing forward
431+
+		 * does not have something like a |MS_UTF8_SPEC| flag
403-
- * with the mount request and failing with a cryptic error message
432+
+		 * to indicate that the input path is in UTF-8,
404-
- * later.
433+
+		 * independently of the current locale
405-
+ * Support nfs://-URLS per RFC 2224 ("NFS URL
434+
+		 */
406-
+ * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
435+
+		mb_path = utf8str2mbstr(pnu.uctx->path);
407-
+ * including port support (nfs://hostname@port/path/...)
436+
+		if (!mb_path) {
408-
  */
437+
+			nfs_error(_("%s: Could not convert path to local encoding."),
409-
-static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
438+
+				progname);
410-
-			     __attribute__((unused)) char **hostname,
439+
+			mount_free_parse_nfs_url(&pnu);
411-
-			     __attribute__((unused)) char **pathname)
440+
+			result = 1;
412-
+static int nfs_parse_nfs_url(const char *dev,
441+
+			errno = EINVAL;
413-
+			     char **out_hostname,
442+
+			goto done;
414-
+			     char **out_pathname)
443+
+		}
418444
+
419-
+	if (out_hostname)
445+
+		(void)snprintf(mount_source, sizeof(mount_source),
420-
+		*out_hostname = NULL;
446+
+			"%s:/%s",
421-
+	if (out_pathname)
447+
+			pnu.uctx->hostport.hostname,
422-
+		*out_pathname = NULL;
448+
+			mb_path);
449+
+		free(mb_path);
423450
+
424-
+	/*
451+
+		if (pnu.uctx->hostport.port != -1) {
425-
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
452+
+			nfs_port = pnu.uctx->hostport.port;
426-
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
453+
+		}
427-
+	 * including port support (nfs://hostname@port/path/...)
454+
428-
+	 */
455+
-	result = mount(mi->spec, mi->node, mi->type,
429-
+
456+
+		/*
430-
+	uctx = url_parser_create_context(dev, 0);
457+
+		 * Insert "port=" option with the value from the nfs://
431-
+	if (!uctx) {
458+
+		 * URL at the beginning of the list of options, so
432-
+		nfs_error(_("%s: out of memory"),
459+
+		 * users can override it with $ mount.nfs4 -o port= #,
433-
+			progname);
460+
+		 * e.g.
434-
+		goto fail;
461+
+		 * $ mount.nfs4 -o port=1234 nfs://10.49.202.230:400//bigdisk /mnt4 #
435-
+	}
462+
+		 * should use port 1234, and not port 400 as specified
463+
+		 * in the URL.
436468
+
437-
+	if (url_parser_parse(uctx) < 0) {
469+
+		if (pnu.mount_params.read_only != TRIS_BOOL_NOT_SET) {
438-
+		nfs_error(_("%s: Error parsing nfs://-URL."),
470+
+			if (pnu.mount_params.read_only)
439-
+			progname);
471+
+				mi->flags |= MS_RDONLY;
440-
+		goto fail;
472+
+			else
441-
+	}
473+
+				mi->flags &= ~MS_RDONLY;
442-
+	if (uctx->login.username || uctx->login.passwd) {
474+
+		}
443-
+		nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
475+
+
444-
+			progname);
476+
+		mount_free_parse_nfs_url(&pnu);
445-
+		goto fail;
477+
+
446-
+	}
478+
+		if (po_join(opts, &options) == PO_FAILED) {
447-
+	if (!uctx->path) {
479+
+			errno = EIO;
448-
+		nfs_error(_("%s: Path missing in nfs://-URL."),
480+
+			result = 1;
449-
+			progname);
481+
+			goto done;
450-
+		goto fail;
482+
+		}
457483
+
458-
+	if (uctx->hostport.port != -1) {
484+
+		result = mount(mount_source, mi->node, mi->type,
459-
+		/* NOP here, unless we switch from hostname to hostport */
485+
+			mi->flags & ~(MS_USER|MS_USERS), options);
460-
+	}
486+
+		free(options);
487+
+	} else {
461493
+
462-
+	if (out_hostname)
494+
+		result = mount(mi->spec, mi->node, mi->type,
463-
+		*out_hostname = strdup(uctx->hostport.hostname);
495+
 			mi->flags & ~(MS_USER|MS_USERS), options);
464-
+	if (out_pathname)
496+
-	free(options);
465-
+		*out_pathname = utf8str2mbstr(uctx->path);
497+
+		free(options);
472498
+	}
499+
473505
+
474-
+	url_parser_free_context(uctx);
506+
+done:
475-
+
507+
 	return !result;
476-
+	return 1;
508+
 }
477-
+
509+
478-
+fail:
510+
diff --git a/utils/mount/urlparser1.c b/utils/mount/urlparser1.c
479-
+	url_parser_free_context(uctx);
511+
new file mode 100644
480-
+	if (out_hostname) {
512+
index 00000000..ad32fde8
481-
+		free(*out_hostname);
513+
--- /dev/null
482-
+		*out_hostname = NULL;
514+
+++ b/utils/mount/urlparser1.c
483-
+	}
515+
@@ -0,0 +1,334 @@
484-
+	if (out_pathname) {
516+
+/*
485-
+		free(*out_pathname);
517+
+ * MIT License
486-
+		*out_pathname = NULL;
518+
+ *
487-
+	}
519+
+ * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
488-
 	return 0;
520+
+ *
489-
 }
521+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
490-
522+
+ * of this software and associated documentation files (the "Software"), to deal
491-
diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
523+
+ * in the Software without restriction, including without limitation the rights
492-
index 2d5fa1f2..20dc0401 100644
524+
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
493-
--- a/utils/mount/stropts.c
525+
+ * copies of the Software, and to permit persons to whom the Software is
494-
+++ b/utils/mount/stropts.c
526+
+ * furnished to do so, subject to the following conditions:
495-
@@ -42,6 +42,7 @@
527+
+ *
496-
 #include "nls.h"
528+
+ * The above copyright notice and this permission notice shall be included in all
497-
 #include "nfsrpc.h"
529+
+ * copies or substantial portions of the Software.
498-
 #include "mount_constants.h"
530+
+ *
499-
+#include "urlparser1.h"
531+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
500-
 #include "stropts.h"
532+
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
501-
 #include "error.h"
533+
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
502-
 #include "network.h"
534+
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
503-
@@ -50,6 +51,7 @@
535+
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
504-
 #include "parse_dev.h"
536+
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
505-
 #include "conffile.h"
537+
+ * SOFTWARE.
506-
 #include "misc.h"
538+
+ */
507-
+#include "utils.h"
539+
+
508-
540+
+/* urlparser1.c - simple URL parser */
509-
 #ifndef NFS_PROGRAM
541+
+
510-
 #define NFS_PROGRAM	(100003)
542+
+#include <stdlib.h>
511-
@@ -647,20 +649,177 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
543+
+#include <stdbool.h>
512-
 	if (mi->fake)
544+
+#include <string.h>
513-
 		return 1;
545+
+#include <ctype.h>
514-
546+
+#include <stdio.h>
521547
+
522-
+	/*
548+
+#include "urlparser1.h"
523-
+	 * Support nfs://-URLS per RFC 2224 ("NFS URL
549+
+
524-
+	 * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
550+
+typedef struct _url_parser_context_private {
525-
+	 * including port support (nfs://hostname@port/path/...)
551+
+	url_parser_context c;
526-
+	 */
552+
+
527-
+	if (!strncmp(mi->spec, "nfs://", 6)) {
553+
+	/* Private data */
528-
+		uctx = url_parser_create_context(mi->spec, 0);
554+
+	char *parameter_string_buff;
529-
+	        if (!uctx) {
555+
+} url_parser_context_private;
530-
+			nfs_error(_("%s: out of memory"),
556+
+
531-
+				progname);
557+
+#define MAX_URL_PARAMETERS 256
532-
+			result = 1;
558+
+
533-
+			goto done;
559+
+/*
534-
+		}
560+
+ * Original extended regular expression:
535-
561+
+ *
536-
-	result = mount(mi->spec, mi->node, mi->type,
562+
+ * "^"
537-
+		if (url_parser_parse(uctx) < 0) {
563+
+ * "(.+?)"				// scheme
538-
+			nfs_error(_("%s: Error parsing nfs://-URL."),
564+
+ * "://"				// '://'
539-
+				progname);
565+
+ * "("					// login
540-
+			result = 1;
566+
+ *	"(?:"
541-
+			goto done;
567+
+ *	"(.+?)"				// user (optional)
542-
+		}
568+
+ *		"(?::(.+))?"		// password (optional)
543-
+		if (uctx->login.username || uctx->login.passwd) {
569+
+ *		"@"
544-
+			nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
570+
+ *	")?"
545-
+				progname);
571+
+ *	"("				// hostport
546-
+			result = 1;
572+
+ *		"(.+?)"			// host
547-
+			goto done;
573+
+ *		"(?::([[:digit:]]+))?"	// port (optional)
548-
+		}
574+
+ *	")"
549-
+		if (!uctx->path) {
575+
+ * ")"
550-
+			nfs_error(_("%s: Path missing in nfs://-URL."),
576+
+ * "(?:/(.*?))?"			// path (optional)
551-
+				progname);
577+
+ * "(?:\?(.*?))?"			// URL parameters (optional)
552-
+			result = 1;
578+
+ * "$"
553-
+			goto done;
579+
+ */
561580
+
562-
+		if (uctx->hostport.port != -1) {
581+
+#define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
563-
+			nfs_port = uctx->hostport.port;
582+
+#if 0 || defined(TEST_URLPARSER)
564-
+		}
583+
+#define D(x) x
584+
+#else
565587
+
566-
+		char *mb_path;
588+
+static
567-
+		char mount_source[1024];
589+
+void urldecodestr(char *outbuff, const char *buffer, size_t len)
590+
+{
568592
+
569-
+		/*
593+
+	for (i = j = 0 ; i < len ; ) {
570-
+		 * |uctx->path| is in UTF-8, but we need the data in
594+
+		switch (buffer[i]) {
571-
+		 * the local locale, as mount(2) does not have a flag
595+
+			case '%':
572-
+		 * that the input path is in UTF-8
596+
+				if ((i + 2) < len) {
573-
+		 */
597+
+					if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
574-
+		mb_path = utf8str2mbstr(uctx->path);
598+
+						const char hexstr[3] = {
575-
+		if (!mb_path) {
599+
+							buffer[i+1],
576-
+			nfs_error(_("%s: Could not convert path to local encoding."),
600+
+							buffer[i+2],
577-
+				progname);
601+
+							'\0'
578-
+			result = 1;
602+
+						};
579-
+			goto done;
603+
+						outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
580-
+		}
604+
+						i += 3;
581-
+
605+
+					} else {
582-
+		(void)snprintf(mount_source, sizeof(mount_source),
606+
+						/* invalid hex digit */
583-
+			"%s:/%s",
607+
+						outbuff[j++] = buffer[i];
584-
+			uctx->hostport.hostname,
608+
+						i++;
585-
+			uctx->path);
609+
+					}
586-
+		free(mb_path);
610+
+				} else {
587-
+
611+
+					/* incomplete hex digit */
588-
+		/*
612+
+					outbuff[j++] = buffer[i];
589-
+		 * Insert "port=" option with the value from the nfs://
613+
+					i++;
590-
+		 * URL first, so users can override it with
614+
+				}
591-
+		 * $ mount.nfs4 -o port= #, e.g.
615+
+				break;
592-
+		 * $ mount.nfs4 -o port=1234 nfs://10.49.202.230:400//bigdisk /mnt4 #
616+
+			case '+':
593-
+		 * should use port 1234, and not port 400 as specified
617+
+				outbuff[j++] = ' ';
594-
+		 * in the URL.
618+
+				i++;
595-
+		 */
619+
+				break;
596-
+		char portoptbuf[6+32];
620+
+			default:
597-
+		(void)snprintf(portoptbuf, sizeof(portoptbuf), "port=%d", nfs_port);
621+
+				outbuff[j++] = buffer[i++];
598-
+		(void)po_insert(opts, portoptbuf);
622+
+				break;
623+
+		}
599625
+
600-
+		if (uctx->num_parameters > 0) {
626+
+	outbuff[j] = '\0';
601-
+			int pi;
627+
+}
604628
+
605-
+			int rwro_already_set =
629+
+url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
606-
+				po_get(opts, "ro") || po_get(opts, "rw");
630+
+{
631+
+	url_parser_context_private *uctx;
607635
+
608-
+			/*
636+
+	/* |flags| is for future extensions */
609-
+			 * Values added here based on URL parameters
637+
+	(void)flags;
616638
+
617-
+				if (!strcmp(pname, "rw")) {
639+
+	if (!in_url)
618-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
640+
+		return NULL;
619-
+						if (!rwro_already_set)
641+
+
620-
+							mi->flags &= ~MS_RDONLY;
642+
+	in_url_len = strlen(in_url);
621-
+					}
643+
+
622-
+					else if (!strcmp(pvalue, "0")) {
644+
+	context_len = sizeof(url_parser_context_private) +
623-
+						if (!rwro_already_set)
645+
+		((in_url_len+1)*6) +
624-
+							mi->flags |= MS_RDONLY;
646+
+		(sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
625-
+					}
647+
+	uctx = malloc(context_len);
626-
+					else {
648+
+	if (!uctx)
627-
+						nfs_error(_("%s: Unsupported nfs://-URL "
649+
+		return NULL;
628-
+							"parameter '%s' value '%s'."),
650+
+
629-
+							progname, pname, pvalue);
651+
+	s = (void *)(uctx+1);
630-
+						result = 1;
652+
+	uctx->c.in_url = s;		s+= in_url_len+1;
631-
+						goto done;
653+
+	(void)strcpy(uctx->c.in_url, in_url);
632-
+					}
654+
+	uctx->c.scheme = s;		s+= in_url_len+1;
633-
+				}
655+
+	uctx->c.login.username = s;	s+= in_url_len+1;
634-
+				else if (!strcmp(pname, "ro")) {
656+
+	uctx->c.hostport.hostname = s;	s+= in_url_len+1;
635-
+					if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
657+
+	uctx->c.path = s;		s+= in_url_len+1;
636-
+						if (!rwro_already_set)
658+
+	uctx->c.hostport.port = -1;
637-
+							mi->flags |= MS_RDONLY;
659+
+	uctx->c.num_parameters = -1;
638-
+					}
660+
+	uctx->c.parameters = (void *)s;		s+= (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
639-
+					else if (!strcmp(pvalue, "0")) {
661+
+	uctx->parameter_string_buff = s;	s+= in_url_len+1;
640-
+						if (!rwro_already_set)
662+
+
641-
+							mi->flags &= ~MS_RDONLY;
663+
+	return &uctx->c;
642-
+					}
664+
+}
643-
+					else {
665+
+
644-
+						nfs_error(_("%s: Unsupported nfs://-URL "
666+
+int url_parser_parse(url_parser_context *ctx)
645-
+							"parameter '%s' value '%s'."),
667+
+{
646-
+							progname, pname, pvalue);
668+
+	url_parser_context_private *uctx = (url_parser_context_private *)ctx;
647-
+						result = 1;
669+
+
648-
+						goto done;
670+
+	D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->c.in_url));
649-
+					}
671+
+
650-
+				}
672+
+	char *s;
651-
+				else {
673+
+	const char *urlstr = uctx->c.in_url;
652-
+					nfs_error(_("%s: Unsupported nfs://-URL "
674+
+	size_t slen;
660675
+
661-
+		if (po_join(opts, &options) == PO_FAILED) {
676+
+	s = strstr(urlstr, "://");
662-
+			errno = EIO;
677+
+	if (!s) {
663-
+			result = 1;
678+
+		D((void)fprintf(stderr, "url_parser: Not an URL\n"));
664-
+			goto done;
679+
+		return -1;
665-
+		}
680+
+	}
666681
+
667-
+		result = mount(mount_source, mi->node, mi->type,
682+
+	slen = s-urlstr;
668-
 			mi->flags & ~(MS_USER|MS_USERS), options);
683+
+	(void)memcpy(uctx->c.scheme, urlstr, slen);
669-
-	free(options);
684+
+	uctx->c.scheme[slen] = '\0';
670-
+		free(options);
685+
+	urlstr += slen + 3;
677686
+
678-
+		result = mount(mi->spec, mi->node, mi->type,
687+
+	D((void)fprintf(stdout, "scheme='%s', rest='%s'\n", uctx->c.scheme, urlstr));
688688
+
689-
+done:
689+
+	s = strstr(urlstr, "@");
690-
+	url_parser_free_context(uctx);
690+
+	if (s) {
691+
+		/* URL has user/password */
691695
+
692-
 	return !result;
696+
+		s = strstr(uctx->c.login.username, ":");
693-
 }
697+
+		if (s) {
694-
698+
+			/* found passwd */
695-
diff --git a/utils/mount/urlparser1.c b/utils/mount/urlparser1.c
699+
+			uctx->c.login.passwd = s+1;
696-
new file mode 100644
700+
+			*s = '\0';
697-
index 00000000..572bc697
701+
+		}
698-
--- /dev/null
702+
+		else
699-
+++ b/utils/mount/urlparser1.c
703+
+		{
700-
@@ -0,0 +1,413 @@
704+
+			uctx->c.login.passwd = NULL;
701-
+/*
705+
+		}
702-
+ * MIT License
706+
+
703-
+ *
707+
+		/* catch password-only URLs */
704-
+ * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
708+
+		if (uctx->c.login.username[0] == '\0')
705-
+ *
709+
+			uctx->c.login.username = NULL;
706-
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
710+
+	}
707-
+ * of this software and associated documentation files (the "Software"), to deal
711+
+	else
708-
+ * in the Software without restriction, including without limitation the rights
712+
+	{
709-
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
713+
+		uctx->c.login.username = NULL;
710-
+ * copies of the Software, and to permit persons to whom the Software is
714+
+		uctx->c.login.passwd = NULL;
711-
+ * furnished to do so, subject to the following conditions:
715+
+	}
712-
+ *
716+
+
713-
+ * The above copyright notice and this permission notice shall be included in all
717+
+	D((void)fprintf(stdout, "login='%s', passwd='%s', rest='%s'\n",
714-
+ * copies or substantial portions of the Software.
718+
+		DBGNULLSTR(uctx->c.login.username),
715-
+ *
719+
+		DBGNULLSTR(uctx->c.login.passwd),
716-
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
720+
+		DBGNULLSTR(urlstr)));
724721
+
725-
+/* urlparser1.c - simple URL parser */
722+
+	char *raw_parameters;
726723
+
727-
+#if ((__STDC_VERSION__-0) < 201710L)
724+
+	uctx->c.num_parameters = 0;
728-
+#error Code requires ISO C17
725+
+	raw_parameters = strstr(urlstr, "?");
729-
+#endif
726+
+	if (raw_parameters) {
727+
+		*raw_parameters++ = '\0';
730729
+
731-
+#include <stdlib.h>
730+
+		char *ps = raw_parameters;
732-
+#include <stdbool.h>
731+
+		char *pv; /* parameter value */
733-
+#include <string.h>
732+
+		char *na; /* next '&' */
734-
+#include <ctype.h>
733+
+		char *pb = uctx->parameter_string_buff;
735-
+#include <stdio.h>
734+
+		char *pname;
735+
+		char *pvalue;
736737
+
737-
+//#define TEST_URLPARSER 1
738+
+		for (pi = 0; pi < MAX_URL_PARAMETERS ; pi++) {
739+
+			pname = ps;
738740
+
739-
+#include "urlparser1.h"
741+
+			/*
740-
+
742+
+			 * Handle parameters without value,
741-
+typedef struct _url_parser_context_private {
743+
+			 * e.g. "path?name1&name2=value2"
742-
+	url_parser_context c;
744+
+			 */
743-
+
745+
+			na = strstr(ps, "&");
744-
+	/* Private data */
746+
+			pv = strstr(ps, "=");
745-
+	char *parameter_string_buff;
747+
+			if (pv && (na?(na > pv):true)) {
746-
+} url_parser_context_private;
748+
+				*pv++ = '\0';
749+
+				pvalue = pv;
747755
+
748-
+#define MAX_URL_PARAMETERS 256
756+
+			if (na) {
757+
+				*na++ = '\0';
749759
+
750-
+#ifdef _MSC_VER
760+
+			/* URLDecode parameter name */
751-
+/*
761+
+			urldecodestr(pb, pname, strlen(pname));
752-
+ * Disable "warning C4996: 'wcscpy': This function or variable may be
762+
+			uctx->c.parameters[pi].name = pb;
753-
+ * unsafe." because in this case the buffers are properly sized,
763+
+			pb += strlen(uctx->c.parameters[pi].name)+1;
763764
+
764-
+/*
765+
+			/* URLDecode parameter value */
765-
+ * Original extended regular expression:
766+
+			if (pvalue) {
766-
+ *
767+
+				urldecodestr(pb, pvalue, strlen(pvalue));
767-
+ * "^"
768+
+				uctx->c.parameters[pi].value = pb;
768-
+ * "(.+?)"				// scheme
769+
+				pb += strlen(uctx->c.parameters[pi].value)+1;
769-
+ * "://"				// '://'
770+
+			}
770-
+ * "("					// login
771+
+			else {
771-
+ *	"(?:"
772+
+				uctx->c.parameters[pi].value = NULL;
772-
+ *	"(.+?)"				// user (optional)
773+
+			}
773-
+ *		"(?::(.+))?"		// password (optional)
774+
+
774-
+ *		"@"
775+
+			/* Next '&' ? */
775-
+ *	")?"
776+
+			if (!na)
776-
+ *	"("				// hostport
777+
+				break;
785778
+
786-
+#define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
779+
+			ps = na;
787-
+#if 0 || defined(TEST_URLPARSER)
780+
+		}
792781
+
793-
+static
782+
+		uctx->c.num_parameters = pi+1;
794-
+void urldecodestr(char *outbuff, const char *buffer, size_t len)
783+
+	}
797784
+
798-
+	for (i = j = 0 ; i < len ; ) {
785+
+	s = strstr(urlstr, "/");
799-
+		switch (buffer[i]) {
786+
+	if (s) {
800-
+			case '%':
787+
+		/* URL has hostport */
801-
+				if ((i + 2) < len) {
788+
+		slen = s-urlstr;
802-
+					if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
789+
+		urldecodestr(uctx->c.hostport.hostname, urlstr, slen);
803-
+						const char hexstr[3] = {
790+
+		urlstr += slen + 1;
804-
+							buffer[i+1],
791+
+
805-
+							buffer[i+2],
792+
+		/*
806-
+							'\0'
793+
+		 * check for addresses within '[' and ']', like
807-
+						};
794+
+		 * IPv6 addresses
808-
+						outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
795+
+		 */
809-
+						i += 3;
796+
+		s = uctx->c.hostport.hostname;
810-
+					} else {
797+
+		if (s[0] == '[')
811-
+						/* invalid hex digit */
798+
+			s = strstr(s, "]");
812-
+						outbuff[j++] = buffer[i];
799+
+
813-
+						i++;
800+
+		if (s == NULL) {
814-
+					}
801+
+			D((void)fprintf(stderr, "url_parser: Unmatched '[' in hostname\n"));
815-
+				} else {
802+
+			return -1;
816-
+					/* incomplete hex digit */
803+
+		}
817-
+					outbuff[j++] = buffer[i];
804+
+
818-
+					i++;
805+
+		s = strstr(s, ":");
819-
+				}
806+
+		if (s) {
820-
+				break;
807+
+			/* found port number */
821-
+			case '+':
808+
+			uctx->c.hostport.port = atoi(s+1);
822-
+				outbuff[j++] = ' ';
809+
+			*s = '\0';
828810
+		}
829811
+	}
812+
+	else
830818
+
831-
+	outbuff[j] = '\0';
819+
+	D((void)fprintf(stdout, "hostport='%s', port=%d, rest='%s', num_parameters=%d\n",
832-
+}
820+
+		DBGNULLSTR(uctx->c.hostport.hostname),
821+
+		uctx->c.hostport.port,
833824
+
834-
+url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
825+
+	D(
835-
+{
826+
+		ssize_t dpi;
836-
+	url_parser_context_private *uctx;
827+
+		for (dpi = 0 ; dpi < uctx->c.num_parameters ; dpi++) {
837-
+	char *s;
828+
+			(void)fprintf(stdout, "param[%d]: name='%s'/value='%s'\n",
838-
+	size_t in_url_len;
829+
+				(int)dpi,
839-
+	size_t context_len;
830+
+				uctx->c.parameters[dpi].name,
831+
+				DBGNULLSTR(uctx->c.parameters[dpi].value));
840834
+
841-
+	/* |flags| is for future extensions */
835+
+	if (!urlstr) {
842-
+	(void)flags;
836+
+		goto done;
837+
+	}
843838
+
844-
+	if (!in_url)
839+
+	urldecodestr(uctx->c.path, urlstr, strlen(urlstr));
845-
+		return NULL;
840+
+	D((void)fprintf(stdout, "path='%s'\n", uctx->c.path));
846841
+
847-
+	in_url_len = strlen(in_url);
842+
+done:
843+
+	return 0;
848845
+
849-
+	context_len = sizeof(url_parser_context_private) +
846+
+void url_parser_free_context(url_parser_context *c)
850-
+		((in_url_len+1)*6) +
847+
+{
851-
+		(sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
848+
+	free(c);
852-
+	uctx = malloc(context_len);
849+
+}
853-
+	if (!uctx)
850+
diff --git a/utils/mount/urlparser1.h b/utils/mount/urlparser1.h
854-
+		return NULL;
851+
new file mode 100644
855-
+
852+
index 00000000..0b7b4c91
856-
+	s = (void *)(uctx+1);
853+
--- /dev/null
857-
+	uctx->c.in_url = s;		s+= in_url_len+1;
854+
+++ b/utils/mount/urlparser1.h
858-
+	(void)strcpy(uctx->c.in_url, in_url);
855+
@@ -0,0 +1,64 @@
859-
+	uctx->c.scheme = s;		s+= in_url_len+1;
856+
+/*
860-
+	uctx->c.login.username = s;	s+= in_url_len+1;
857+
+ * MIT License
861-
+	uctx->c.hostport.hostname = s;	s+= in_url_len+1;
858+
+ *
862-
+	uctx->c.path = s;		s+= in_url_len+1;
859+
+ * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
863-
+	uctx->c.hostport.port = -1;
860+
+ *
864-
+	uctx->c.num_parameters = -1;
861+
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
865-
+	uctx->c.parameters = (void *)s;		s+= (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
862+
+ * of this software and associated documentation files (the "Software"), to deal
866-
+	uctx->parameter_string_buff = s;	s+= in_url_len+1;
863+
+ * in the Software without restriction, including without limitation the rights
867-
+
864+
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
868-
+	return &uctx->c;
865+
+ * copies of the Software, and to permit persons to whom the Software is
869-
+}
866+
+ * furnished to do so, subject to the following conditions:
870-
+
867+
+ *
871-
+int url_parser_parse(url_parser_context *ctx)
868+
+ * The above copyright notice and this permission notice shall be included in all
872-
+{
869+
+ * copies or substantial portions of the Software.
873-
+	url_parser_context_private *uctx = (url_parser_context_private *)ctx;
870+
+ *
871+
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR

Submit a correction or amendment below (click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:

To highlight particular lines, prefix each line with {%HIGHLIGHT}




All content is user-submitted.
The administrators of this site (kpaste.net) are not responsible for their content.
Abuse reports should be emailed to us at