From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=0.3 required=5.0 tests=MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE,RDNS_NONE,SPF_PASS autolearn=no autolearn_force=no version=3.4.2 Received: (qmail 24786 invoked from network); 16 Mar 2020 10:12:41 -0000 Received-SPF: pass (primenet.com.au: domain of zsh.org designates 203.24.36.2 as permitted sender) receiver=inbox.vuxu.org; client-ip=203.24.36.2 envelope-from= Received: from unknown (HELO primenet.com.au) (203.24.36.2) by inbox.vuxu.org with ESMTP; 16 Mar 2020 10:12:41 -0000 Received: (qmail 12677 invoked by alias); 16 Mar 2020 10:12:28 -0000 Mailing-List: contact zsh-workers-help@zsh.org; run by ezmlm Precedence: bulk X-No-Archive: yes List-Id: Zsh Workers List List-Post: List-Help: List-Unsubscribe: X-Seq: 45566 Received: (qmail 17744 invoked by uid 1010); 16 Mar 2020 10:12:28 -0000 X-Qmail-Scanner-Diagnostics: from mailout2.w1.samsung.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.102.2/25751. spamassassin: 3.4.2. Clear:RC:0(210.118.77.12):SA:0(-7.0/5.0):. Processed in 3.696461 secs); 16 Mar 2020 10:12:28 -0000 X-Envelope-From: p.stephenson@samsung.com X-Qmail-Scanner-Mime-Attachments: | X-Qmail-Scanner-Zip-Files: | Received-SPF: pass (ns1.primenet.com.au: SPF record at _spf.samsung.com designates 210.118.77.12 as permitted sender) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout2.w1.samsung.com 20200316101147euoutp02b7cc312dd3d56e6a277da99c4b334c25~8wR7X0F1C0366603666euoutp02a X-AuditID: cbfec7f5-a29ff7000001ed1a-16-5e6f50e2512a Message-ID: <1584353505.4512.3.camel@samsung.com> Subject: Re: PATCH: sshfs user-side automount From: Peter Stephenson To: Date: Mon, 16 Mar 2020 10:11:45 +0000 In-Reply-To: <1582024239.4529.13.camel@samsung.com> X-Mailer: Evolution 3.18.5.2-0ubuntu3.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrLIsWRmVeSWpSXmKPExsWy7djP87qPAvLjDJ7uNrM42PyQyYHRY9XB D0wBjFFcNimpOZllqUX6dglcGae21Bb88qu43qHewHjesYuRk0NCwETiweqpbF2MXBxCAisY JR68m8oM4fQxSexcfokJwullkjj1fh0jTMvDzmlQLcsZJVqvTkeoenfwPiOEc4ZR4tv7t1DO BUaJ7482M4H08woYSszo7mQDsYUFdCWm79wMZrMBxadumg22Q0RAUuJa82kwm0VAVWLHvgus IDangLFE65e37BB3aEhsuHkMaqagxMmZT1hAbGYBeYnmrbPBvpAQuM8msX/LTSCHA8hxkZj5 KQCiV1ji1fEtUHNkJE5P7mGBqG9nlFgz6TU7hNPDKLHp6B2or60l+m5fZAQZxCygKbF+lz5E 2FFiy92FjBDz+SRuvBWEuIFPYtK26VBreSU62oQgqtUkdjRthaqWkXi6RmECo9IsJA/MQvLA LIRVCxiZVzGKp5YW56anFhvnpZbrFSfmFpfmpesl5+duYgQmgtP/jn/dwbjvT9IhRgEORiUe Xom0vDgh1sSy4srcQ4wSHMxKIrwdNdlxQrwpiZVVqUX58UWlOanFhxilOViUxHmNF72MFRJI TyxJzU5NLUgtgskycXBKNTAa3D+m03xukau/3I2Oc69ec/HKTbp1t9Og/JaeiU9Fa1B4La+Q 8azTRW3SKyfsyb3wgH3evv0cm9fUmWUmFltt7X3ws2VfgEg5Z4qKU/g/gZsb7Fbt7mzzKu7r 09bc/7LkkJbxxk/n1AN+PJN2m69V3HLB+hN/+LzXOznqz+/WfVZ75MnSgholluKMREMt5qLi RADT54edAAMAAA== X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmpgkeLIzCtJLcpLzFFi42I5/e/4Xd1HAflxBhsbFCwONj9kcmD0WHXw A1MAY5SeTVF+aUmqQkZ+cYmtUrShhZGeoaWFnpGJpZ6hsXmslZGpkr6dTUpqTmZZapG+XYJe xqkttQW//Cqud6g3MJ537GLk5JAQMJF42DmNrYuRi0NIYCmjxK2r/9khEjISn658hLKFJf5c 62IDsYUEupkkTh+2hWg4wyix69lkJgjnAqPEp197wKp4BQwlZnR3gtnCAroS03duBrPZgOJT N81mBLFFBCQlrjWfBrNZBFQlduy7wApicwoYS7R+ecsOMfQZo8T/I9uZQRLMApoSrdt/Q52k IbHh5jEmiGWCEidnPmGBqJGXaN46m3kCo9AsJC2zkJTNQlK2gJF5FaNIamlxbnpusaFecWJu cWleul5yfu4mRmDobzv2c/MOxksbgw8xCnAwKvHwSqTlxQmxJpYVV+YeYpTgYFYS4e2oyY4T 4k1JrKxKLcqPLyrNSS0+xGgK9NFEZinR5HxgXOaVxBuaGppbWBqaG5sbm1koifN2CByMERJI TyxJzU5NLUgtgulj4uCUamAMf3K/zLhtt3DhDxaejypcWoUHjN7O7vYvYpXPC53C7pebJeNw K23zlKnZi25eXvbh25V1xSoHGuXvfbu7fcW26wx728y0eZX2x5wNEzv95OTnREX/L3NbMtX5 /C3uHbr9vzhm3dt3EgesbEwUL15+Vnv+cm7D3Dqh9z0L2Jysm/d+87PfWdmmxFKckWioxVxU nAgAap2zrJMCAAA= X-CMS-MailID: 20200316101146eucas1p248136de2f0bb902f85fad6db9dd53ccb X-Msg-Generator: CA Content-Type: text/plain; charset="utf-8" X-RootMTR: 20200217154528eucas1p17c3730dd3979ce40eb383d7f6889c5e2 X-EPHeader: CA CMS-TYPE: 201P X-CMS-RootMailID: 20200217154528eucas1p17c3730dd3979ce40eb383d7f6889c5e2 References: <1581954328.4418.19.camel@samsung.com> <20200218104451.1813845b@tarpaulin.shahaf.local2> <1582024239.4529.13.camel@samsung.com> Here's an updated version I intend to commit if there are not further comments. I've taken on board most of Daniel's comments, thanks. (Lines are marked as "preformatted" in Evolution --- I hope that removes hard spaces.) pws commit e8e950151b501011d0041c1955a55e151c564fde Author: Peter Stephenson Date:   Mon Feb 17 15:16:29 2020 +0000     Not yet posted: Add chpwd_check_mount to handle automatic sshfs mounting.          Use this in cdr. diff --git a/Doc/Zsh/contrib.yo b/Doc/Zsh/contrib.yo index 0909cd4f5..55285657a 100644 --- a/Doc/Zsh/contrib.yo +++ b/Doc/Zsh/contrib.yo @@ -386,6 +386,7 @@ findex(_cdr)  findex(chpwd_recent_add)  findex(chpwd_recent_dirs)  findex(chpwd_recent_filehandler) +findex(chpwd_check_mount)  sect(Remembering Recent Directories)    The function tt(cdr) allows you to change the working directory to a @@ -615,8 +616,77 @@ directory stack is completely separate from the list of files saved  by the mechanism used in this file there is no obvious reason to do  this.  ) +item(tt(mount-path))( +This style is provided by the function tt(chpwd_check_mount), which +is documented below in the subsection `Automatic sshfs mounting'.  This +allows user-side automounting of directories provide by tt(sshfs). +tt(cdr) already calls this function, so setting the style is +sufficient to enable this behaviour. +)  enditem()   +subsect(Automatic sshfs mounting) + +The function tt(chpwd_check_mount) is provided to allow user-side +automounting of directories by the tt(sshfs) command, a widely used +utility that can provide a user with no system privileges direct file +access to files visible via an tt(ssh) connection. + +The function takes a single argument, the path to check.  This does not +have to be a directory as prefixes are examined. + +This function is called by tt(cdr) so that this ability is provided +seamlessly in this case.  However, the function may also be called +directly, for example in a user's function front-end to the tt(cd) +builtin. + +To enable this feature, the tt(mount-path) style should be set in the +tt(:chpwd:) context.  The style takes pairs of arguments.  Each pair +consists of a local directory path var(local-path), and a remote path +for the form var(method):var(mount-spec).  If a directory to which +tt(cdr) needs to change does not exit, the list of var(local-path)s is +checked to see if one of them is a prefix of the target directory. +If one is found, the remote path is used to provide the directory. + +Currently the only var(method) handled is tt(sshfs), for which +var(mount-spec) should be a standard sshfs remote directory reference, +so var(mount-spec) may be e.g. tt(user@remotehost:/path/to/dir). +By default this causes tt(sshfs) to be invoked with the option +tt(workaround=rename); to change this, set the style tt(command-args) +in the context `tt(:chpwd:sshfs:)'.  The value should be an +array of command arguments preceding the remote directory and mount +point starting with the command itself, typically `tt(sshfs)', so +the default behaviour is equivalent to the following value: +example(zstyle ':chwpd:sshfs:' command-path sshfs -o workaround=rename) + +This is most useful when there is an ssh agent running in the +background, so that the mount action is invisible to the user. +See the manual page for manref(ssh-agent)(1) if you are unfamiliar with +this. + +The source path is not rendered canonical (symbolic links are not +removed), so it may be necessary to have multiple local directories +with the same remote path.  For this purpose, the local directory +path may take the form var(check-directory):var(mount-point). +For example, var(check-directory) may be tt(/home/mydir/doc), +a symbolic link to a directory under the var(mount-point) +tt(/home/mydir/mnt/remhost). + +Note that recursive mounting is also not currently handled, so +the var(local-path) directories should not be subdirectories of one +another. + +Here is a full style definition using the example above.  If +tt(cdr) attempts to switch to a non-existent directory below +tt(/home/mydir/doc) (or to tt(/home/mydir/doc) itself, if that exists +but is empy), an attempt will be made to mount files from +tt(myuser@remhost:/home/myuser) via tt(sshfs) at the mount point +tt(/home/mydir/mnt/remhost).  The resulting tt(cd) succeeds if the +originally requested directory is made available by this means. +example(zstyle :chpwd: mount-point \ +  /home/mydir/doc:/home/mydir/mnt/remhost \ +  sshfs:myuser@remhost:/home/myuser) +  subsect(Use with dynamic directory naming)    It is possible to refer to recent directories using the dynamic directory diff --git a/Functions/Chpwd/cdr b/Functions/Chpwd/cdr index 4bed88b13..d1818cd7d 100644 --- a/Functions/Chpwd/cdr +++ b/Functions/Chpwd/cdr @@ -268,6 +268,11 @@ else      1=1    elif [[ $# -ne 1 || $1 != <-> ]]; then      if zstyle -t ':chpwd:' recent-dirs-default; then +      if (( $# == 1 )); then + # See below. + autoload -Uz chpwd_check_mount + chpwd_check_mount $1 +      fi        cd "$@"        return      else @@ -329,6 +334,12 @@ if (( $1 > ${#reply} )); then  fi  dir=${reply[$1]}   +# This checks if the directory is available or can be mounted, +# and returns failure if not, but we'll simply pass back the +# (in context, more obvious) failure from pushd or cd. +autoload -Uz chpwd_check_mount +chpwd_check_mount $dir +  if zstyle -t ':chpwd:' recent-dirs-pushd; then    pushd -- $dir  else diff --git a/Functions/Chpwd/chpwd_check_mount b/Functions/Chpwd/chpwd_check_mount new file mode 100644 index 000000000..371fa181a --- /dev/null +++ b/Functions/Chpwd/chpwd_check_mount @@ -0,0 +1,107 @@ +# This function is designed to do a poor person's automount in +# the user space, typically of a sshfs file system as this is +# entirely controlled by the user. +# +# The return status is 0 if the path exists; 1 if it does not exist +# (even if a mount was made in an attempt to provide it); 2 if some +# condition other than a missing directory was found, in particular +# bad zstyle configuration or an sshfs failure. +# +# The style mount-path in context :chpwd: is set to an array of pairs of +# paths and URL-style references looking like +# +# /local/dir method:path-to-dir +# +# If the argument to the function is a path that doesn't exist, the +# system checks to see if the path is under /local/dir.  If, so the +# other element of the pair is examined.  If "method" is a known method +# for mounting the remote path path-to-dir the path, it is mounted and +# the function returns success. +# +# Currently the only method knonwn is sshfs, in which case path-to-dir +# is a standard ssh path e.g. "rhost:/home/mydir".  Mounting is done +# simply: "sshfs -o workaround=rename path-to_dir /local/dir".  This +# may become more configurable in future.  It is assumed the user +# has an appropriate ssh agent running, else the call may prompt for +# login info at an unexpected place. +# +# Does not currently handle (the unusual case of) recursive mounts, +# i.e. /local/dir and /local/dir/under/that does not handle the second case. + +emulate -L zsh +setopt extendedglob cbases + +local -a mpath +# If no directories we could mount, fail silently; +# no point even looking at the argument. +zstyle -a ':chpwd:' mount-path mpath || return 1 + +# Nothing to if path exists. +# +# We'll allow the path to be something other than a directory as we +# are in any case going to check prefixes. +if [[ -d $1 ]]; then +  # As this may be the mount point itself, we'll assume it +  # should be non-empty, though we don't know for sure. +  local -a files +  # Glob dots; expand to empty if no matches; don't bother globbing +  # more than one file, we just want to know if there are any +  files=($1/*(DNY1)) +  (( ${#files} )) && return 0 +elif [[ -e $1 ]]; then +  # Not a directory, so assume everything is OK. +  return 0 +fi + +local -a match mbegin mend +local dir +if [[ $1 = /* ]]; then +  dir="$1" +else +  # Hmm... We can't use (:a) or (:A) as the path doesn't yet exist in +  # the file system.  We'll just bang it on the end of $PWD.. +  # It's not clear whether we should remove symbolic links from +  # $PWD as we don't know whether the user has or has not rationalised +  # the zstyle accordingly. +  dir="$PWD/$1" +  # Rationalise ..'s --- a bit naive, but hopefully good enough... +  while [[ $dir = (#b)(*/)([^/]##)/..(/*|) ]]; do +    dir="$match[1]${match[3]##/}" +  done +  dir=${dir%%/#} +fi + +local locdir remote mpoint cmdargs + +for locdir remote in $mpath; do +  # To be clever here we would look for the shortest matching path +  # and work our way down. +  if [[ $dir = ${locdir%%:*}(|/*) ]]; then +    mpoint=${locdir#*:} +    case $remote in +      ((#b)sshfs:(*)) +      zstyle -a ':chpwd:sshfs:' command-args cmdargs || +   cmdargs=(sshfs -o workaround=rename) +      if ! "${cmdargs[@]}" "${match[1]}" "$mpoint"; then +        # Bad mount: it probably complained, but let's be clear. + print -r -- "$0: attempt to mount $remote for $locdir failed." >&2 + return 2 +      fi +      # Break for success / failure depending on whether path is now provided. +      # To be clever (see above) could loop further. +      break +      ;; + +      (*) +      # Incorrect configuration, so return noisily. +      print -r -- "$0: method ${remote%%:*} not handled" >&2 +      return 2 +      ;; +    esac +  fi +done + +# Final test in case we found something that might be a mount point. +# If we couldn't mount it but this is the directory being referred to, +# assume it's OK. +[[ -e $dir ]]