pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


nfs-utils nfs://-URL support patch
Posted by Anonymous on Fri 6th Dec 2024 10:31
raw | new post
view followups (newest first): nfs-utils nfs://-URL support patch by Anonymous
modification of post by Anonymous (view diff)

  1. From e7b5a3ac981727e4585288bd66d1a9b2dea045dc Mon Sep 17 00:00:00 2001
  2. From: Roland Mainz <roland.mainz@nrubsig.org>
  3. Date: Fri, 6 Dec 2024 10:58:48 +0100
  4. Subject: [PATCH] mount.nfs4: Add support for nfs://-URLs
  5.  
  6. Add support for RFC 2224-style nfs://-URLs as alternative to the
  7. traditional hostname:/path+-o port=<tcp-port> notation,
  8. providing standardised, extensible, single-string, crossplatform,
  9. portable, Character-Encoding independent (e.g. mount point with
  10. Japanese, Chinese, French etc. characters) and ASCII-compatible
  11. descriptions of NFSv4 server resources (exports).
  12.  
  13. Reviewed-by: Martin Wege <martin.l.wege@gmail.com>
  14. Signed-off-by: Cedric Blancher <cedric.blancher@gmail.com>
  15. ---
  16. utils/mount/Makefile.am  |   3 +-
  17.  utils/mount/nfs4mount.c  |  69 +++++++-
  18.  utils/mount/nfsmount.c   |  93 ++++++++--
  19.  utils/mount/parse_dev.c  |  67 ++++++--
  20.  utils/mount/stropts.c    |  96 ++++++++++-
  21.  utils/mount/urlparser1.c | 358 +++++++++++++++++++++++++++++++++++++++
  22.  utils/mount/urlparser1.h |  60 +++++++
  23.  utils/mount/utils.c      | 155 +++++++++++++++++
  24.  utils/mount/utils.h      |  23 +++
  25.  9 files changed, 887 insertions(+), 37 deletions(-)
  26.  create mode 100644 utils/mount/urlparser1.c
  27.  create mode 100644 utils/mount/urlparser1.h
  28.  
  29. diff --git a/utils/mount/Makefile.am b/utils/mount/Makefile.am
  30. index 83a8ee1c..0e4cab3e 100644
  31. --- a/utils/mount/Makefile.am
  32. +++ b/utils/mount/Makefile.am
  33. @@ -13,7 +13,8 @@ sbin_PROGRAMS = mount.nfs
  34.  EXTRA_DIST = nfsmount.conf $(man8_MANS) $(man5_MANS)
  35.  mount_common = error.c network.c token.c \
  36.                     parse_opt.c parse_dev.c \
  37. -                   nfsmount.c nfs4mount.c stropts.c\
  38. +                   nfsmount.c nfs4mount.c \
  39. +                   urlparser1.c urlparser1.h stropts.c \
  40.                     mount_constants.h error.h network.h token.h \
  41.                     parse_opt.h parse_dev.h \
  42.                     nfs4_mount.h stropts.h version.h \
  43. diff --git a/utils/mount/nfs4mount.c b/utils/mount/nfs4mount.c
  44. index 0fe142a7..8e4fbf30 100644
  45. --- a/utils/mount/nfs4mount.c
  46. +++ b/utils/mount/nfs4mount.c
  47. @@ -50,8 +50,10 @@
  48.  #include "mount_constants.h"
  49.  #include "nfs4_mount.h"
  50.  #include "nfs_mount.h"
  51. +#include "urlparser1.h"
  52.  #include "error.h"
  53.  #include "network.h"
  54. +#include "utils.h"
  55.  
  56.  #if defined(VAR_LOCK_DIR)
  57.  #define DEFAULT_DIR VAR_LOCK_DIR
  58. @@ -182,7 +184,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
  59.         int num_flavour = 0;
  60.         int ip_addr_in_opts = 0;
  61.  
  62. -       char *hostname, *dirname, *old_opts;
  63. +       char *hostname, *dirname, *mb_dirname = NULL, *old_opts;
  64.         char new_opts[1024];
  65.         char *opt, *opteq;
  66.         char *s;
  67. @@ -192,15 +194,66 @@ int nfs4mount(const char *spec, const char *node, int flags,
  68.         int retry;
  69.         int retval = EX_FAIL;
  70.         time_t timeout, t;
  71. +       int nfs_port = NFS_PORT;
  72. +       parsed_nfs_url pnu;
  73. +
  74. +       (void)memset(&pnu, 0, sizeof(parsed_nfs_url));
  75.  
  76.         if (strlen(spec) >= sizeof(hostdir)) {
  77.                 nfs_error(_("%s: excessively long host:dir argument\n"),
  78.                                 progname);
  79.                 goto fail;
  80.         }
  81. -       strcpy(hostdir, spec);
  82. -       if (parse_devname(hostdir, &hostname, &dirname))
  83. -               goto fail;
  84. +
  85. +       /*
  86. +        * Support nfs://-URLS per RFC 2224 ("NFS URL
  87. +        * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  88. +        * including custom port (nfs://hostname@port/path/...)
  89. +        * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
  90. +        * support
  91. +        */
  92. +       if (is_spec_nfs_url(spec)) {
  93. +               if (!mount_parse_nfs_url(spec, &pnu)) {
  94. +                       goto fail;
  95. +               }
  96. +
  97. +               /*
  98. +                * |pnu.uctx->path| is in UTF-8, but we need the data
  99. +                * in the current local locale's encoding, as mount(2)
  100. +                * does not have something like a |MS_UTF8_SPEC| flag
  101. +                * to indicate that the input path is in UTF-8,
  102. +                * independently of the current locale
  103. +                */
  104. +               hostname = pnu.uctx->hostport.hostname;
  105. +               dirname = mb_dirname = utf8str2mbstr(pnu.uctx->path);
  106. +
  107. +               (void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
  108. +                       hostname, dirname);
  109. +               spec = hostdir;
  110. +
  111. +               if (pnu.uctx->hostport.port != -1) {
  112. +                       nfs_port = pnu.uctx->hostport.port;
  113. +               }
  114. +
  115. +               /*
  116. +                * Values added here based on URL parameters
  117. +                * should be added the front of the list of options,
  118. +                * so users can override the nfs://-URL given default.
  119. +                *
  120. +                * FIXME: We do not do that here for |MS_RDONLY|!
  121. +                */
  122. +               if (pnu.mount_params.read_only != TRIS_BOOL_NOT_SET) {
  123. +                       if (pnu.mount_params.read_only)
  124. +                               flags |= MS_RDONLY;
  125. +                       else
  126. +                               flags &= ~MS_RDONLY;
  127. +               }
  128. +        } else {
  129. +               (void)strcpy(hostdir, spec);
  130. +
  131. +               if (parse_devname(hostdir, &hostname, &dirname))
  132. +                       goto fail;
  133. +       }
  134.  
  135.         if (fill_ipv4_sockaddr(hostname, &server_addr))
  136.                 goto fail;
  137. @@ -247,7 +300,7 @@ int nfs4mount(const char *spec, const char *node, int flags,
  138.         /*
  139.          * NFSv4 specifies that the default port should be 2049
  140.          */
  141. -       server_addr.sin_port = htons(NFS_PORT);
  142. +       server_addr.sin_port = htons(nfs_port);
  143.  
  144.         /* parse options */
  145.  
  146. @@ -474,8 +527,14 @@ int nfs4mount(const char *spec, const char *node, int flags,
  147.                 }
  148.         }
  149.  
  150. +       mount_free_parse_nfs_url(&pnu);
  151. +       free(mb_dirname);
  152. +
  153.         return EX_SUCCESS;
  154.  
  155.  fail:
  156. +       mount_free_parse_nfs_url(&pnu);
  157. +       free(mb_dirname);
  158. +
  159.         return retval;
  160.  }
  161. diff --git a/utils/mount/nfsmount.c b/utils/mount/nfsmount.c
  162. index a1c92fe8..e61d718a 100644
  163. --- a/utils/mount/nfsmount.c
  164. +++ b/utils/mount/nfsmount.c
  165. @@ -63,11 +63,13 @@
  166.  #include "xcommon.h"
  167.  #include "mount.h"
  168.  #include "nfs_mount.h"
  169. +#include "urlparser1.h"
  170.  #include "mount_constants.h"
  171.  #include "nls.h"
  172.  #include "error.h"
  173.  #include "network.h"
  174.  #include "version.h"
  175. +#include "utils.h"
  176.  
  177.  #ifdef HAVE_RPCSVC_NFS_PROT_H
  178.  #include <rpcsvc/nfs_prot.h>
  179. @@ -493,7 +495,7 @@ nfsmount(const char *spec, const char *node, int flags,
  180.          char **extra_opts, int fake, int running_bg)
  181.  {
  182.         char hostdir[1024];
  183. -       char *hostname, *dirname, *old_opts, *mounthost = NULL;
  184. +       char *hostname, *dirname, *mb_dirname = NULL, *old_opts, *mounthost = NULL;
  185.         char new_opts[1024], cbuf[1024];
  186.         static struct nfs_mount_data data;
  187.         int val;
  188. @@ -521,29 +523,79 @@ nfsmount(const char *spec, const char *node, int flags,
  189.         time_t t;
  190.         time_t prevt;
  191.         time_t timeout;
  192. +       int nfsurl_port = -1;
  193. +       parsed_nfs_url pnu;
  194. +
  195. +       (void)memset(&pnu, 0, sizeof(parsed_nfs_url));
  196.  
  197.         if (strlen(spec) >= sizeof(hostdir)) {
  198.                 nfs_error(_("%s: excessively long host:dir argument"),
  199.                                 progname);
  200.                 goto fail;
  201.         }
  202. -       strcpy(hostdir, spec);
  203. -       if ((s = strchr(hostdir, ':'))) {
  204. -               hostname = hostdir;
  205. -               dirname = s + 1;
  206. -               *s = '\0';
  207. -               /* Ignore all but first hostname in replicated mounts
  208. -                  until they can be fully supported. (mack@sgi.com) */
  209. -               if ((s = strchr(hostdir, ','))) {
  210. +
  211. +       /*
  212. +        * Support nfs://-URLS per RFC 2224 ("NFS URL
  213. +        * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  214. +        * including custom port (nfs://hostname@port/path/...)
  215. +        * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
  216. +        * support
  217. +        */
  218. +       if (is_spec_nfs_url(spec)) {
  219. +               if (!mount_parse_nfs_url(spec, &pnu)) {
  220. +                       goto fail;
  221. +               }
  222. +
  223. +               /*
  224. +                * |pnu.uctx->path| is in UTF-8, but we need the data
  225. +                * in the current local locale's encoding, as mount(2)
  226. +                * does not have something like a |MS_UTF8_SPEC| flag
  227. +                * to indicate that the input path is in UTF-8,
  228. +                * independently of the current locale
  229. +                */
  230. +               hostname = pnu.uctx->hostport.hostname;
  231. +               dirname = mb_dirname = utf8str2mbstr(pnu.uctx->path);
  232. +
  233. +               (void)snprintf(hostdir, sizeof(hostdir), "%s:/%s",
  234. +                       hostname, dirname);
  235. +               spec = hostdir;
  236. +
  237. +               if (pnu.uctx->hostport.port != -1) {
  238. +                       nfsurl_port = pnu.uctx->hostport.port;
  239. +               }
  240. +
  241. +               /*
  242. +                * Values added here based on URL parameters
  243. +                * should be added the front of the list of options,
  244. +                * so users can override the nfs://-URL given default.
  245. +                *
  246. +                * FIXME: We do not do that here for |MS_RDONLY|!
  247. +                */
  248. +               if (pnu.mount_params.read_only != TRIS_BOOL_NOT_SET) {
  249. +                       if (pnu.mount_params.read_only)
  250. +                               flags |= MS_RDONLY;
  251. +                       else
  252. +                               flags &= ~MS_RDONLY;
  253. +               }
  254. +        } else {
  255. +               (void)strcpy(hostdir, spec);
  256. +               if ((s = strchr(hostdir, ':'))) {
  257. +                       hostname = hostdir;
  258. +                       dirname = s + 1;
  259.                         *s = '\0';
  260. -                       nfs_error(_("%s: warning: "
  261. -                                 "multiple hostnames not supported"),
  262. +                       /* Ignore all but first hostname in replicated mounts
  263. +                          until they can be fully supported. (mack@sgi.com) */
  264. +                       if ((s = strchr(hostdir, ','))) {
  265. +                               *s = '\0';
  266. +                               nfs_error(_("%s: warning: "
  267. +                                       "multiple hostnames not supported"),
  268.                                         progname);
  269. -               }
  270. -       } else {
  271. -               nfs_error(_("%s: directory to mount not in host:dir format"),
  272. +                       }
  273. +               } else {
  274. +                       nfs_error(_("%s: directory to mount not in host:dir format"),
  275.                                 progname);
  276. -               goto fail;
  277. +                       goto fail;
  278. +               }
  279.         }
  280.  
  281.         if (!nfs_gethostbyname(hostname, nfs_saddr))
  282. @@ -579,6 +631,14 @@ nfsmount(const char *spec, const char *node, int flags,
  283.         memset(nfs_pmap, 0, sizeof(*nfs_pmap));
  284.         nfs_pmap->pm_prog = NFS_PROGRAM;
  285.  
  286. +       if (nfsurl_port != -1) {
  287. +               /*
  288. +                * Set custom TCP port defined by a nfs://-URL here,
  289. +                * so $ mount -o port ... # can be used to override
  290. +                */
  291. +               nfs_pmap->pm_port = nfsurl_port;
  292. +       }
  293. +
  294.         /* parse options */
  295.         new_opts[0] = 0;
  296.         if (!parse_options(old_opts, &data, &bg, &retry, &mnt_server, &nfs_server,
  297. @@ -863,10 +923,13 @@ noauth_flavors:
  298.                 }
  299.         }
  300.  
  301. +       mount_free_parse_nfs_url(&pnu);
  302. +
  303.         return EX_SUCCESS;
  304.  
  305.         /* abort */
  306.   fail:
  307. +       mount_free_parse_nfs_url(&pnu);
  308.         if (fsock != -1)
  309.                 close(fsock);
  310.         return retval;
  311. diff --git a/utils/mount/parse_dev.c b/utils/mount/parse_dev.c
  312. index 2ade5d5d..d9f8cf59 100644
  313. --- a/utils/mount/parse_dev.c
  314. +++ b/utils/mount/parse_dev.c
  315. @@ -27,6 +27,8 @@
  316.  #include "xcommon.h"
  317.  #include "nls.h"
  318.  #include "parse_dev.h"
  319. +#include "urlparser1.h"
  320. +#include "utils.h"
  321.  
  322.  #ifndef NFS_MAXHOSTNAME
  323.  #define NFS_MAXHOSTNAME                (255)
  324. @@ -179,17 +181,62 @@ static int nfs_parse_square_bracket(const char *dev,
  325.  }
  326.  
  327.  /*
  328. - * RFC 2224 says an NFS client must grok "public file handles" to
  329. - * support NFS URLs.  Linux doesn't do that yet.  Print a somewhat
  330. - * helpful error message in this case instead of pressing forward
  331. - * with the mount request and failing with a cryptic error message
  332. - * later.
  333. + * Support nfs://-URLS per RFC 2224 ("NFS URL
  334. + * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  335. + * including port support (nfs://hostname@port/path/...)
  336.   */
  337. -static int nfs_parse_nfs_url(__attribute__((unused)) const char *dev,
  338. -                            __attribute__((unused)) char **hostname,
  339. -                            __attribute__((unused)) char **pathname)
  340. +static int nfs_parse_nfs_url(const char *dev,
  341. +                            char **out_hostname,
  342. +                            char **out_pathname)
  343.  {
  344. -       nfs_error(_("%s: NFS URLs are not supported"), progname);
  345. +       parsed_nfs_url pnu;
  346. +
  347. +       if (out_hostname)
  348. +               *out_hostname = NULL;
  349. +       if (out_pathname)
  350. +               *out_pathname = NULL;
  351. +
  352. +       /*
  353. +        * Support nfs://-URLS per RFC 2224 ("NFS URL
  354. +        * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  355. +        * including custom port (nfs://hostname@port/path/...)
  356. +        * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
  357. +        * support
  358. +        */
  359. +       if (!mount_parse_nfs_url(dev, &pnu)) {
  360. +               goto fail;
  361. +       }
  362. +
  363. +       if (pnu.uctx->hostport.port != -1) {
  364. +               /* NOP here, unless we switch from hostname to hostport */
  365. +       }
  366. +
  367. +       if (out_hostname)
  368. +               *out_hostname = strdup(pnu.uctx->hostport.hostname);
  369. +       if (out_pathname)
  370. +               *out_pathname = utf8str2mbstr(pnu.uctx->path);
  371. +
  372. +       if (((out_hostname)?(*out_hostname == NULL):0) ||
  373. +               ((out_pathname)?(*out_pathname == NULL):0)) {
  374. +               nfs_error(_("%s: out of memory"),
  375. +                       progname);
  376. +               goto fail;
  377. +       }
  378. +
  379. +       mount_free_parse_nfs_url(&pnu);
  380. +
  381. +       return 1;
  382. +
  383. +fail:
  384. +       mount_free_parse_nfs_url(&pnu);
  385. +       if (out_hostname) {
  386. +               free(*out_hostname);
  387. +               *out_hostname = NULL;
  388. +       }
  389. +       if (out_pathname) {
  390. +               free(*out_pathname);
  391. +               *out_pathname = NULL;
  392. +       }
  393.         return 0;
  394.  }
  395.  
  396. @@ -223,7 +270,7 @@ int nfs_parse_devname(const char *devname,
  397.                 return nfs_pdn_nomem_err();
  398.         if (*dev == '[')
  399.                 result = nfs_parse_square_bracket(dev, hostname, pathname);
  400. -       else if (strncmp(dev, "nfs://", 6) == 0)
  401. +       else if (is_spec_nfs_url(dev))
  402.                 result = nfs_parse_nfs_url(dev, hostname, pathname);
  403.         else
  404.                 result = nfs_parse_simple_hostname(dev, hostname, pathname);
  405. diff --git a/utils/mount/stropts.c b/utils/mount/stropts.c
  406. index 23f0a8c0..ad92ab78 100644
  407. --- a/utils/mount/stropts.c
  408. +++ b/utils/mount/stropts.c
  409. @@ -42,6 +42,7 @@
  410.  #include "nls.h"
  411.  #include "nfsrpc.h"
  412.  #include "mount_constants.h"
  413. +#include "urlparser1.h"
  414.  #include "stropts.h"
  415.  #include "error.h"
  416.  #include "network.h"
  417. @@ -50,6 +51,7 @@
  418.  #include "parse_dev.h"
  419.  #include "conffile.h"
  420.  #include "misc.h"
  421. +#include "utils.h"
  422.  
  423.  #ifndef NFS_PROGRAM
  424.  #define NFS_PROGRAM    (100003)
  425. @@ -643,24 +645,106 @@ static int nfs_sys_mount(struct nfsmount_info *mi, struct mount_options *opts)
  426.  {
  427.         char *options = NULL;
  428.         int result;
  429. +       int nfs_port = 2049;
  430.  
  431.         if (mi->fake)
  432.                 return 1;
  433.  
  434. -       if (po_join(opts, &options) == PO_FAILED) {
  435. -               errno = EIO;
  436. -               return 0;
  437. -       }
  438. +       /*
  439. +        * Support nfs://-URLS per RFC 2224 ("NFS URL
  440. +        * SCHEME", see https://www.rfc-editor.org/rfc/rfc2224.html),
  441. +        * including custom port (nfs://hostname@port/path/...)
  442. +        * and URL parameter (e.g. nfs://.../?param1=val1&param2=val2
  443. +        * support
  444. +        */
  445. +       if (is_spec_nfs_url(mi->spec)) {
  446. +               parsed_nfs_url pnu;
  447. +               char *mb_path;
  448. +               char mount_source[1024];
  449. +
  450. +               if (!mount_parse_nfs_url(mi->spec, &pnu)) {
  451. +                       result = 1;
  452. +                       errno = EINVAL;
  453. +                       goto done;
  454. +               }
  455. +
  456. +               /*
  457. +                * |pnu.uctx->path| is in UTF-8, but we need the data
  458. +                * in the current local locale's encoding, as mount(2)
  459. +                * does not have something like a |MS_UTF8_SPEC| flag
  460. +                * to indicate that the input path is in UTF-8,
  461. +                * independently of the current locale
  462. +                */
  463. +               mb_path = utf8str2mbstr(pnu.uctx->path);
  464. +               if (!mb_path) {
  465. +                       nfs_error(_("%s: Could not convert path to local encoding."),
  466. +                               progname);
  467. +                       mount_free_parse_nfs_url(&pnu);
  468. +                       result = 1;
  469. +                       errno = EINVAL;
  470. +                       goto done;
  471. +               }
  472. +
  473. +               (void)snprintf(mount_source, sizeof(mount_source),
  474. +                       "%s:/%s",
  475. +                       pnu.uctx->hostport.hostname,
  476. +                       mb_path);
  477. +               free(mb_path);
  478. +
  479. +               if (pnu.uctx->hostport.port != -1) {
  480. +                       nfs_port = pnu.uctx->hostport.port;
  481. +               }
  482.  
  483. -       result = mount(mi->spec, mi->node, mi->type,
  484. +               /*
  485. +                * Insert "port=" option with the value from the nfs://
  486. +                * URL at the beginning of the list of options, so
  487. +                * users can override it with $ mount.nfs4 -o port= #,
  488. +                * e.g.
  489. +                * $ mount.nfs4 -o port=1234 nfs://10.49.202.230:400//bigdisk /mnt4 #
  490. +                * should use port 1234, and not port 400 as specified
  491. +                * in the URL.
  492. +                */
  493. +               char portoptbuf[5+32+1];
  494. +               (void)snprintf(portoptbuf, sizeof(portoptbuf), "port=%d", nfs_port);
  495. +               (void)po_insert(opts, portoptbuf);
  496. +
  497. +               if (pnu.mount_params.read_only != TRIS_BOOL_NOT_SET) {
  498. +                       if (pnu.mount_params.read_only)
  499. +                               mi->flags |= MS_RDONLY;
  500. +                       else
  501. +                               mi->flags &= ~MS_RDONLY;
  502. +               }
  503. +
  504. +               mount_free_parse_nfs_url(&pnu);
  505. +
  506. +               if (po_join(opts, &options) == PO_FAILED) {
  507. +                       errno = EIO;
  508. +                       result = 1;
  509. +                       goto done;
  510. +               }
  511. +
  512. +               result = mount(mount_source, mi->node, mi->type,
  513. +                       mi->flags & ~(MS_USER|MS_USERS), options);
  514. +               free(options);
  515. +       } else {
  516. +               if (po_join(opts, &options) == PO_FAILED) {
  517. +                       errno = EIO;
  518. +                       result = 1;
  519. +                       goto done;
  520. +               }
  521. +
  522. +               result = mount(mi->spec, mi->node, mi->type,
  523.                         mi->flags & ~(MS_USER|MS_USERS), options);
  524. -       free(options);
  525. +               free(options);
  526. +       }
  527.  
  528.         if (verbose && result) {
  529.                 int save = errno;
  530.                 nfs_error(_("%s: mount(2): %s"), progname, strerror(save));
  531.                 errno = save;
  532.         }
  533. +
  534. +done:
  535.         return !result;
  536.  }
  537.  
  538. diff --git a/utils/mount/urlparser1.c b/utils/mount/urlparser1.c
  539. new file mode 100644
  540. index 00000000..d4c6f339
  541. --- /dev/null
  542. +++ b/utils/mount/urlparser1.c
  543. @@ -0,0 +1,358 @@
  544. +/*
  545. + * MIT License
  546. + *
  547. + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
  548. + *
  549. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  550. + * of this software and associated documentation files (the "Software"), to deal
  551. + * in the Software without restriction, including without limitation the rights
  552. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  553. + * copies of the Software, and to permit persons to whom the Software is
  554. + * furnished to do so, subject to the following conditions:
  555. + *
  556. + * The above copyright notice and this permission notice shall be included in all
  557. + * copies or substantial portions of the Software.
  558. + *
  559. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  560. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  561. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  562. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  563. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  564. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  565. + * SOFTWARE.
  566. + */
  567. +
  568. +/* urlparser1.c - simple URL parser */
  569. +
  570. +#include <stdlib.h>
  571. +#include <stdbool.h>
  572. +#include <string.h>
  573. +#include <ctype.h>
  574. +#include <stdio.h>
  575. +
  576. +#ifdef DBG_USE_WIDECHAR
  577. +#include <wchar.h>
  578. +#include <locale.h>
  579. +#include <io.h>
  580. +#include <fcntl.h>
  581. +#endif /* DBG_USE_WIDECHAR */
  582. +
  583. +#include "urlparser1.h"
  584. +
  585. +typedef struct _url_parser_context_private {
  586. +       url_parser_context c;
  587. +
  588. +       /* Private data */
  589. +       char *parameter_string_buff;
  590. +} url_parser_context_private;
  591. +
  592. +#define MAX_URL_PARAMETERS 256
  593. +
  594. +/*
  595. + * Original extended regular expression:
  596. + *
  597. + * "^"
  598. + * "(.+?)"                             // scheme
  599. + * "://"                               // '://'
  600. + * "("                                 // login
  601. + *     "(?:"
  602. + *     "(.+?)"                         // user (optional)
  603. + *             "(?::(.+))?"            // password (optional)
  604. + *             "@"
  605. + *     ")?"
  606. + *     "("                             // hostport
  607. + *             "(.+?)"                 // host
  608. + *             "(?::([[:digit:]]+))?"  // port (optional)
  609. + *     ")"
  610. + * ")"
  611. + * "(?:/(.*?))?"                       // path (optional)
  612. + * "(?:\?(.*?))?"                      // URL parameters (optional)
  613. + * "$"
  614. + */
  615. +
  616. +#define DBGNULLSTR(s) (((s)!=NULL)?(s):"<NULL>")
  617. +#if 0 || defined(TEST_URLPARSER)
  618. +#define D(x) x
  619. +#else
  620. +#define D(x)
  621. +#endif
  622. +
  623. +#ifdef DBG_USE_WIDECHAR
  624. +/*
  625. + * Use wide-char APIs on WIN32, otherwise we cannot output
  626. + * Japanese/Chinese/etc correctly
  627. + */
  628. +#define DBG_PUTS(str, fp)              fputws(L"" str, (fp))
  629. +#define DBG_PUTC(c, fp)                        fputwc(btowc(c), (fp))
  630. +#define DBG_PRINTF(fp, fmt, ...)       fwprintf((fp), L"" fmt, __VA_ARGS__)
  631. +#else
  632. +#define DBG_PUTS(str, fp)              fputs((str), (fp))
  633. +#define DBG_PUTC(c, fp)                        fputc((c), (fp))
  634. +#define DBG_PRINTF(fp, fmt, ...)       fprintf((fp), fmt, __VA_ARGS__)
  635. +#endif /* DBG_USE_WIDECHAR */
  636. +
  637. +static
  638. +void urldecodestr(char *outbuff, const char *buffer, size_t len)
  639. +{
  640. +       size_t i, j;
  641. +
  642. +       for (i = j = 0 ; i < len ; ) {
  643. +               switch (buffer[i]) {
  644. +                       case '%':
  645. +                               if ((i + 2) < len) {
  646. +                                       if (isxdigit((int)buffer[i+1]) && isxdigit((int)buffer[i+2])) {
  647. +                                               const char hexstr[3] = {
  648. +                                                       buffer[i+1],
  649. +                                                       buffer[i+2],
  650. +                                                       '\0'
  651. +                                               };
  652. +                                               outbuff[j++] = (unsigned char)strtol(hexstr, NULL, 16);
  653. +                                               i += 3;
  654. +                                       } else {
  655. +                                               /* invalid hex digit */
  656. +                                               outbuff[j++] = buffer[i];
  657. +                                               i++;
  658. +                                       }
  659. +                               } else {
  660. +                                       /* incomplete hex digit */
  661. +                                       outbuff[j++] = buffer[i];
  662. +                                       i++;
  663. +                               }
  664. +                               break;
  665. +                       case '+':
  666. +                               outbuff[j++] = ' ';
  667. +                               i++;
  668. +                               break;
  669. +                       default:
  670. +                               outbuff[j++] = buffer[i++];
  671. +                               break;
  672. +               }
  673. +       }
  674. +
  675. +       outbuff[j] = '\0';
  676. +}
  677. +
  678. +url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags)
  679. +{
  680. +       url_parser_context_private *uctx;
  681. +       char *s;
  682. +       size_t in_url_len;
  683. +       size_t context_len;
  684. +
  685. +       /* |flags| is for future extensions */
  686. +       (void)flags;
  687. +
  688. +       if (!in_url)
  689. +               return NULL;
  690. +
  691. +       in_url_len = strlen(in_url);
  692. +
  693. +       context_len = sizeof(url_parser_context_private) +
  694. +               ((in_url_len+1)*6) +
  695. +               (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
  696. +       uctx = malloc(context_len);
  697. +       if (!uctx)
  698. +               return NULL;
  699. +
  700. +       s = (void *)(uctx+1);
  701. +       uctx->c.in_url = s;             s+= in_url_len+1;
  702. +       (void)strcpy(uctx->c.in_url, in_url);
  703. +       uctx->c.scheme = s;             s+= in_url_len+1;
  704. +       uctx->c.login.username = s;     s+= in_url_len+1;
  705. +       uctx->c.hostport.hostname = s;  s+= in_url_len+1;
  706. +       uctx->c.path = s;               s+= in_url_len+1;
  707. +       uctx->c.hostport.port = -1;
  708. +       uctx->c.num_parameters = -1;
  709. +       uctx->c.parameters = (void *)s;         s+= (sizeof(url_parser_name_value)*MAX_URL_PARAMETERS)+sizeof(void*);
  710. +       uctx->parameter_string_buff = s;        s+= in_url_len+1;
  711. +
  712. +       return &uctx->c;
  713. +}
  714. +
  715. +int url_parser_parse(url_parser_context *ctx)
  716. +{
  717. +       url_parser_context_private *uctx = (url_parser_context_private *)ctx;
  718. +
  719. +       D((void)DBG_PRINTF(stderr, "## parser in_url='%s'\n", uctx->c.in_url));
  720. +
  721. +       char *s;
  722. +       const char *urlstr = uctx->c.in_url;
  723. +       size_t slen;
  724. +
  725. +       s = strstr(urlstr, "://");
  726. +       if (!s) {
  727. +               D((void)DBG_PUTS("url_parser: Not an URL\n", stderr));
  728. +               return -1;
  729. +       }
  730. +
  731. +       slen = s-urlstr;
  732. +       (void)memcpy(uctx->c.scheme, urlstr, slen);
  733. +       uctx->c.scheme[slen] = '\0';
  734. +       urlstr += slen + 3;
  735. +
  736. +       D((void)DBG_PRINTF(stdout, "scheme='%s', rest='%s'\n", uctx->c.scheme, urlstr));
  737. +
  738. +       s = strstr(urlstr, "@");
  739. +       if (s) {
  740. +               /* URL has user/password */
  741. +               slen = s-urlstr;
  742. +               urldecodestr(uctx->c.login.username, urlstr, slen);
  743. +               urlstr += slen + 1;
  744. +
  745. +               s = strstr(uctx->c.login.username, ":");
  746. +               if (s) {
  747. +                       /* found passwd */
  748. +                       uctx->c.login.passwd = s+1;
  749. +                       *s = '\0';
  750. +               }
  751. +               else {
  752. +                       uctx->c.login.passwd = NULL;
  753. +               }
  754. +
  755. +               /* catch password-only URLs */
  756. +               if (uctx->c.login.username[0] == '\0')
  757. +                       uctx->c.login.username = NULL;
  758. +       }
  759. +       else {
  760. +               uctx->c.login.username = NULL;
  761. +               uctx->c.login.passwd = NULL;
  762. +       }
  763. +
  764. +       D((void)DBG_PRINTF(stdout, "login='%s', passwd='%s', rest='%s'\n",
  765. +               DBGNULLSTR(uctx->c.login.username),
  766. +               DBGNULLSTR(uctx->c.login.passwd),
  767. +               DBGNULLSTR(urlstr)));
  768. +
  769. +       char *raw_parameters;
  770. +
  771. +       uctx->c.num_parameters = 0;
  772. +       raw_parameters = strstr(urlstr, "?");
  773. +       /* Do we have a non-empty parameter string ? */
  774. +       if (raw_parameters && (raw_parameters[1] != '\0')) {
  775. +               *raw_parameters++ = '\0';
  776. +               D((void)DBG_PRINTF(stdout, "raw parameters = '%s'\n", raw_parameters));
  777. +
  778. +               char *ps = raw_parameters;
  779. +               char *pv; /* parameter value */
  780. +               char *na; /* next '&' */
  781. +               char *pb = uctx->parameter_string_buff;
  782. +               char *pname;
  783. +               char *pvalue;
  784. +               ssize_t pi;
  785. +
  786. +               for (pi = 0; pi < MAX_URL_PARAMETERS ; pi++) {
  787. +                       pname = ps;
  788. +
  789. +                       /*
  790. +                        * Handle parameters without value,
  791. +                        * e.g. "path?name1&name2=value2"
  792. +                        */
  793. +                       na = strstr(ps, "&");
  794. +                       pv = strstr(ps, "=");
  795. +                       if (pv && (na?(na > pv):true)) {
  796. +                               *pv++ = '\0';
  797. +                               pvalue = pv;
  798. +                               ps = pv;
  799. +                       }
  800. +                       else {
  801. +                               pvalue = NULL;
  802. +                       }
  803. +
  804. +                       if (na) {
  805. +                               *na++ = '\0';
  806. +                       }
  807. +
  808. +                       /* URLDecode parameter name */
  809. +                       urldecodestr(pb, pname, strlen(pname));
  810. +                       uctx->c.parameters[pi].name = pb;
  811. +                       pb += strlen(uctx->c.parameters[pi].name)+1;
  812. +
  813. +                       /* URLDecode parameter value */
  814. +                       if (pvalue) {
  815. +                               urldecodestr(pb, pvalue, strlen(pvalue));
  816. +                               uctx->c.parameters[pi].value = pb;
  817. +                               pb += strlen(uctx->c.parameters[pi].value)+1;
  818. +                       }
  819. +                       else {
  820. +                               uctx->c.parameters[pi].value = NULL;
  821. +                       }
  822. +
  823. +                       /* Next '&' ? */
  824. +                       if (!na)
  825. +                               break;
  826. +
  827. +                       ps = na;
  828. +               }
  829. +
  830. +               uctx->c.num_parameters = pi+1;
  831. +       }
  832. +
  833. +       s = strstr(urlstr, "/");
  834. +       if (s) {
  835. +               /* URL has hostport */
  836. +               slen = s-urlstr;
  837. +               urldecodestr(uctx->c.hostport.hostname, urlstr, slen);
  838. +               urlstr += slen + 1;
  839. +
  840. +               /*
  841. +                * check for addresses within '[' and ']', like
  842. +                * IPv6 addresses
  843. +                */
  844. +               s = uctx->c.hostport.hostname;
  845. +               if (s[0] == '[')
  846. +                       s = strstr(s, "]");
  847. +
  848. +               if (s == NULL) {
  849. +                       D((void)DBG_PUTS("url_parser: Unmatched '[' in hostname\n", stderr));
  850. +                       return -1;
  851. +               }
  852. +
  853. +               s = strstr(s, ":");
  854. +               if (s) {
  855. +                       /* found port number */
  856. +                       uctx->c.hostport.port = atoi(s+1);
  857. +                       *s = '\0';
  858. +               }
  859. +       }
  860. +       else {
  861. +               (void)strcpy(uctx->c.hostport.hostname, urlstr);
  862. +               uctx->c.path = NULL;
  863. +               urlstr = NULL;
  864. +       }
  865. +
  866. +       D(
  867. +               (void)DBG_PRINTF(stdout,
  868. +                       "hostport='%s', port=%d, rest='%s', num_parameters=%d\n",
  869. +                       DBGNULLSTR(uctx->c.hostport.hostname),
  870. +                       uctx->c.hostport.port,
  871. +                       DBGNULLSTR(urlstr),
  872. +                       (int)uctx->c.num_parameters);
  873. +       );
  874. +
  875. +
  876. +       D(
  877. +               ssize_t dpi;
  878. +               for (dpi = 0 ; dpi < uctx->c.num_parameters ; dpi++) {
  879. +                       (void)DBG_PRINTF(stdout,
  880. +                               "param[%d]: name='%s'/value='%s'\n",
  881. +                               (int)dpi,
  882. +                               uctx->c.parameters[dpi].name,
  883. +                               DBGNULLSTR(uctx->c.parameters[dpi].value));
  884. +               }
  885. +       );
  886. +
  887. +       if (!urlstr) {
  888. +               goto done;
  889. +       }
  890. +
  891. +       urldecodestr(uctx->c.path, urlstr, strlen(urlstr));
  892. +       D((void)DBG_PRINTF(stdout, "path='%s'\n", uctx->c.path));
  893. +
  894. +done:
  895. +       return 0;
  896. +}
  897. +
  898. +void url_parser_free_context(url_parser_context *c)
  899. +{
  900. +       free(c);
  901. +}
  902. diff --git a/utils/mount/urlparser1.h b/utils/mount/urlparser1.h
  903. new file mode 100644
  904. index 00000000..515eea9d
  905. --- /dev/null
  906. +++ b/utils/mount/urlparser1.h
  907. @@ -0,0 +1,60 @@
  908. +/*
  909. + * MIT License
  910. + *
  911. + * Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
  912. + *
  913. + * Permission is hereby granted, free of charge, to any person obtaining a copy
  914. + * of this software and associated documentation files (the "Software"), to deal
  915. + * in the Software without restriction, including without limitation the rights
  916. + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  917. + * copies of the Software, and to permit persons to whom the Software is
  918. + * furnished to do so, subject to the following conditions:
  919. + *
  920. + * The above copyright notice and this permission notice shall be included in all
  921. + * copies or substantial portions of the Software.
  922. + *
  923. + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  924. + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  925. + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  926. + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  927. + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  928. + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  929. + * SOFTWARE.
  930. + */
  931. +
  932. +/* urlparser1.h - header for simple URL parser */
  933. +
  934. +#ifndef __URLPARSER1_H__
  935. +#define __URLPARSER1_H__ 1
  936. +
  937. +#include <stdlib.h>
  938. +
  939. +typedef struct _url_parser_name_value {
  940. +       char *name;
  941. +       char *value;
  942. +} url_parser_name_value;
  943. +
  944. +typedef struct _url_parser_context {
  945. +       char *in_url;
  946. +
  947. +       char *scheme;
  948. +       struct {
  949. +               char *username;
  950. +               char *passwd;
  951. +       } login;
  952. +       struct {
  953. +               char *hostname;
  954. +               signed int port;
  955. +       } hostport;
  956. +       char *path;
  957. +
  958. +       ssize_t num_parameters;
  959. +       url_parser_name_value *parameters;
  960. +} url_parser_context;
  961. +
  962. +/* Prototypes */
  963. +url_parser_context *url_parser_create_context(const char *in_url, unsigned int flags);
  964. +int url_parser_parse(url_parser_context *uctx);
  965. +void url_parser_free_context(url_parser_context *c);
  966. +
  967. +#endif /* !__URLPARSER1_H__ */
  968. diff --git a/utils/mount/utils.c b/utils/mount/utils.c
  969. index b7562a47..2d4cfa5a 100644
  970. --- a/utils/mount/utils.c
  971. +++ b/utils/mount/utils.c
  972. @@ -28,6 +28,7 @@
  973.  #include <unistd.h>
  974.  #include <sys/types.h>
  975.  #include <sys/stat.h>
  976. +#include <iconv.h>
  977.  
  978.  #include "sockaddr.h"
  979.  #include "nfs_mount.h"
  980. @@ -173,3 +174,157 @@ int nfs_umount23(const char *devname, char *string)
  981.         free(dirname);
  982.         return result;
  983.  }
  984. +
  985. +/* Convert UTF-8 string to multibyte string in the current locale */
  986. +char *utf8str2mbstr(const char *utf8_str)
  987. +{
  988. +       iconv_t cd;
  989. +
  990. +       cd = iconv_open("UTF-8", "");
  991. +       if (cd == (iconv_t)-1) {
  992. +               perror("utf8str2mbstr: iconv_open failed");
  993. +               return NULL;
  994. +       }
  995. +
  996. +       size_t inbytesleft = strlen(utf8_str);
  997. +       char *inbuf = (char *)utf8_str;
  998. +       size_t outbytesleft = inbytesleft*4+1;
  999. +       char *outbuf = malloc(outbytesleft);
  1000. +       char *outbuf_orig = outbuf;
  1001. +
  1002. +       if (!outbuf) {
  1003. +               perror("utf8str2mbstr: out of memory");
  1004. +               (void)iconv_close(cd);
  1005. +               return NULL;
  1006. +       }
  1007. +
  1008. +       int ret = iconv(cd, &inbuf, &inbytesleft, &outbuf, &outbytesleft);
  1009. +       if (ret == -1) {
  1010. +               perror("utf8str2mbstr: iconv() failed");
  1011. +               free(outbuf_orig);
  1012. +               (void)iconv_close(cd);
  1013. +               return NULL;
  1014. +       }
  1015. +
  1016. +       *outbuf = '\0';
  1017. +
  1018. +       (void)iconv_close(cd);
  1019. +       return outbuf_orig;
  1020. +}
  1021. +
  1022. +/* fixme: We should use |bool|! */
  1023. +int is_spec_nfs_url(const char *spec)
  1024. +{
  1025. +       return (!strncmp(spec, "nfs://", 6));
  1026. +}
  1027. +
  1028. +int mount_parse_nfs_url(const char *spec, parsed_nfs_url *pnu)
  1029. +{
  1030. +       int result = 1;
  1031. +       url_parser_context *uctx = NULL;
  1032. +
  1033. +       (void)memset(pnu, 0, sizeof(parsed_nfs_url));
  1034. +       pnu->mount_params.read_only = TRIS_BOOL_NOT_SET;
  1035. +
  1036. +       uctx = url_parser_create_context(spec, 0);
  1037. +       if (!uctx) {
  1038. +               nfs_error(_("%s: out of memory"),
  1039. +                       progname);
  1040. +               result = 1;
  1041. +               goto done;
  1042. +       }
  1043. +
  1044. +       if (url_parser_parse(uctx) < 0) {
  1045. +               nfs_error(_("%s: Error parsing nfs://-URL."),
  1046. +                       progname);
  1047. +               result = 1;
  1048. +               goto done;
  1049. +       }
  1050. +       if (uctx->login.username || uctx->login.passwd) {
  1051. +               nfs_error(_("%s: Username/Password are not defined for nfs://-URL."),
  1052. +                       progname);
  1053. +               result = 1;
  1054. +               goto done;
  1055. +       }
  1056. +       if (!uctx->path) {
  1057. +               nfs_error(_("%s: Path missing in nfs://-URL."),
  1058. +                       progname);
  1059. +               result = 1;
  1060. +               goto done;
  1061. +       }
  1062. +       if (uctx->path[0] != '/') {
  1063. +               nfs_error(_("%s: Relative nfs://-URLs are not supported."),
  1064. +                       progname);
  1065. +               result = 1;
  1066. +               goto done;
  1067. +       }
  1068. +
  1069. +       if (uctx->num_parameters > 0) {
  1070. +               int pi;
  1071. +               const char *pname;
  1072. +               const char *pvalue;
  1073. +
  1074. +               /*
  1075. +                * Values added here based on URL parameters
  1076. +                * should be added the front of the list of options,
  1077. +                * so users can override the nfs://-URL given default.
  1078. +                */
  1079. +               for (pi = 0; pi < uctx->num_parameters ; pi++) {
  1080. +                       pname = uctx->parameters[pi].name;
  1081. +                       pvalue = uctx->parameters[pi].value;
  1082. +
  1083. +                       if (!strcmp(pname, "rw")) {
  1084. +                               if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
  1085. +                                       pnu->mount_params.read_only = TRIS_BOOL_FALSE;
  1086. +                               }
  1087. +                               else if (!strcmp(pvalue, "0")) {
  1088. +                                       pnu->mount_params.read_only = TRIS_BOOL_TRUE;
  1089. +                               }
  1090. +                               else {
  1091. +                                       nfs_error(_("%s: Unsupported nfs://-URL "
  1092. +                                               "parameter '%s' value '%s'."),
  1093. +                                               progname, pname, pvalue);
  1094. +                                       result = 1;
  1095. +                                       goto done;
  1096. +                               }
  1097. +                       }
  1098. +                       else if (!strcmp(pname, "ro")) {
  1099. +                               if ((pvalue == NULL) || (!strcmp(pvalue, "1"))) {
  1100. +                                       pnu->mount_params.read_only = TRIS_BOOL_TRUE;
  1101. +                               }
  1102. +                               else if (!strcmp(pvalue, "0")) {
  1103. +                                       pnu->mount_params.read_only = TRIS_BOOL_FALSE;
  1104. +                               }
  1105. +                               else {
  1106. +                                       nfs_error(_("%s: Unsupported nfs://-URL "
  1107. +                                               "parameter '%s' value '%s'."),
  1108. +                                               progname, pname, pvalue);
  1109. +                                       result = 1;
  1110. +                                       goto done;
  1111. +                               }
  1112. +                       }
  1113. +                       else {
  1114. +                               nfs_error(_("%s: Unsupported nfs://-URL "
  1115. +                                               "parameter '%s'."),
  1116. +                                       progname, pname);
  1117. +                               result = 1;
  1118. +                               goto done;
  1119. +                       }
  1120. +               }
  1121. +       }
  1122. +
  1123. +       result = 0;
  1124. +done:
  1125. +       if (result != 0) {
  1126. +               url_parser_free_context(uctx);
  1127. +               return 0;
  1128. +       }
  1129. +
  1130. +       pnu->uctx = uctx;
  1131. +       return 1;
  1132. +}
  1133. +
  1134. +void mount_free_parse_nfs_url(parsed_nfs_url *pnu)
  1135. +{
  1136. +       url_parser_free_context(pnu->uctx);
  1137. +}
  1138. diff --git a/utils/mount/utils.h b/utils/mount/utils.h
  1139. index 224918ae..465c0a5e 100644
  1140. --- a/utils/mount/utils.h
  1141. +++ b/utils/mount/utils.h
  1142. @@ -24,13 +24,36 @@
  1143.  #define _NFS_UTILS_MOUNT_UTILS_H
  1144.  
  1145.  #include "parse_opt.h"
  1146. +#include "urlparser1.h"
  1147.  
  1148. +/* Boolean with three states: { not_set, false, true */
  1149. +typedef signed char tristate_bool;
  1150. +#define TRIS_BOOL_NOT_SET (-1)
  1151. +#define TRIS_BOOL_TRUE (1)
  1152. +#define TRIS_BOOL_FALSE (0)
  1153. +
  1154. +#define TRIS_BOOL_GET_VAL(tsb, tsb_default) \
  1155. +       (((tsb)!=TRIS_BOOL_NOT_SET)?(tsb):(tsb_default))
  1156. +
  1157. +typedef struct _parsed_nfs_url {
  1158. +       url_parser_context *uctx;
  1159. +       struct {
  1160. +               tristate_bool read_only;
  1161. +       } mount_params;
  1162. +} parsed_nfs_url;
  1163. +
  1164. +/* Prototypes */
  1165.  int discover_nfs_mount_data_version(int *string_ver);
  1166.  void print_one(char *spec, char *node, char *type, char *opts);
  1167.  void mount_usage(void);
  1168.  void umount_usage(void);
  1169.  int chk_mountpoint(const char *mount_point);
  1170. +char *utf8str2mbstr(const char *utf8_str);
  1171. +int is_spec_nfs_url(const char *spec);
  1172.  
  1173.  int nfs_umount23(const char *devname, char *string);
  1174.  
  1175. +int mount_parse_nfs_url(const char *spec, parsed_nfs_url *pnu);
  1176. +void mount_free_parse_nfs_url(parsed_nfs_url *pnu);
  1177. +
  1178.  #endif /* !_NFS_UTILS_MOUNT_UTILS_H */
  1179. --
  1180. 2.30.2

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