zsh-workers
 help / color / mirror / code / Atom feed
* [PATCH] Completion: Add _hostname (+ a question)
@ 2018-06-17 22:20 dana
  2018-06-17 23:02 ` Oliver Kiddle
  0 siblings, 1 reply; 3+ messages in thread
From: dana @ 2018-06-17 22:20 UTC (permalink / raw)
  To: Zsh workers

This is a new completion function for the hostname command.

For Dragonfly i needed to complete locally bound IP addresses (see bottom). The
_bind_addresses type function was presumably intended for just this kind of
thing... except that all it does on many systems is call _hosts. That doesn't
seem appropriate at all in cases like this, nor in the cases where the function
is already being used, such as `ssh -b` and `rsync --address`.

Instead of doing my own thing here, would there be any issue with my changing
_bind_addresses to unconditionally return the actual interface addresses using a
similar method (maybe with a few flags to control inclusion of loop-backs, &c.)?
If so, i'll prepare an improved patch.

dana


diff --git a/Completion/Unix/Command/_hostname b/Completion/Unix/Command/_hostname
new file mode 100644
index 000000000..22127fed7
--- /dev/null
+++ b/Completion/Unix/Command/_hostname
@@ -0,0 +1,77 @@
+#compdef hostname
+
+local ret=1
+local -a context line state state_descr args aopts tmp
+local -A opt_args
+
+if _pick_variant net-tools=--yp unix --help; then
+  args=(
+    '(: * -)'{-h,--help}'[display help information]'
+    '(: * -)'{-V,--version}'[display version information]'
+    + '(g)' # Get
+    '(: gs s)'{-A,--all-fqdns}'[display FQDNs resolved from network interface addresses]'
+    '(: gs s)'{-d,--domain}'[display DNS domain only]'
+    '(: gs s)'{-f,--fqdn,--long}'[display host name with DNS domain (FQDN)]'
+    '(: gs s)'{-i,--ip-address}'[display IP addresses for host (via DNS resolution)]'
+    '(: gs s)'{-I,--all-ip-addresses}'[display IP addresses for host (via network interfaces)]'
+    '(: gs s)'{-s,--short}'[display short host name only]'
+    + '(gs)' # Get/set
+    '(g)'{-y,--yp,--nis}'[display NIS domain only]'
+    + s # Set
+    '(-b --boot g)'{-b,--boot}'[always set a host name]'
+    '(: -F --file g)'{-F+,--file=}'[read host name to set from specified file]: :_files'
+    + o
+    '(-F --file g)1: :->host-or-domain'
+  )
+else
+  aopts=( -A '-*' )
+  args=(
+    '(-4 -6 -d -f -i -r -s)1: :_guard "^-*" "host name"'
+    '(: -4 -6 -d -f)-s[display short host name only]'
+  )
+
+  case $OSTYPE in
+    darwin*|freebsd*)
+      args+=(
+        '(: -d -s)-f[display host name with DNS domain (FQDN)]'
+      )
+      ;| # MATCH AGAIN
+    freebsd*)
+      args+=(
+        '(: -f -s)-d[display DNS domain only]'
+      )
+      ;;
+    dragonfly*)
+      args+=(
+        '(: -6 -r)-4[use first IPv4 address on interface (with -i)]'
+        '(: -4 -r)-6[use first IPv6 address on interface (with -i)]'
+        '(: -r)-i+[retrieve host name via specified interface]: :_net_interfaces'
+        '(: -4 -6 -i)-r+[retrieve host name via specified IP address]: :->ip-address'
+      )
+      ;;
+  esac
+fi
+
+_arguments -s -S $aopts : $args && ret=0
+
+case $state in
+  host-or-domain)
+    [[ -prefix -* ]] ||
+    if [[ -n ${opt_args[(i)*-(-y|--yp|--nis)]} ]]; then
+      _message -e nis-domains 'NIS domain' && ret=0
+    else
+      _message -e host-names 'host name' && ret=0
+    fi
+    ;;
+  ip-address)
+    # @todo Should we have a proper type function for local IPs?
+    tmp=( ${(f)"$( _call_program ip-addresses ifconfig -a )"} )
+    tmp=( ${(@M)tmp##(|[[:space:]]##)inet(|6)(|:)[[:space:]]*} )
+    tmp=( ${(@)tmp#*inet(|6)(|:)[[:space:]]##} )
+    tmp=( ${(@)tmp%%[^0-9A-Fa-f:.]*} )
+    tmp=( ${(@u)${(@)tmp//:/\\:}} )
+    _describe -t ip-addresses 'IP address' tmp && ret=0
+    ;;
+esac
+
+return ret


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Completion: Add _hostname (+ a question)
  2018-06-17 22:20 [PATCH] Completion: Add _hostname (+ a question) dana
@ 2018-06-17 23:02 ` Oliver Kiddle
  2018-06-18  0:35   ` dana
  0 siblings, 1 reply; 3+ messages in thread
From: Oliver Kiddle @ 2018-06-17 23:02 UTC (permalink / raw)
  To: dana; +Cc: Zsh workers

dana wrote:
>
> Instead of doing my own thing here, would there be any issue with my changing
> _bind_addresses to unconditionally return the actual interface addresses using a

Fixing _bind_addresses should be fine.

> +#compdef hostname

> +if _pick_variant net-tools=--yp unix --help; then

We can't do this. On some systems, e.g. Solaris, this will change the
system's hostname to "--help" if someone tries to complete hostname as
root.

Perhaps only call this on Linux.

Oliver


^ permalink raw reply	[flat|nested] 3+ messages in thread

* Re: [PATCH] Completion: Add _hostname (+ a question)
  2018-06-17 23:02 ` Oliver Kiddle
