- diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
- index 5ff1148c..ad1d0884 100644
- --- a/utils/mount/Makefile.am
- +++ b/utils/mount/Makefile.am
- @@ -13,7 +13,8 @@ sbin_PROGRAMS = mount.nfs
- EXTRA_DIST = nfsmount.conf $(man8_MANS) $(man5_MANS)
- mount_common = error.c network.c token.c \
- parse_opt.c parse_dev.c \
- - nfsmount.c nfs4mount.c stropts.c\
- + nfsmount.c nfs4mount.c \
- + urlparser1.c urlparser1.h stropts.c \
- mount_constants.h error.h network.h token.h \
- parse_opt.h parse_dev.h \
- nfs4_mount.h stropts.h version.h \
- diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
- index 0fe142a7..20199f65 100644
- --- a/utils/mount/nfs4mount.c
- +++ b/utils/mount/nfs4mount.c
- @@ -50,8 +50,10 @@
- #include "mount_constants.h"
- #include "nfs4_mount.h"
- #include "nfs_mount.h"
- +#include "urlparser1.h"
- #include "error.h"
- #include "network.h"
- +#include "utils.h"
- #if defined(VAR_LOCK_DIR)
- #define DEFAULT_DIR VAR_LOCK_DIR
- @@ -192,15 +194,120 @@ int nfs4mount(const char *spec, const char *node, int flags,
- int retry;
- int retval = EX_FAIL;
- time_t timeout, t;
- + int nfs_port = NFS_PORT;
- + url_parser_context *uctx = NULL;
- if (strlen(spec) >= sizeof(hostdir)) {
- nfs_error(_("%s: excessively long host:dir argument\n"),
- progname);
- goto fail;
- }
- - strcpy(hostdir, spec);
- - if (parse_devname(hostdir, &hostname, &dirname))
- - goto fail;
- +
- + /*
- + * Support nfs://-URLS per RFC 2224 ("NFS URL
- + * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- + * including port support (nfs://hostname@port/path/...)
- + */
- + if (!strncmp(spec, "nfs://", 6)) {
- + dirname = NULL;
- +
- + uctx = url_parser_create_context(spec, 0);
- + if (!uctx) {
- + nfs_error(_("%s: out of memory"),
- + progname);
- + goto fail;
- + }
- +
- + if (url_parser_parse(uctx) < 0) {
- + nfs_error(_("%s: Error parsing nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (uctx->login.username || uctx->login.passwd) {
- + nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (!uctx->path) {
- + nfs_error(_("%s: Path missing in nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (uctx->path[0] != '/') {
- + nfs_error(_("%s: Relative nfs://-URLs are not supported."),
- + progname);
- + goto fail;
- + }
- +
- + if (uctx->hostport.port != -1) {
- + nfs_port = uctx->hostport.port;
- + }
- +
- + hostname = uctx->hostport.hostname;
- + dirname = utf8str2mbstr(uctx->path);
- +
- + (void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
- + hostname, dirname);
- + spec = hostdir;
- +
- + if (uctx->num_parameters > 0) {
- + int pi;
- + const char *pname;
- + const char *pvalue;
- +
- + /*
- + * Values added here based on URL parameters
- + * should be added the front of the list of options,
- + * so users can override the nfs://-URL given default.
- + *
- + * FIXME: We do not do that here for |MS_RDONLY|!
- + */
- + for (pi = 0; pi < uctx->num_parameters ; pi++) {
- + pname = uctx->parameters[pi].name;
- + pvalue = uctx->parameters[pi].value;
- +
- + if (!strcmp(pname, "rw")) {
- + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
- + flags &= ~MS_RDONLY;
- + }
- + else if (!strcmp(pvalue, "0")) {
- + flags |= MS_RDONLY;
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s' value '%s'."),
- + progname, pname, pvalue);
- + goto fail;
- + }
- + }
- + else if (!strcmp(pname, "ro")) {
- + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
- + flags |= MS_RDONLY;
- + }
- + else if (!strcmp(pvalue, "0")) {
- + flags &= ~MS_RDONLY;
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s' value '%s'."),
- + progname, pname, pvalue);
- + goto fail;
- + }
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s'."),
- + progname, pname);
- + goto fail;
- + }
- + }
- + }
- + } else {
- + (void)strcpy(hostdir, spec);
- +
- + if (parse_devname(hostdir, &hostname, &dirname))
- + goto fail;
- + }
- if (fill_ipv4_sockaddr(hostname, &server_addr))
- goto fail;
- @@ -247,7 +354,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
- /*
- * NFSv4 specifies that the default port should be 2049
- */
- - server_addr.sin_port = htons(NFS_PORT);
- + server_addr.sin_port = htons(nfs_port);
- /* parse options */
- @@ -474,8 +581,18 @@ int nfs4mount(const char *spec, const char *node, int flags,
- }
- }
- + if (uctx) {
- + url_parser_free_context(uctx);
- + free(dirname);
- + }
- +
- return EX_SUCCESS;
- fail:
- + if (uctx) {
- + url_parser_free_context(uctx);
- + free(dirname);
- + }
- +
- return retval;
- }
- diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
- index a1c92fe8..1002e6e3 100644
- --- a/utils/mount/nfsmount.c
- +++ b/utils/mount/nfsmount.c
- @@ -63,11 +63,13 @@
- #include "xcommon.h"
- #include "mount.h"
- #include "nfs_mount.h"
- +#include "urlparser1.h"
- #include "mount_constants.h"
- #include "nls.h"
- #include "error.h"
- #include "network.h"
- #include "version.h"
- +#include "utils.h"
- #ifdef HAVE_RPCSVC_NFS_PROT_H
- #include <rpcsvc/nfs_prot.h>
- @@ -521,29 +523,133 @@ nfsmount(const char *spec, const char *node, int flags,
- time_t t;
- time_t prevt;
- time_t timeout;
- + url_parser_context *uctx = NULL;
- + int nfsurl_port = -1;
- if (strlen(spec) >= sizeof(hostdir)) {
- nfs_error(_("%s: excessively long host:dir argument"),
- progname);
- goto fail;
- }
- - strcpy(hostdir, spec);
- - if ((s = strchr(hostdir, ':'))) {
- - hostname = hostdir;
- - dirname = s + 1;
- - *s = '\0';
- - /* Ignore all but first hostname in replicated mounts
- - until they can be fully supported. (mack@sgi.com) */
- - if ((s = strchr(hostdir, ','))) {
- +
- + /*
- + * Support nfs://-URLS per RFC 2224 ("NFS URL
- + * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- + * including port support (nfs://hostname@port/path/...)
- + */
- + if (!strncmp(spec, "nfs://", 6)) {
- + dirname = NULL;
- +
- + uctx = url_parser_create_context(spec, 0);
- + if (!uctx) {
- + nfs_error(_("%s: out of memory"),
- + progname);
- + goto fail;
- + }
- +
- + if (url_parser_parse(uctx) < 0) {
- + nfs_error(_("%s: Error parsing nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (uctx->login.username || uctx->login.passwd) {
- + nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (!uctx->path) {
- + nfs_error(_("%s: Path missing in nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (uctx->path[0] != '/') {
- + nfs_error(_("%s: Relative nfs://-URLs are not supported."),
- + progname);
- + goto fail;
- + }
- +
- + if (uctx->hostport.port != -1) {
- + nfsurl_port = uctx->hostport.port;
- + }
- +
- + hostname = uctx->hostport.hostname;
- + dirname = utf8str2mbstr(uctx->path);
- +
- + (void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
- + hostname, dirname);
- + spec = hostdir;
- +
- + if (uctx->num_parameters > 0) {
- + int pi;
- + const char *pname;
- + const char *pvalue;
- +
- + /*
- + * Values added here based on URL parameters
- + * should be added the front of the list of options,
- + * so users can override the nfs://-URL given default.
- + *
- + * FIXME: We do not do that here for |MS_RDONLY|!
- + */
- + for (pi = 0; pi < uctx->num_parameters ; pi++) {
- + pname = uctx->parameters[pi].name;
- + pvalue = uctx->parameters[pi].value;
- +
- + if (!strcmp(pname, "rw")) {
- + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
- + flags &= ~MS_RDONLY;
- + }
- + else if (!strcmp(pvalue, "0")) {
- + flags |= MS_RDONLY;
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s' value '%s'."),
- + progname, pname, pvalue);
- + goto fail;
- + }
- + }
- + else if (!strcmp(pname, "ro")) {
- + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
- + flags |= MS_RDONLY;
- + }
- + else if (!strcmp(pvalue, "0")) {
- + flags &= ~MS_RDONLY;
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s' value '%s'."),
- + progname, pname, pvalue);
- + goto fail;
- + }
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s'."),
- + progname, pname);
- + goto fail;
- + }
- + }
- + }
- + } else {
- + (void)strcpy(hostdir, spec);
- + if ((s = strchr(hostdir, ':'))) {
- + hostname = hostdir;
- + dirname = s + 1;
- *s = '\0';
- - nfs_error(_("%s: warning: "
- - "multiple hostnames not supported"),
- + /* Ignore all but first hostname in replicated mounts
- + until they can be fully supported. (mack@sgi.com) */
- + if ((s = strchr(hostdir, ','))) {
- + *s = '\0';
- + nfs_error(_("%s: warning: "
- + "multiple hostnames not supported"),
- progname);
- - }
- - } else {
- - nfs_error(_("%s: directory to mount not in host:dir format"),
- + }
- + } else {
- + nfs_error(_("%s: directory to mount not in host:dir format"),
- progname);
- - goto fail;
- + goto fail;
- + }
- }
- if (!nfs_gethostbyname(hostname, nfs_saddr))
- @@ -579,6 +685,14 @@ nfsmount(const char *spec, const char *node, int flags,
- memset(nfs_pmap, 0, sizeof(*nfs_pmap));
- nfs_pmap->pm_prog = NFS_PROGRAM;
- + if (nfsurl_port != -1) {
- + /*
- + * Set custom TCP port defined by a nfs://-URL here,
- + * so $ mount -o port ... # can be used to override
- + */
- + nfs_pmap->pm_port = nfsurl_port;
- + }
- +
- /* parse options */
- new_opts[0] = 0;
- if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
- @@ -863,10 +977,19 @@ noauth_flavors:
- }
- }
- + if (uctx) {
- + free(dirname);
- + url_parser_free_context(uctx);
- + }
- +
- return EX_SUCCESS;
- /* abort */
- fail:
- + if (uctx) {
- + free(dirname);
- + url_parser_free_context(uctx);
- + }
- if (fsock != -1)
- close(fsock);
- return retval;
- diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
- index 2ade5d5d..2fe2cfc3 100644
- --- a/utils/mount/parse_dev.c
- +++ b/utils/mount/parse_dev.c
- @@ -27,6 +27,8 @@
- #include "xcommon.h"
- #include "nls.h"
- #include "parse_dev.h"
- +#include "urlparser1.h"
- +#include "utils.h"
- #ifndef NFS_MAXHOSTNAME
- #define NFS_MAXHOSTNAME (255)
- @@ -179,17 +181,85 @@ static int nfs_parse_square_bracket(const char *dev,
- }
- /*
- - * 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.
- + * Support nfs://-URLS per RFC 2224 ("NFS URL
- + * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- + * including port support (nfs://hostname@port/path/...)
- */
- -static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
- - __attribute__((unused)) char **hostname,
- - __attribute__((unused)) char **pathname)
- +static int nfs_parse_nfs_url(const char *dev,
- + char **out_hostname,
- + char **out_pathname)
- {
- - nfs_error(_("%s: NFS URLs are not supported"), progname);
- + url_parser_context *uctx = NULL;
- +
- + if (out_hostname)
- + *out_hostname = NULL;
- + if (out_pathname)
- + *out_pathname = NULL;
- +
- + /*
- + * Support nfs://-URLS per RFC 2224 ("NFS URL
- + * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- + * including port support (nfs://hostname@port/path/...)
- + */
- +
- + uctx = url_parser_create_context(dev, 0);
- + if (!uctx) {
- + nfs_error(_("%s: out of memory"),
- + progname);
- + goto fail;
- + }
- +
- + if (url_parser_parse(uctx) < 0) {
- + nfs_error(_("%s: Error parsing nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (uctx->login.username || uctx->login.passwd) {
- + nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (!uctx->path) {
- + nfs_error(_("%s: Path missing in nfs://-URL."),
- + progname);
- + goto fail;
- + }
- + if (uctx->path[0] != '/') {
- + nfs_error(_("%s: Relative nfs://-URLs are not supported."),
- + progname);
- + goto fail;
- + }
- +
- + if (uctx->hostport.port != -1) {
- + /* NOP here, unless we switch from hostname to hostport */
- + }
- +
- + if (out_hostname)
- + *out_hostname = strdup(uctx->hostport.hostname);
- + if (out_pathname)
- + *out_pathname = utf8str2mbstr(uctx->path);
- +
- + if (((out_hostname)?(*out_hostname == NULL):0) ||
- + ((out_pathname)?(*out_pathname == NULL):0)) {
- + nfs_error(_("%s: out of memory"),
- + progname);
- + goto fail;
- + }
- +
- + url_parser_free_context(uctx);
- +
- + return 1;
- +
- +fail:
- + url_parser_free_context(uctx);
- + if (out_hostname) {
- + free(*out_hostname);
- + *out_hostname = NULL;
- + }
- + if (out_pathname) {
- + free(*out_pathname);
- + *out_pathname = NULL;
- + }
- return 0;
- }
- diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
- index 2d5fa1f2..20dc0401 100644
- --- a/utils/mount/stropts.c
- +++ b/utils/mount/stropts.c
- @@ -42,6 +42,7 @@
- #include "nls.h"
- #include "nfsrpc.h"
- #include "mount_constants.h"
- +#include "urlparser1.h"
- #include "stropts.h"
- #include "error.h"
- #include "network.h"
- @@ -50,6 +51,7 @@
- #include "parse_dev.h"
- #include "conffile.h"
- #include "misc.h"
- +#include "utils.h"
- #ifndef NFS_PROGRAM
- #define NFS_PROGRAM (100003)
- @@ -647,20 +649,177 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
- if (mi->fake)
- return 1;
- - if (po_join(opts, &options) == PO_FAILED) {
- - errno = EIO;
- - return 0;
- - }
- + url_parser_context *uctx = NULL;
- + int nfs_port = 2049;
- +
- + /*
- + * Support nfs://-URLS per RFC 2224 ("NFS URL
- + * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
- + * including port support (nfs://hostname@port/path/...)
- + */
- + if (!strncmp(mi->spec, "nfs://", 6)) {
- + uctx = url_parser_create_context(mi->spec, 0);
- + if (!uctx) {
- + nfs_error(_("%s: out of memory"),
- + progname);
- + result = 1;
- + goto done;
- + }
- - result = mount(mi->spec, mi->node, mi->type,
- + if (url_parser_parse(uctx) < 0) {
- + nfs_error(_("%s: Error parsing nfs://-URL."),
- + progname);
- + result = 1;
- + goto done;
- + }
- + if (uctx->login.username || uctx->login.passwd) {
- + nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
- + progname);
- + result = 1;
- + goto done;
- + }
- + if (!uctx->path) {
- + nfs_error(_("%s: Path missing in nfs://-URL."),
- + progname);
- + result = 1;
- + goto done;
- + }
- + if (uctx->path[0] != '/') {
- + nfs_error(_("%s: Relative nfs://-URLs are not supported."),
- + progname);
- + result = 1;
- + goto done;
- + }
- +
- + if (uctx->hostport.port != -1) {
- + nfs_port = uctx->hostport.port;
- + }
- +
- + char *mb_path;
- + char mount_source[1024];
- +
- + /*
- + * |uctx->path| is in UTF-8, but we need the data in
- + * the local locale, as mount(2) does not have a flag
- + * that the input path is in UTF-8
- + */
- + mb_path = utf8str2mbstr(uctx->path);
- + if (!mb_path) {
- + nfs_error(_("%s: Could not convert path to local encoding."),
- + progname);
- + result = 1;
- + goto done;
- + }
- +
- + (void)snprintf(mount_source, sizeof(mount_source),
- + "%s:/%s",
- + uctx->hostport.hostname,
- + uctx->path);
- + free(mb_path);
- +
- + /*
- + * Insert "port=" option with the value from the nfs://
- + * URL first, so users can override it with
- + * $ mount.nfs4 -o port= #, e.g.
- + * $ mount.nfs4 -o port=1234 nfs://10.49.202.230:400//bigdisk /mnt4 #
- + * should use port 1234, and not port 400 as specified
- + * in the URL.
- + */
- + char portoptbuf[6+32];
- + (void)snprintf(portoptbuf, sizeof(portoptbuf), "port=%d", nfs_port);
- + (void)po_insert(opts, portoptbuf);
- +
- + if (uctx->num_parameters > 0) {
- + int pi;
- + const char *pname;
- + const char *pvalue;
- +
- + int rwro_already_set =
- + po_get(opts, "ro") || po_get(opts, "rw");
- +
- + /*
- + * Values added here based on URL parameters
- + * should be added the front of the list of options,
- + * so users can override the nfs://-URL given default.
- + */
- + for (pi = 0; pi < uctx->num_parameters ; pi++) {
- + pname = uctx->parameters[pi].name;
- + pvalue = uctx->parameters[pi].value;
- +
- + if (!strcmp(pname, "rw")) {
- + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
- + if (!rwro_already_set)
- + mi->flags &= ~MS_RDONLY;
- + }
- + else if (!strcmp(pvalue, "0")) {
- + if (!rwro_already_set)
- + mi->flags |= MS_RDONLY;
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s' value '%s'."),
- + progname, pname, pvalue);
- + result = 1;
- + goto done;
- + }
- + }
- + else if (!strcmp(pname, "ro")) {
- + if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
- + if (!rwro_already_set)
- + mi->flags |= MS_RDONLY;
- + }
- + else if (!strcmp(pvalue, "0")) {
- + if (!rwro_already_set)
- + mi->flags &= ~MS_RDONLY;
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s' value '%s'."),
- + progname, pname, pvalue);
- + result = 1;
- + goto done;
- + }
- + }
- + else {
- + nfs_error(_("%s: Unsupported nfs://-URL "
- + "parameter '%s'."),
- + progname, pname);
- + result = 1;
- + goto done;
- + }
- + }
- + }
- +
- + if (po_join(opts, &options) == PO_FAILED) {
- + errno = EIO;
- + result = 1;
- + goto done;
- + }
- +
- + result = mount(mount_source, mi->node, mi->type,
- mi->flags & ~(MS_USER|MS_USERS), options);
- - free(options);
- + free(options);
- + } else {
- + if (po_join(opts, &options) == PO_FAILED) {
- + errno = EIO;
- + result = 1;
- + goto done;
- + }
- +
- + result = mount(mi->spec, mi->node, mi->type,
- + mi->flags & ~(MS_USER|MS_USERS), options);
- + free(options);
- + }
- if (verbose && result) {
- int save = errno;
- nfs_error(_("%s: mount(2): %s"), progname, strerror(save));
- errno = save;
- }
- +
- +done:
- + url_parser_free_context(uctx);
- +
- return !result;
- }
- diff --git a/utils/mount/urlparser1.c b/utils/mount/urlparser1.c
- new file mode 100644
- index 00000000..572bc697
- --- /dev/null
- +++ b/utils/mount/urlparser1.c
- @@ -0,0 +1,413 @@
- +/*
- + * MIT License
- + *
- + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * Permission is hereby granted, free of charge, to any person obtaining a copy
- + * of this software and associated documentation files (the "Software"), to deal
- + * in the Software without restriction, including without limitation the rights
- + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- + * copies of the Software, and to permit persons to whom the Software is
- + * furnished to do so, subject to the following conditions:
- + *
- + * The above copyright notice and this permission notice shall be included in all
- + * copies or substantial portions of the Software.
- + *
- + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- + * SOFTWARE.
- + */
- +
- +/* urlparser1.c - simple URL parser */
- +
- +#if ((__STDC_VERSION__-0) < 201710L)
- +#error Code requires ISO C17
- +#endif
- +
- +#include <stdlib.h>
- +#include <stdbool.h>
- +#include <string.h>
- +#include <ctype.h>
- +#include <stdio.h>
- +
- +//#define TEST_URLPARSER 1
- +
- +#include "urlparser1.h"
- +
- +typedef struct _url_parser_context_private {
- + url_parser_context c;
- +
- + /* Private data */
- + char *parameter_string_buff;
- +} url_parser_context_private;
- +
- +#define MAX_URL_PARAMETERS 256
- +
- +#ifdef _MSC_VER
- +/*
- + * Disable "warning C4996: 'wcscpy': This function or variable may be
- + * unsafe." because in this case the buffers are properly sized,
- + * making this function safe
- + */
- +#pragma warning (disable : 4996)
- +/*
- + * Disable "warning C4706: assignment within conditional expression"
- + * because it is safe to use in our code.
- + */
- +#pragma warning (disable : 4706)
- +#endif /* _MSC_VER */
- +
- +/*
- + * Original extended regular expression:
- + *
- + * "^"
- + * "(.+?)" // scheme
- + * "://" // '://'
- + * "(" // login
- + * "(?:"
- + * "(.+?)" // user (optional)
- + * "(?::(.+))?" // password (optional)
- + * "@"
- + * ")?"
- + * "(" // hostport
- + * "(.+?)" // host
- + * "(?::([[:digit:]]+))?" // port (optional)
- + * ")"
- + * ")"
- + * "(?:/(.*?))?" // path (optional)
- + * "(?:\?(.*?))?" // URL parameters (optional)
- + * "$"
- + */
- +
- +#define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
- +#if 0 || defined(TEST_URLPARSER)
- +#define D(x) x
- +#else
- +#define D(x)
- +#endif
- +
- +static
- +void urldecodestr(char *outbuff, const char *buffer, size_t len)
- +{
- + size_t i, j;
- +
- + for (i = j = 0 ; i < len ; ) {
- + switch (buffer[i]) {
- + case '%':
- + if ((i + 2) < len) {
- + if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
- + const char hexstr[3] = {
- + buffer[i+1],
- + buffer[i+2],
- + '\0'
- + };
- + outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
- + i += 3;
- + } else {
- + /* invalid hex digit */
- + outbuff[j++] = buffer[i];
- + i++;
- + }
- + } else {
- + /* incomplete hex digit */
- + outbuff[j++] = buffer[i];
- + i++;
- + }
- + break;
- + case '+':
- + outbuff[j++] = ' ';
- + i++;
- + break;
- + default:
- + outbuff[j++] = buffer[i++];
- + break;
- + }
- + }
- +
- + outbuff[j] = '\0';
- +}
- +
- +url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
- +{
- + url_parser_context_private *uctx;
- + char *s;
- + size_t in_url_len;
- + size_t context_len;
- +
- + /* |flags| is for future extensions */
- + (void)flags;
- +
- + if (!in_url)
- + return NULL;
- +
- + in_url_len = strlen(in_url);
- +
- + context_len = sizeof(url_parser_context_private) +
- + ((in_url_len+1)*6) +
- + (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
- + uctx = malloc(context_len);
- + if (!uctx)
- + return NULL;
- +
- + s = (void *)(uctx+1);
- + uctx->c.in_url = s; s+= in_url_len+1;
- + (void)strcpy(uctx->c.in_url, in_url);
- + uctx->c.scheme = s; s+= in_url_len+1;
- + uctx->c.login.username = s; s+= in_url_len+1;
- + uctx->c.hostport.hostname = s; s+= in_url_len+1;
- + uctx->c.path = s; s+= in_url_len+1;
- + uctx->c.hostport.port = -1;
- + uctx->c.num_parameters = -1;
- + uctx->c.parameters = (void *)s; s+= (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
- + uctx->parameter_string_buff = s; s+= in_url_len+1;
- +
- + return &uctx->c;
- +}
- +
- +int url_parser_parse(url_parser_context *ctx)
- +{
- + url_parser_context_private *uctx = (url_parser_context_private *)ctx;
- +
- + D((void)fprintf(stderr, "## parser in_url='%s'\n", uctx->c.in_url));
- +
- + char *s;
- + const char *urlstr = uctx->c.in_url;
- + size_t slen;
- +
- + s = strstr(urlstr, "://");
- + if (!s) {
- + D((void)fprintf(stderr, "url_parser: Not an URL\n"));
- + return -1;
- + }
- +
- + slen = s-urlstr;
- + (void)memcpy(uctx->c.scheme, urlstr, slen);
- + uctx->c.scheme[slen] = '\0';
- + urlstr += slen + 3;
- +
- + D((void)fprintf(stdout, "scheme='%s', rest='%s'\n", uctx->c.scheme, urlstr));
- +
- + s = strstr(urlstr, "@");
- + if (s) {
- + /* URL has user/password */
- + slen = s-urlstr;
- + urldecodestr(uctx->c.login.username, urlstr, slen);
- + urlstr += slen + 1;
- +
- + s = strstr(uctx->c.login.username, ":");
- + if (s) {
- + /* found passwd */
- + uctx->c.login.passwd = s+1;
- + *s = '\0';
- + }
- + else
- + {
- + uctx->c.login.passwd = NULL;
- + }
- +
- + /* catch password-only URLs */
- + if (uctx->c.login.username[0] == '\0')
- + uctx->c.login.username = NULL;
- + }
- + else
- + {
- + uctx->c.login.username = NULL;
- + uctx->c.login.passwd = NULL;
- + }
- +
- + D((void)fprintf(stdout, "login='%s', passwd='%s', rest='%s'\n",
- + DBGNULLSTR(uctx->c.login.username),
- + DBGNULLSTR(uctx->c.login.passwd),
- + DBGNULLSTR(urlstr)));
- +
- + char *raw_parameters;
- +
- + uctx->c.num_parameters = 0;
- + raw_parameters = strstr(urlstr, "?");
- + if (raw_parameters) {
- + *raw_parameters++ = '\0';
- + D((void)fprintf(stdout, "raw parameters = '%s'\n", raw_parameters));
- +
- + char *ps = raw_parameters;
- + char *pv; /* parameter value */
- + char *na; /* next '&' */
- + char *pb = uctx->parameter_string_buff;
- + char *pname;
- + char *pvalue;
- + ssize_t pi;
- +
- + for (pi = 0; pi < MAX_URL_PARAMETERS ; pi++) {
- + pname = ps;
- +
- + /*
- + * Handle parameters without value,
- + * e.g. "path?name1&name2=value2"
- + */
- + na = strstr(ps, "&");
- + pv = strstr(ps, "=");
- + if (pv && (na?(na > pv):true)) {
- + *pv++ = '\0';
- + pvalue = pv;
- + ps = pv;
- + }
- + else {
- + pvalue = NULL;
- + }
- +
- + if (na) {
- + *na++ = '\0';
- + }
- +
- + /* URLDecode parameter name */
- + urldecodestr(pb, pname, strlen(pname));
- + uctx->c.parameters[pi].name = pb;
- + pb += strlen(uctx->c.parameters[pi].name)+1;
- +
- + /* URLDecode parameter value */
- + if (pvalue) {
- + urldecodestr(pb, pvalue, strlen(pvalue));
- + uctx->c.parameters[pi].value = pb;
- + pb += strlen(uctx->c.parameters[pi].value)+1;
- + }
- + else {
- + uctx->c.parameters[pi].value = NULL;
- + }
- +
- + /* Next '&' ? */
- + if (!na)
- + break;
- +
- + ps = na;
- + }
- +
- + uctx->c.num_parameters = pi+1;
- + }
- +
- + s = strstr(urlstr, "/");
- + if (s) {
- + /* URL has hostport */
- + slen = s-urlstr;
- + urldecodestr(uctx->c.hostport.hostname, urlstr, slen);
- + urlstr += slen + 1;
- +
- + /*
- + * check for addresses within '[' and ']', like
- + * IPv6 addresses
- + */
- + s = uctx->c.hostport.hostname;
- + if (s[0] == '[')
- + s = strstr(s, "]");
- +
- + if (s == NULL) {
- + D((void)fprintf(stderr, "url_parser: Unmatched '[' in hostname\n"));
- + return -1;
- + }
- +
- + s = strstr(s, ":");
- + if (s) {
- + /* found port number */
- + uctx->c.hostport.port = atoi(s+1);
- + *s = '\0';
- + }
- + }
- + else
- + {
- + (void)strcpy(uctx->c.hostport.hostname, urlstr);
- + uctx->c.path = NULL;
- + urlstr = NULL;
- + }
- +
- + D((void)fprintf(stdout, "hostport='%s', port=%d, rest='%s', num_parameters=%d\n",
- + DBGNULLSTR(uctx->c.hostport.hostname),
- + uctx->c.hostport.port,
- + DBGNULLSTR(urlstr),
- + (int)uctx->c.num_parameters));
- +
- + D(
- + ssize_t dpi;
- + for (dpi = 0 ; dpi < uctx->c.num_parameters ; dpi++) {
- + (void)fprintf(stdout, "param[%d]: name='%s'/value='%s'\n",
- + (int)dpi,
- + uctx->c.parameters[dpi].name,
- + DBGNULLSTR(uctx->c.parameters[dpi].value));
- + }
- + );
- +
- + if (!urlstr) {
- + goto done;
- + }
- +
- + urldecodestr(uctx->c.path, urlstr, strlen(urlstr));
- + D((void)fprintf(stdout, "path='%s'\n", uctx->c.path));
- +
- +done:
- + return 0;
- +}
- +
- +void url_parser_free_context(url_parser_context *c)
- +{
- + free(c);
- +}
- +
- +#ifdef TEST_URLPARSER
- +static
- +void test_url_parser(const char *instr)
- +{
- + url_parser_context *c;
- +
- + c = url_parser_create_context(instr, 0);
- +
- + (void)url_parser_parse(c);
- +
- + (void)fputc('\n', stdout);
- +
- + url_parser_free_context(c);
- +}
- +
- +int main(int ac, char *av[])
- +{
- + (void)puts("#start");
- +
- + (void)setvbuf(stdout, NULL, _IONBF, 0);
- + (void)setvbuf(stderr, NULL, _IONBF, 0);
- +
- + (void)test_url_parser("foo://hostbar/baz");
- + (void)test_url_parser("foo://myuser@hostbar/baz");
- + (void)test_url_parser("foo://myuser:mypasswd@hostbar/baz");
- + (void)test_url_parser("foo://Vorname+Nachname:mypasswd@hostbar/baz");
- + (void)test_url_parser("foo://Vorname%20Nachname:mypasswd@hostbar/baz%");
- + (void)test_url_parser("foo://myuser:mypasswd@hostbar:666/baz");
- + (void)test_url_parser("foo://myuser:mypasswd@hostbar:666//baz");
- + (void)test_url_parser("foo://myuser:mypasswd@[fe80::21b:1bff:fec3:7713]:666/baz");
- + (void)test_url_parser("foo://:mypasswd2@hostbar2:667/baf");
- + (void)test_url_parser("foo://hostbar/euro/symbol/%E2%82%AC/here");
- + (void)test_url_parser("foo://hostbar");
- + (void)test_url_parser("foo://hostbar:93");
- + (void)test_url_parser("nfs://hostbar:93/relativepath/a");
- + (void)test_url_parser("nfs://hostbar:93//absolutepath/a");
- + (void)test_url_parser("nfs://hostbar:93//absolutepath/blank%20path/a");
- + (void)test_url_parser("nfs://hostbar:93//absolutepath/blank+path/a");
- + (void)test_url_parser("foo://hostbar:93?param1");
- + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1");
- + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&pname2=pvalue2");
- + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&pvalue2=v2&n3=v3");
- + (void)test_url_parser("foo://hostbar:93?pname1¶m2=p2");
- + (void)test_url_parser("foo://hostbar:93?pname1=¶m2=p2");
- + (void)test_url_parser("foo://hostbar:93//path/path2?param1=p1");
- + (void)test_url_parser("foo://hostbar:93//path/path2?param1¶m2=p2");
- + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&%E2%82%AC=u+n2&n3=v3");
- + (void)test_url_parser("foo://hostbar:93?pname1=pvalue1&%E2%82%AC=%E2%82%AC&n3=v3");
- +
- + (void)test_url_parser("foo://");
- + (void)test_url_parser("typo:/hostbar");
- + (void)test_url_parser("wrong");
- +
- + (void)puts("#done");
- +
- + return EXIT_SUCCESS;
- +}
- +#endif /* !TEST_URLPARSER */
- diff --git a/utils/mount/urlparser1.h b/utils/mount/urlparser1.h
- new file mode 100644
- index 00000000..0b7b4c91
- --- /dev/null
- +++ b/utils/mount/urlparser1.h
- @@ -0,0 +1,64 @@
- +/*
- + * MIT License
- + *
- + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
- + *
- + * Permission is hereby granted, free of charge, to any person obtaining a copy
- + * of this software and associated documentation files (the "Software"), to deal
- + * in the Software without restriction, including without limitation the rights
- + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- + * copies of the Software, and to permit persons to whom the Software is
- + * furnished to do so, subject to the following conditions:
- + *
- + * The above copyright notice and this permission notice shall be included in all
- + * copies or substantial portions of the Software.
- + *
- + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- + * SOFTWARE.
- + */
- +
- +/* urlparser1.h - header for simple URL parser */
- +
- +#ifndef __URLPARSER1_H__
- +#define __URLPARSER1_H__
- +
- +#include <stdlib.h>
- +
- +#ifdef _MSC_VER
- +typedef signed long long ssize_t;
- +#endif
- +
- +typedef struct _url_parser_name_value {
- + char *name;
- + char *value;
- +} url_parser_name_value;
- +
- +typedef struct _url_parser_context {
- + char *in_url;
- +
- + char *scheme;
- + struct {
- + char *username;
- + char *passwd;
- + } login;
- + struct {
- + char *hostname;
- + signed int port;
- + } hostport;
- + char *path;
- +
- + ssize_t num_parameters;
- + url_parser_name_value *parameters;
- +} url_parser_context;
- +
- +/* Prototypes */
- +url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags);
- +int url_parser_parse(url_parser_context *uctx);
- +void url_parser_free_context(url_parser_context *c);
- +
- +#endif /* !__URLPARSER1_H__ */
- diff --git a/utils/mount/utils.c b/utils/mount/utils.c
- index b7562a47..2b5ec599 100644
- --- a/utils/mount/utils.c
- +++ b/utils/mount/utils.c
- @@ -28,6 +28,7 @@
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- +#include <iconv.h>
- #include "sockaddr.h"
- #include "nfs_mount.h"
- @@ -173,3 +174,38 @@ int nfs_umount23(const char *devname, char *string)
- free(dirname);
- return result;
- }
- +
- +/* Convert UTF-8 string to multibyte string in the current locale */
- +char *utf8str2mbstr(const char *utf8_str)
- +{
- + iconv_t cd;
- +
- + cd = iconv_open("UTF-8", "");
- + if (cd == (iconv_t)-1) {
- + perror("utf8str2mbstr: iconv_open failed");
- + return NULL;
- + }
- +
- + size_t inbytesleft = strlen(utf8_str);
- + char *inbuf = (char *)utf8_str;
- + size_t outbytesleft = inbytesleft*4;
- + char *outbuf = malloc(outbytesleft);
- + char *outbuf_orig = outbuf;
- +
- + if (!outbuf) {
- + perror("utf8str2mbstr: out of memory");
- + (void)iconv_close(cd);
- + return NULL;
- + }
- +
- + int ret = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
- + if (ret == -1) {
- + perror("utf8str2mbstr: iconv() failed");
- + free(outbuf_orig);
- + (void)iconv_close(cd);
- + return NULL;
- + }
- +
- + (void)iconv_close(cd);
- + return outbuf_orig;
- +}
- diff --git a/utils/mount/utils.h b/utils/mount/utils.h
- index 224918ae..eff70464 100644
- --- a/utils/mount/utils.h
- +++ b/utils/mount/utils.h
- @@ -30,6 +30,7 @@ void print_one(char *spec, char *node, char *type, char *opts);
- void mount_usage(void);
- void umount_usage(void);
- int chk_mountpoint(const char *mount_point);
- +char *utf8str2mbstr(const char *utf8_str);
- int nfs_umount23(const char *devname, char *string);
nfs-utils nfs://-URL support patch
Posted by Anonymous on Fri 1st Nov 2024 10:59
raw | new post
view followups (newest first): nfs-utils nfs://-URL support patch by Anonymous
modification of post by Anonymous (view diff)
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.