From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on inbox.vuxu.org X-Spam-Level: X-Spam-Status: No, score=-1.0 required=5.0 tests=MAILING_LIST_MULTI, RCVD_IN_DNSWL_NONE autolearn=ham autolearn_force=no version=3.4.2 Received: from primenet.com.au (ns1.primenet.com.au [203.24.36.2]) by inbox.vuxu.org (OpenSMTPD) with ESMTP id bd6a39f0 for ; Mon, 17 Feb 2020 15:46:14 +0000 (UTC) Received: (qmail 14809 invoked by alias); 17 Feb 2020 15:46:09 -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: 45454 Received: (qmail 15151 invoked by uid 1010); 17 Feb 2020 15:46:09 -0000 X-Qmail-Scanner-Diagnostics: from mailout1.w1.samsung.com by f.primenet.com.au (envelope-from , uid 7791) with qmail-scanner-2.11 (clamdscan: 0.102.2/25725. spamassassin: 3.4.2. Clear:RC:0(210.118.77.11):SA:0(-7.0/5.0):. Processed in 3.84307 secs); 17 Feb 2020 15:46:09 -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.11 as permitted sender) DKIM-Filter: OpenDKIM Filter v2.11.0 mailout1.w1.samsung.com 20200217154529euoutp0173d38cab323b88053e82e8a0c9637035~0OxTDnN-a1877118771euoutp01V X-AuditID: cbfec7f2-f0bff7000001ef66-71-5e4ab5196287 Message-ID: <1581954328.4418.19.camel@samsung.com> Subject: PATCH: sshfs user-side automount From: Peter Stephenson To: Zsh Hackers' List Date: Mon, 17 Feb 2020 15:45:28 +0000 X-Mailer: Evolution 3.18.5.2-0ubuntu3.2 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrNIsWRmVeSWpSXmKPExsWy7djPc7qSW73iDFbsEbQ42PyQyYHRY9XB D0wBjFFcNimpOZllqUX6dglcGdMmLmUu2OtS8WD/XMYGxh0WXYycHBICJhKP+m4zdzFycQgJ rGCUeN15kwUkISTQxySxeI8jRKKXSaLt/BoWmI7nq/vYIRLLGSU6vn5gh6t62/uLDcI5wyjx 9v5xxi5GDiDnAqPEyjyQbl4BI4kDVzewgdjCApoSzzZvAJvKJmAoMXXTbLByEQFtifaPYiBh FgFVifst2xkhFmtIbLh5jAlijKDEyZlPwFqZBeQlmrfOBntBQuAEm0T3sadMIHMkBFwknp7n gegVlnh1fAs7hC0jcXpyDwtEfTujxJpJr9khnB5GiU1H70Bts5bou30R7CBmoEPX79KHCDtK bLm7kBFiPp/EjbeCEDfwSUzaNp0ZIswr0dEmBFGtJrGjaStUtYzE0zUKEGEPiZvr+pkmMCrO QvLMLCTPzEJYu4CReRWjeGppcW56arFhXmq5XnFibnFpXrpecn7uJkZgEjj97/inHYxfLyUd YhTgYFTi4Q3o84oTYk0sK67MPcQowcGsJMLrLQ4U4k1JrKxKLcqPLyrNSS0+xCjNwaIkzmu8 6GWskEB6YklqdmpqQWoRTJaJg1OqgbHyyWnJeX4zgyqeaYi9N25mDr/dsDytIujJzc1dkccW VWuKr+SzSuidfuNeeNKTPdUz79r6m0VnqovFOMecTZFdsWi+WWWmQ9H5iEpdOcdGo8++Hvmq IrlOTDKTmDNv6bMdkpR2zHuVnKGZ8yO6bYeiNdvXg8mLt+58vDL43fxVd39M52GWU2Ipzkg0 1GIuKk4EAOQAFmH+AgAA X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFnrJLMWRmVeSWpSXmKPExsVy+t/xu7oSW73iDOZ0WFgcbH7I5MDoserg B6YAxig9m6L80pJUhYz84hJbpWhDCyM9Q0sLPSMTSz1DY/NYKyNTJX07m5TUnMyy1CJ9uwS9 jGkTlzIX7HWpeLB/LmMD4w6LLkZODgkBE4nnq/vYuxi5OIQEljJKbF2wiAkiISPx6cpHdghb WOLPtS42iKJuJomlyw4xQzhnGCWabnWxQjgXGCVO9p1nBGnhFTCSOHB1AxuILSygKfFs8wYW EJtNwFBi6qbZQDUcHCIC2hLtH8VAwiwCqhL3W7aDtTIDlbdu/w21WUNiw81jTBAjBSVOznzC AlEjL9G8dTbzBEaBWUhaZiEpm4WkbAEj8ypGkdTS4tz03GJDveLE3OLSvHS95PzcTYzAYN52 7OfmHYyXNgYfYhTgYFTi4Q3o84oTYk0sK67MPcQowcGsJMLrLQ4U4k1JrKxKLcqPLyrNSS0+ xGgKdPhEZinR5HxgpOWVxBuaGppbWBqaG5sbm1koifN2CByMERJITyxJzU5NLUgtgulj4uCU amDsqv23yuB00MN9AWIhuyx1dGS0TXmFtDY+ac1YKHD2/+5I57cJN7b8/7HMftGnXVOKPvtr PZm7oniTQP5uuUlSTXVXlinmf2yNVmycMI+ptFL8c7/rhospPf3VbqzvHQ+vmj3hwWPJsInv ZY4eEFkTsvjMD/5TZ9kU5TYfmm5TduDcHHH7q+VTlFiKMxINtZiLihMB48XXknwCAAA= X-CMS-MailID: 20200217154528eucas1p17c3730dd3979ce40eb383d7f6889c5e2 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: Hi, This certainly won't go in until the dust has settled, both on the release and the proposed change, but I'd quite like to add some user-side automount capability, in particular for the cdr system that I use quite a lot (though you can slot it in anywhere, including your own function front-end to cd). The point is, in case it's not obvious:  I use sshfs quite a lot for access to remote files these days, and as it's all done in user space there's no automatic way of getting an ssh directory mounted.  This is only really useful if you have seamless sshfs mounting, i.e. an ssh agent in the background. Obviously, please let me know whatever you don't like about it.  It'll probably grow, at least for my own purposes. It's documented as a style for cdr, which is how it's currently exposed, but if it goes in, chpwd_check_mount probably needs a separate entry in that section. The syntax is currently a bit of a mouthful, but it's hard to make it neater without also reducing flexibility. pws commit 6b1b417fb0da581f8186fbfaadfe8a8b07dc2b8c 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 c6bf745b7..252487fbb 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,6 +616,39 @@ 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 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). +This causes tt(sshfs) to be invoked with the option +tt(workaround=rename); this is likely to become configurable in future. +This is most useful when there is an ssh agent running in the +background, so that the mount action is invisible to the user. + +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/remote). + +Note that recursive mounting is also not currently handled, so +the var(local-path) directories should not be subdirectories of one +another. + +This style is provided by the function tt(chpwd_check_mount), which +can be run separately.  It takes a single argument, the path +to check.  This does not have to be a directory as prefixes +are examined. +)  enditem()    subsect(Use with dynamic directory naming) diff --git a/Functions/Chpwd/cdr b/Functions/Chpwd/cdr index 4bed88b13..7fc4345f6 100644 --- a/Functions/Chpwd/cdr +++ b/Functions/Chpwd/cdr @@ -268,6 +268,8 @@ else      1=1    elif [[ $# -ne 1 || $1 != <-> ]]; then      if zstyle -t ':chpwd:' recent-dirs-default; then +      # See below. +      (( $# == 1 )) && chpwd_check_mount $1        cd "$@"        return      else @@ -329,6 +331,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 +chwpd_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..adc0bc65f --- /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. +# +# Return 0 if the path is available, possibly after mounting, 1 if +# it is still not available at the end of the function. +# +# 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 moutning 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. +# +# 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. + +emulate -L zsh +setopt extendedglob cbases + +# 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 [[ -e $1 ]]; then +  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 +    files=($1/*(DN)) +    (( ${#files} )) && return 0 +  else +    # Not a directory, so assume everything is OK. +    return 0 +  fi +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 -a mpath +# If no directories we could mount, fail silently +zstyle -a ':chpwd:' mount-path mpath || return 1 + +local locdir remote mpoint + +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:(*)) +      if ! sshfs -o workaround=rename $match[1] $mpoint; then +        # Bad mount: it probably complained, but let's be clear. + print "$0: attempt to mount $remote for $locdir failed." >&2 + return 2 +      fi +      # Success / failure depending on whether path is now provided. +      # To be clever (see above) could loop further. +      [[ -e $dir ]] +      ;; + +      (*) +      # Incorrect configuration, so return noisily. +      print "$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 ]]