pastebin - collaborative debugging tool
nrubsig.kpaste.net RSS


nfsurl.ksh prototype
Posted by Anonymous on Wed 31st Jan 2024 13:43
raw | new post
view followups (newest first): nfsurlconv.ksh prototype by Anonymous
modification of post by Anonymous (view diff)

  1. #!/bin/ksh93
  2.  
  3. #
  4. # MIT License
  5. #
  6. # Copyright (c) 2024 Roland Mainz <roland.mainz@nrubsig.org>
  7. #
  8. # Permission is hereby granted, free of charge, to any person obtaining a copy
  9. # of this software and associated documentation files (the "Software"), to deal
  10. # in the Software without restriction, including without limitation the rights
  11. # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. # copies of the Software, and to permit persons to whom the Software is
  13. # furnished to do so, subject to the following conditions:
  14. #
  15. # The above copyright notice and this permission notice shall be included in all
  16. # copies or substantial portions of the Software.
  17. #
  18. # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  24. # SOFTWARE.
  25. #
  26.  
  27. #
  28. # nfsurlconv.ksh - convert host/port/path from/to a nfs://-URL
  29.  
  30. #
  31. # Written by Roland Mainz <roland.mainz@nrubsig.org>
  32. #
  33.  
  34. function usage
  35. {
  36.         (( OPTIND=0 ))
  37.         getopts -a "${1}" "${2}" OPT '-?'
  38.         return 2
  39. }
  40.  
  41. #
  42. # parse_rfc1738_url - parse RFC 1838 URLs
  43. #
  44. # Output variables are named after RFC 1838 Section 5 ("BNF for
  45. # specific URL schemes")
  46. #
  47. function parse_rfc1738_url
  48. {
  49.         set -o nounset
  50.  
  51.         typeset url="$2"
  52.         typeset leftover
  53.         nameref data="$1" # output compound variable
  54.  
  55.         # ~(E) is POSIX extended regular expression matching (instead
  56.         # of shell pattern), "x" means "multiline", "l" means "left
  57.         # anchor", "r" means "right anchor"
  58.         leftover="${url/~(Elrx)
  59.                 (.+?)                           # scheme
  60.                 :\/\/                           # '://'
  61.                 (                               # login
  62.                         (?:
  63.                                 (.+?)           # user (optional)
  64.                                 (?::(.+))?      # password (optional)
  65.                                 @
  66.                         )?
  67.                         (                       # hostport
  68.                                 (.+?)           # host
  69.                                 (?::([[:digit:]]+))? # port (optional)
  70.                         )
  71.                 )
  72.                 (?:\/(.*?))?/X}"                # path (optional)
  73.  
  74.         # All parsed data should be captured via eregex in .sh.match - if
  75.         # there is anything left (except the 'X') then the input string did
  76.         # not properly match the eregex
  77.         [[ "$leftover" == 'X' ]] ||
  78.                 { print -u2 -f $"%s: Parser error, leftover=%q\n" \
  79.                         "$0" "$leftover" ; return 1 ; }
  80.  
  81.         data.url="${.sh.match[0]}"
  82.         data.scheme="${.sh.match[1]}"
  83.         data.login="${.sh.match[2]}"
  84.         # FIXME: This should use [[ ! -v .sh.match[3] ]], but ksh93u has bugs
  85.         [[ "${.sh.match[3]-}" != '' ]] && data.user="${.sh.match[3]}"
  86.         [[ "${.sh.match[4]-}" != '' ]] && data.password="${.sh.match[4]}"
  87.         data.hostport="${.sh.match[5]}"
  88.         data.host="${.sh.match[6]}"
  89.         [[ "${.sh.match[7]-}" != '' ]] && integer data.port="${.sh.match[7]}"
  90.         [[ "${.sh.match[8]-}" != '' ]] && data.uripath="${.sh.match[8]}"
  91.  
  92.         if [[ -v data.uripath ]] ; then
  93.                 data.path="${ printf "${data.uripath//~(E)(?:%([[:xdigit:]][[:xdigit:]]))/\\x\1}" ; }"
  94.         fi
  95.  
  96.         return 0
  97. }
  98.  
  99.  
  100. function parse_sshnfs_url
  101. {
  102.         typeset url="$2"
  103.         nameref data="$1"
  104.  
  105.         parse_rfc1738_url data "$url" || return 1
  106.  
  107.         [[ "${data.scheme}" == ~(Elr)(ssh\+nfs|nfs) ]] || \
  108.                 { print -u2 -f $"%s: Not a nfs:// or ssh+nfs:// url\n" "$0" ; return 1 ; }
  109.         [[ "${data.host}" != '' ]] || { print -u2 -f $"%s: NFS hostname missing\n" "$0" ; return 1 ; }
  110.         [[ "${data.uripath}" != '' ]] || { print -u2 -f $"%s: NFS path missing\n" "$0" ; return 1 ; }
  111.         [[ "${data.uripath}" == /* ]] || { print -u2 -f $"%s: NFS path (%q) must be absolute\n" "$0" "${data.uripath}" ; return 1 ; }
  112.         [[ "${data.uripath}" != //* ]] || { print -u2 -f $"%s: NFS path (%q) should not start with '//' \n" "$0" "${data.uripath}" ; return 1 ; }
  113.  
  114.         return 0
  115. }
  116.  
  117.  
  118. function urlencodestr
  119. {
  120.         set -o nounset
  121.  
  122.         nameref out_encodedstr=$1
  123.         typeset in_str="$2"
  124.         typeset ch ch_hexval dummy
  125.         integer ch_num
  126.         typeset url=''
  127.  
  128.         #
  129.         # URLs encode non-ASCII characters as UTF-8 on byte-level,
  130.         # while POSIX shells (ksh93, bash, etc.) operate on
  131.         # characters (which *MAY* be - like UTF-8 - encoded as
  132.         # multibyte characters, but may use a different encoding
  133.         # like ISO8859-1 or GB18030).
  134.         # The code below solves that by using iconv(1) to
  135.         # convert everything into UTF-8 bytes, then convert the
  136.         # bytes via od(1) into pairs of { position, hexadecimal
  137.         # character value ("hexval") }, and then turn these to
  138.         # ASCII ("ch") / numeric ASCII ("ch_num") values
  139.         # (this assumes that the current LC_CTYPE is
  140.         # ASCII-compatible)
  141.         #
  142.         printf '%s' "$in_str" | \
  143.                 iconv -t 'UTF-8' | \
  144.                 od -t x1 -w1 -v | \
  145.                 while read dummy ch_hexval ; do
  146.                 [[ "$ch_hexval" != '' ]] || break
  147.  
  148.                 ch_num="${ printf "%d" "0x$ch_hexval" ; }"
  149.                 if (( ch_num <= 127 )) ; then
  150.                         typeset ch="${ printf "\x$ch_hexval" ; }"
  151.                 else
  152.                         #
  153.                         # character is outside ASCII, shell may
  154.                         # not be able to represent this
  155.                         #
  156.                         [[ -v ch ]] && unset ch
  157.                 fi
  158.  
  159.                 #
  160.                 # From RFC 1738 ("Uniform Resource Locators (URL)"):
  161.                 # unsafe characters in URLS:
  162.                 # "{", "}", "|", "\", "^", "~", "[", "]", and "`"
  163.                 # characters which must always be encoded:
  164.                 # "#", "%"
  165.                 # characters which must be encoded because they have a special meaning:
  166.                 # ";", "/", "?", ":", "@", "=" and "&"
  167.                 # Only alphanumerics, "$-_.+!*'()," and reserved characters
  168.                 # ("/" for nfs://-URLS) are allowed
  169.                 #
  170.                 if (( ch_num > 127 )) || [[ "$ch" != ~(Elr)[/$-_.+!*\'(),[:alnum:]] ]] ; then
  171.                         url+="%$ch_hexval"
  172.                 else
  173.                         url+="$ch"
  174.                 fi
  175.         done
  176.  
  177.         #printf 'str=%q\n' "$url"
  178.         out_encodedstr="$url"
  179.         return 0
  180. }
  181.  
  182.  
  183. function hostname_port_path_to_nfsurl
  184. {
  185.         set -o nounset
  186.  
  187.         typeset hostname="$1"
  188.         integer port="$2"
  189.         typeset path="$3"
  190.  
  191.         typeset enc_path
  192.         typeset enc_hostname
  193.  
  194.         urlencodestr enc_hostname "$hostname"
  195.         urlencodestr enc_path "$path"
  196.         if (( port == 2049 )) ; then
  197.                 printf 'url=nfs://%s/%s\n' "$enc_hostname" "$enc_path"
  198.         else
  199.                 printf 'url=nfs://%s:%d/%s\n' "$enc_hostname" port "$enc_path"
  200.         fi
  201.         return 0
  202. }
  203.  
  204. function main
  205. {
  206.         set -o nounset
  207.  
  208.         # fixme: Need better text layout for $ nfsurlconv --man #
  209.         typeset -r nfsurlconv_usage=$'+
  210.         [-?\n@(#)\$Id: nfsurlconv (Roland Mainz) 2024-01-31 \$\n]
  211.         [-author?Roland Mainz <roland.mainz@nrubsig.org>]
  212.         [+NAME?nfsurlconv - convert hostname,port,path from/to a nfs://-URL]
  213.         [+DESCRIPTION?\bnfsurlconv\b convert { hostname, port, path } from/to a nfs://-URL.]
  214.         [D:debug?Enable debugging.]
  215.  
  216.         hostnameportpath2nfsurl [options]
  217.         hostnamepath2nfsurl [options]
  218.         url2hostnameportpath [options]
  219.         url2hostportpath [options]
  220.         url2compound [options]
  221.         --man
  222.  
  223.         [+EXAMPLES]{
  224.                 [+?Example 1:][+?Convert hostname bbb, port 12049 and path /a/b/c to a nfs://-URL]{
  225. [+\n$ nfsurlconv hostnameportpath2nfsurl bbb 12049 "/a/b/c"
  226. url=nfs:://bbb::12049//a/b/c
  227. ]
  228. }
  229.                 [+?Example 2:][+?Convert URL nfs://bbb:12049//a/b/c to ( hostname=, port=, path= )]{
  230. [+\n$ nfsurlconv.ksh url2hostnameportpath nfs:://bbb//a/b/c
  231. hostname=bbb
  232. port=2049
  233. path=/a/b/c
  234. ]
  235. }
  236.                 [+?Example 3:][+?Convert URL nfs://bbb:12049//a/b/c to ( hostport=, path= )]{
  237. [+\n$ nfsurlconv.ksh url2hostportpath nfs:://bbb//a/b/c
  238. hostport=bbb
  239. path=/a/b/c
  240. ]
  241. }
  242.         }
  243.         [+SEE ALSO?\bksh93\b(1),\bssh\b(1),\bmount.nfs\b(8),\bnfs\b(5)]
  244.         '
  245.  
  246.         compound c
  247.         typeset -a c.args
  248.         integer saved_optind_m1 # saved OPTIND-1
  249.  
  250.         c.args=( "$@" )
  251.  
  252.         #
  253.         # Argument parsing
  254.         #
  255.         while getopts -a "${progname}" "${nfsurlconv_usage}" OPT "${c.args[@]}" ; do
  256.                 case "${OPT}" in
  257.                         'D')
  258.                                 # fixme: Implement debugging option
  259.                                 ;;
  260.                         *)
  261.                                 usage "${progname}" "${nfsurlconv_usage}"
  262.                                 return $?
  263.                                 ;;
  264.                 esac
  265.         done
  266.  
  267.         (( saved_optind_m1=OPTIND-1 ))
  268.  
  269.         # remove options we just parsed from c.args
  270.         for ((i=0 ; i < saved_optind_m1 ; i++)) ; do
  271.                 unset c.args[$i]
  272.         done
  273.  
  274.         #
  275.         # c.args mighth be a sparse array (e.g. "([1]=aaa [2]=bbb [4]=ccc)")
  276.         # right now after we removed processed options/arguments.
  277.         # For easier processing below we "reflow" the array back to a
  278.         # normal linear layout (e.g. ([0]=aaa [1]=bbb [2]=ccc)
  279.         #
  280.         c.args=( "${c.args[@]}" )
  281.  
  282.         typeset mode="$1"
  283.  
  284.         case "$mode" in
  285.                 'hostnameportpath2nfsurl')
  286.                         hostname_port_path_to_nfsurl "${@:2}"
  287.                         return $?
  288.                         ;;
  289.                 'hostnamepath2nfsurl')
  290.                         hostname_port_path_to_nfsurl "${@:2:1}" 2049 "${@:3:1}"
  291.                         return $?
  292.                         ;;
  293.                 'url2hostnameportpath')
  294.                         compound urldata
  295.  
  296.                         parse_sshnfs_url urldata "${@:2:1}" || return 1
  297.                         printf 'hostname=%s\n' "${urldata.host}"
  298.                         printf 'port=%s\n' "${urldata.port-2049}"
  299.                         printf 'path=%s\n' "${urldata.path-}"
  300.                         return 0
  301.                         ;;
  302.                 'url2hostportpath')
  303.                         compound urldata
  304.  
  305.                         parse_sshnfs_url urldata "${@:2:1}" || return 1
  306.                         printf 'hostport=%s\n' "${urldata.hostport}"
  307.                         printf 'path=%s\n' "${urldata.path-}"
  308.                         return 0
  309.                         ;;
  310.                 'url2compound')
  311.                         compound urldata
  312.  
  313.                         parse_sshnfs_url urldata "${@:2:1}" || return 1
  314.                         print -v urldata
  315.                         return 0
  316.                         ;;
  317.                 *)
  318.                         print -u2 -f $"Unknown mode %q\n" "$mode"
  319.                         usage "${progname}" "${nfsurlconv_usage}"
  320.                         return 2
  321.                         ;;
  322.         esac
  323.  
  324.         return 2
  325. }
  326.  
  327. #
  328. # main
  329. #
  330. builtin cat
  331. builtin mkdir
  332. builtin basename
  333.  
  334. typeset progname="${ basename "${0}" ; }"
  335.  
  336. main "$@"
  337. exit $?
  338.  
  339. # EOF.

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