@ 2018-06-18  0:35   ` dana
  0 siblings, 0 replies; 3+ messages in thread
From: dana @ 2018-06-18  0:35 UTC (permalink / raw)
  To: Oliver Kiddle; +Cc: Zsh workers

On 17 Jun 2018, at 18:02, Oliver Kiddle <okiddle@yahoo.co.uk> wrote:
>We can't do this. On some systems, e.g. Solaris, this will change the
>system's hostname to "--help" if someone tries to complete hostname as
>root.

Hm, that's not the behaviour i get with either Oracle's or Illumos's hostname.
(I was actually under the impression that Solaris didn't *have* a hostname
command, which is why i didn't bother with it. And if i had, i would have run
into that issue where OSTYPE isn't good enough to tell the different variants
apart.) You're right though, it's risky — even on some Linux systems.

I think the attached should be good enough (better than nothing certainly) until
we can come up with a better way to safely differentiate commands like these.
Maybe _pick_variant could take an option to evaluate arbitrary code or
something, not sure.

Included patch has the reworked variant handling and _bind_addresses.

Thanks!

dana


diff --git a/Completion/Unix/Command/_hostname b/Completion/Unix/Command/_hostname
new file mode 100644
index 000000000..40a3189ae
--- /dev/null
+++ b/Completion/Unix/Command/_hostname
@@ -0,0 +1,76 @@
+#compdef hostname
+
+local variant=$OSTYPE ret=1
+local -a context line state state_descr args aopts=( -A '-*' )
+local -A opt_args
+
+# May be overridden below
+args=( '(-4 -6 -d -f -i -r -s)1: :_guard "^-*" "host name"' )
+
+# On badly behaved systems it may be dangerous to call `hostname --help` or
+# similar, so for now we'll avoid _pick_variant and just trust this. In the
+# future, we should replace this by a method that can safely detect Solaris,
+# BusyBox, etc. (@todo)
+[[ $OSTYPE == linux* ]] &&
+(( $+commands[nisdomainname] || $+commands[ypdomainname] )) &&
+variant+=-net-tools
+
+case $variant in
+  *-net-tools)
+    aopts=( )
+    args=(
+      '(: * -)'{-h,--help}'[display help information]'
+      '(: * -)'{-V,--version}'[display version information]'
+      + '(g)' # Get
+      '(: gs s)'{-A,--all-fqdns}'[display FQDNs resolved from network interface addresses]'
+      '(: gs s)'{-d,--domain}'[display DNS domain only]'
+      '(: gs s)'{-f,--fqdn,--long}'[display host name with DNS domain (FQDN)]'
+      '(: gs s)'{-i,--ip-address}'[display IP addresses for host (via DNS resolution)]'
+      '(: gs s)'{-I,--all-ip-addresses}'[display IP addresses for host (via network interfaces)]'
+      '(: gs s)'{-s,--short}'[display short host name only]'
+      + '(gs)' # Get/set
+      '(g)'{-y,--yp,--nis}'[display NIS domain only]'
+      + s # Set
+      '(-b --boot g)'{-b,--boot}'[always set a host name]'
+      '(: -F --file g)'{-F+,--file=}'[read host name to set from specified file]: :_files'
+      + o
+      '(-F --file g)1: :->host-or-domain'
+    )
+  ;;
+  darwin*|dragonfly*|freebsd*|netbsd*|openbsd*)
+    args+=(
+      '(: -4 -6 -d -f)-s[display short host name only]'
+    )
+    ;| # MATCH AGAIN
+  darwin*|freebsd*)
+    args+=(
+      '(: -d -s)-f[display host name with DNS domain (FQDN)]'
+    )
+    ;| # MATCH AGAIN
+  freebsd*)
+    args+=(
+      '(: -f -s)-d[display DNS domain only]'
+    )
+    ;;
+  dragonfly*)
+    args+=(
+      '(: -6 -r)-4[use first IPv4 address on interface (with -i)]'
+      '(: -4 -r)-6[use first IPv6 address on interface (with -i)]'
+      '(: -r)-i+[retrieve host name via specified interface]: :_net_interfaces'
+      '(: -4 -6 -i)-r+[retrieve host name via specified IP address]: :_bind_addresses'
+    )
+    ;;
+esac
+
+_arguments -s -S $aopts : $args && ret=0
+
+[[ $state == host-or-domain ]] && {
+  [[ -prefix -* ]] ||
+  if [[ -n ${opt_args[(i)*-(-y|--yp|--nis)]} ]]; then
+    _message -e nis-domains 'NIS domain' && ret=0
+  else
+    _message -e host-names 'host name' && ret=0
+  fi
+}
+
+return ret

diff --git a/Completion/Unix/Type/_bind_addresses b/Completion/Unix/Type/_bind_addresses
index 3460b7959..6042eaf1e 100644
--- a/Completion/Unix/Type/_bind_addresses
+++ b/Completion/Unix/Type/_bind_addresses
@@ -1,15 +1,17 @@
 #autoload
 
-local expl
-
-case $OSTYPE in
-  aix*) _hosts "$@" ;;
-  darwin*|freebsd*|dragonfly*) _hosts "$@" ;;
-  irix*) _hosts "$@" ;;
-  # Couldn't find anything special for linux except for /proc/net/dev
-  # Is there any proc file which gives the formatted ip?
-  linux*) ;&
-  *)
-    _wanted bind-addresses expl 'bind address' compadd "$@" - \
-      ${${${(M)${(f)"$(ifconfig -a)"}:#*addr:*}##*addr:( |)}%%(/| )*}
-esac
+# @todo In the future it might be useful to have this function take a glob or
+# similar to filter out loop-back addresses, only return IPv4/6, etc.
+
+local -a expl tmp cmd=( ifconfig -a )
+
+# A lot of Linux systems have ifconfig, but this is probably safer (and it's
+# parsed the same way)
+[[ $OSTYPE == linux* ]] && (( $+commands[ip] )) && cmd=( ip addr show )
+
+tmp=( ${(f)"$( _call_program bind-addresses $cmd )"} )
+tmp=( ${(@M)tmp##(|[[:space:]]##)inet(|6)(|:)[[:space:]]*} )
+tmp=( ${(@)tmp#*inet(|6)(|:)[[:space:]]##} )
+tmp=( ${(@)tmp%%[^0-9A-Fa-f:.]*} )
+
+_wanted bind-addresses expl 'bind address' compadd -a "$@" - tmp


^ permalink raw reply	[flat|nested] 3+ messages in thread

end of thread, other threads:[~2018-06-18  0:35 UTC | newest]

Thread overview: 3+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-06-17 22:20 [PATCH] Completion: Add _hostname (+ a question) dana
2018-06-17 23:02 ` Oliver Kiddle
2018-06-18  0:35   ` dana

Code repositories for project(s) associated with this public inbox

	https://git.vuxu.org/mirror/zsh/

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).