[PATCH] Debian: Zsh Completion für ifup und ifdown: _net_interfaces

Gültig für zsh 4.3.6 (i686-pc-linux-gnu) auf einem Debian GNU Linux Unstable (Stand September 2008)

% zsh --version
zsh 4.3.6 (i686-pc-linux-gnu)

Dieser Patch muß nicht für andere Versionen funktionieren!

Beschreibung

Nachdem die Zsh zwar Completion für ifup und ifdown beherrscht aber dies nur ohne den tatsächlichen Zustandes des Systems zu berücksichtigen, wollte ich genau dies und Completion für mappings implementieren. Die Completion für ifup und ifdown befindet sich in der Datei /usr/share/zsh/functions/Completion/Unix/_net_interfaces.

zsh completion

Zsh Completion für ifup und ifdown

Folgendes Verhalten soll meine Implementierung der Completion zeigen. Ist ein Interface up sollte nur dieses beim Befehl ifdown angezeit werden. Ebenso sollten nur Interfaces die auch wirklich vorhanden sind angezeigt werden. Aber sobald mappings in der Datei /etc/network/interfaces definiert sind sollen alle Interfaces mit allen mappings vervollständigt werden.

Um dieses Verhalten zu erreichen, war es notwendig in der Datei /usr/share/zsh/functions/Completion/Unix/_net_interfaces einen Parser für /etc/network/run/ifstate bzw für /etc/network/interfaces einzubauen. Diese Parser sind der zweite Teil meines Patches, der erste ist lediglich ein Patch um den sed Aufruf zu vermeiden, der ja recht einfach auch in zsh gelöst werden kann.

% cat /usr/share/zsh/functions/Completion/Unix/_net_interfaces
#compdef ifup ifdown

local expl list intf sep
local -a disp

case $OSTYPE in
  aix*)
    intf=( ${(f)"$(lsdev -C -c if -F 'name:description')"} )
    if zstyle -T ":completion:${curcontext}" verbose; then
      zstyle -s ":completion:${curcontext}:" list-separator sep || sep=--
      zformat -a list " $sep " "$intf[@]"
      disp=(-ld list)
    fi
  ;;
  darwin*|freebsd*|dragonfly*) intf=( $(ifconfig -l) ) ;;
  irix*) intf=( ${${${(f)"$(/usr/etc/netstat -i)"}%% *}[2,-1]} ) ;;

  *)
  # Make sure ifconfig is in the path.
  local PATH=$PATH
  PATH=/sbin:$PATH

### patch to avoid sed
  #intf=( $(ifconfig -a 2>/dev/null | sed -n 's/^\([^   :]*\).*/\1/p') )
  local ifconfig_out_tmp
  ifconfig_out_tmp=`ifconfig -a 2>/dev/null`
  for i in ${${(f)${ifconfig_out_tmp}}:#[[:blank:]]*};do
    [[ ${#intf} == 0 ]] && intf=( ${${(s: :)${i}}[1]} ) || intf+=( ${${(s: :)${i}}[1]} )
  done
### EO patch

  if [[ ${#intf} -eq 0 && -d /proc/sys/net/ipv4/conf ]]; then
    # On linux we used to use the following as the default.
    # However, we now use ifconfig since it finds additional devices such
    # as tunnels.  So only do this if that didn't work.
    intf=( /proc/sys/net/ipv4/conf/*~*(all|default)(N:t) )
  fi

  ###patch for completion of interfaces including mappings for debian

  # run only on debian systems
  if [[ -a /etc/debian_version ]]; then
    local intf_map_sorted intf_map
    local intf_up intf_up_sorted

    # get interfaces that are up
    _get_intf_up_sorted(){
      if [[ -a /etc/network/run/ifstate ]]; then
        intf_up=( ${${(f)"$(</etc/network/run/ifstate)"}%%\=*} )
      fi
      intf_up_sorted=(${(u)${(o)${(s: :)${intf_up}}}})
    }

    # get mappings, sort them and make them unique
    _get_intf_map_sorted(){
      if [[ -a /etc/network/interfaces ]]; then
        for j in ${(M)${${(f)"$(</etc/network/interfaces)"}%%\#*}%%iface\ *};do
          intf_map+=(${${(s: :)${j}}[2]})
        done
        intf_map_sorted=(${(u)${(o)${(s: :)${intf_map}}}:#lo})
      fi
    }

    # get interfaces that are not up
    _get_intf_not_up(){
      _get_intf_up_sorted
      for i in $intf_up_sorted;do
        intf=(${${intf}:%$i})
      done
    }

    # eliminate interfaces in mappings
    _check_mappings(){
      for i in $intf;do
        intf_map_sorted=(${${intf_map_sorted}:%$i})
      done
    }

    if [[ "$service" == "ifup" ]];then
      _get_intf_not_up
      [[ ${#intf} != 0 ]] && _get_intf_map_sorted
      [[ ${#intf_map_sorted} != 0 ]] && _check_mappings
      [[ ${#intf_map_sorted} != 0 ]] && intf+=(${^${intf}}"="${^${intf_map_sorted}})
    else
        _get_intf_up_sorted
        intf=( ${intf_up_sorted} )
    fi
  fi
  ###EO patch

  ;;
esac

_wanted interfaces expl 'network interface' \
    compadd "$@" "$disp[@]" - "${(@)intf%%:*}"

Downloads

Hier noch die nötige Datei zum herunterladen:

Patch: _net_interfaces.patch
Completion Datei: _net_interfaces

Update und Errata 9. Sep 2008

  • Korrektur der Escapesequenzen im '<pre>' Block.
  • Korrektur des Pfades zur _net_interfaces: /usr/share/zsh/Completion/Unix wurde zu /usr/share/zsh/functions/Completion/Unix
  • Einfügen der verwendeten Version der Zsh: zsh 4.3.6 (i686-pc-linux-gnu)