##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8 ## Outils pour les distributions debian ##@cooked nocomments ##@require base ##@require sysinfos ##@require service uprovide debian urequire base sysinfos service ################################################################################ # Gestion des packages function pkg_check() { # Vérifier que les packages sont installés sur le système local pkg status for pkg in "$@"; do status="$(LANG=C dpkg -s "$pkg" 2>/dev/null | grep '^Status:')" || return 1 [[ "$status" == *not-installed* ]] && return 1 [[ "$status" == *deinstall* ]] && return 1 done return 0 } function pkg_update() { # Mettre à jour la liste des packages silencieusement sans confirmation LANG=C apt-get update -qy } function pkg_upgrade() { # Mettre à jour la liste des packages silencieusement sans confirmation LANG=C apt-get upgrade -qy } function pkg_install() { # Installer les packages silencieusement et sans confirmation LANG=C apt-get install -qy "$@" } function pkg_installm() { # Installer les packages silencieusement et sans confirmation # Retourner 0 si au moins un des packages a été installé. Sinon, les # packages n'ont pas été installés, soit parce qu'ils sont déjà installé, # soit parce qu'il y a eu une erreur. if ! pkg_check "$@"; then # essayer d'installer les packages pkg_install "$@" else # aucun package n'a été installé return 1 fi } ################################################################################ # Gestion des services function service_disable() { # Désactiver le service $1 pour qu'il ne se lance pas automatiquement au # démarrage update-rc.d -f "$1" remove } function service_enable() { # Activer le service $1 pour qu'il se lance automatiquement au démarrage update-rc.d "$1" defaults } ################################################################################ # Gestion des interfaces réseau function network_create_bridge() { # Modifier le fichier /etc/network/interfaces pour créer un nouveau pont # nommé $1 avec les paramètres $2. Si $2 est vide, sa valeur par défaut est # bridge_ports none # bridge_stp off # bridge_fd 2 # bridge_maxwait 0 # OPTIONS: # --static L'interface est statique plutôt que de recevoir son # adresse par DHCP # --auto Démarrer l'interface automatiquement # Une définition existante de l'interface n'est jamais écrasée. # Retourner vrai si la définition a été ajoutée dans /etc/network/interfaces local args method auto ifname lines method=dhcp parse_opts \ --static method=static \ --auto auto \ @ args -- "$@" && set -- "${args[@]}" || { eerror "$args" return 1 } ifname="${1:-br0}" array_from_lines lines "$2" lines="$(array_to_lines lines "" " ")" doinplacef /etc/network/interfaces awkrun ifname="$ifname" lines="$lines" method="$method" auto="$auto" ' BEGIN { foundif = 0 } $0 ~ "^iface " ifname " " { foundif = 1 } { print } END { if (foundif) { exit 1 } else { print "" if (auto != "") print "auto " ifname print "iface " ifname " inet " method if (lines != "") print lines exit 0 } }' } __DEBIAN_NETWORK_DEVEL_SHOW_MODIFS= function __network_hostname() { local hostname="${1%%.*}" if [ -n "$__DEBIAN_NETWORK_DEVEL_SHOW_MODIFS" ]; then uecho "Setting /etc/hostname to $hostname" else echo "$hostname" >/etc/hostname fi } function __network_mailname() { local host="$1" if [ -n "$__DEBIAN_NETWORK_DEVEL_SHOW_MODIFS" ]; then uecho "Setting /etc/mailname to $host" else echo "$host" >/etc/mailname fi } function __network_fix_exim4() { local host="$1" local tmpfile; ac_set_tmpfile tmpfile "$tmpfile" if [ -n "$__DEBIAN_NETWORK_DEVEL_SHOW_MODIFS" ]; then if testdiff "$tmpfile" /etc/exim4/update-exim4.conf.conf; then uecho "Setting /etc/exim4/update-exim4.conf.conf to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else uecho "/etc/exim4/update-exim4.conf.conf: pas de modifications" fi elif testdiff "$tmpfile" /etc/exim4/update-exim4.conf.conf; then cat "$tmpfile" >/etc/exim4/update-exim4.conf.conf update-exim4.conf fi } function __network_hosts() { local host="$1" hostname="${1%%.*}" ip="$2" local tmpfile; ac_set_tmpfile tmpfile "$tmpfile" local sip="${ip//./\\.}" shost="${host//./\\.}" if ! quietgrep "^$sip[ $TAB]\\+$shost[ $TAB]\\+$hostname" "$tmpfile"; then sed -i "/^$sip[ $TAB]/d" "$tmpfile" sed -i "1i\\ $ip$TAB$host $hostname" "$tmpfile" fi if [ -n "$__DEBIAN_NETWORK_DEVEL_SHOW_MODIFS" ]; then if testdiff "$tmpfile" /etc/hosts; then uecho "Setting /etc/hosts to:" cat "$tmpfile" | sed 's/^/ /g' 1>&2 else uecho "/etc/hosts: pas de modifications" fi elif testdiff "$tmpfile" /etc/hosts; then cat "$tmpfile" >/etc/hosts fi ac_clean "$tmpfile" } function __network_parse_confip() { # confip --> iface [ipspecs@] [ipspecs] local __npc_tmp splitfsep2 "$1" : "${2:-iface}" __npc_tmp [ -n "$3" ] && array_split "$3" "$__npc_tmp" , [ -n "$4" ] && set_var "$4" "$__npc_tmp" } function __network_parse_ipspec() { # ipspec --> ip mask gateway local __npi_tmp splitfsep "$1" / "${2:-ip}" __npi_tmp splitfsep "$__npi_tmp" + "${3:-mask}" "${4:-gateway}" } function __network_parse_confbr() { # confbr --> br [ifaces@] [ifaces] local __npc_tmp splitfsep "$1" : "${2:-br}" __npc_tmp [ -n "$3" ] && array_split "$3" "$__npc_tmp" , [ -n "$4" ] && set_var "$4" "$__npc_tmp" } function __network_fix_confips() { # confips@ local -a __nfc_confips __nfc_ipspecs __nfc_ifaces __nfc_ips local __nfc_confip __nfc_iface __nfc_ipspec __nfc_ip __nfc_mask __nfc_gateway array_copy __nfc_confips "${1:-confips}" # recenser les interfaces et créer les tableaux __IFACE_ipspecs for __nfc_confip in "${__nfc_confips[@]}"; do __network_parse_confip "$__nfc_confip" __nfc_iface __nfc_ipspecs array_addu __nfc_ifaces "$__nfc_iface" eval "local -a __nfc_${__nfc_iface}_ipspecs" done # puis constuire la liste des adresses IP associées à chaque interface for __nfc_confip in "${__nfc_confips[@]}"; do __network_parse_confip "$__nfc_confip" __nfc_iface __nfc_ipspecs for __nfc_ipspec in "${__nfc_ipspecs[@]}"; do __network_parse_ipspec "$__nfc_ipspec" __nfc_ip __nfc_mask __nfc_gateway if ! array_contains __nfc_ips "$__nfc_ip"; then eval "array_add __nfc_${__nfc_iface}_ipspecs \"$__nfc_ipspec\"" array_add __nfc_ips "$__nfc_ip" fi done done # puis construire le tableau final array_new __nfc_confips for __nfc_iface in "${__nfc_ifaces[@]}"; do array_add __nfc_confips "$__nfc_iface:$(array_join "__nfc_${__nfc_iface}_ipspecs" ,)" done array_copy "${1:-confips}" __nfc_confips } function __network_fix_confbrs() { # confbrs@ local -a __nfc_confbrs __nfc_ifaces __nfc_brs __nfc_ips local __nfc_confbr __nfc_br __nfc_iface __nfc_ip __nfc_mask __nfc_gateway array_copy __nfc_confbrs "${1:-confbrs}" # recenser les bridges et créer les tableaux __BR_ifaces for __nfc_confbr in "${__nfc_confbrs[@]}"; do __network_parse_confbr "$__nfc_confbr" __nfc_br __nfc_ifaces array_addu __nfc_brs "$__nfc_br" eval "local -a __nfc_${__nfc_br}_ifaces" done # puis constuire la liste des interfaces associées à chaque bridge for __nfc_confbr in "${__nfc_confbrs[@]}"; do __network_parse_confbr "$__nfc_confbr" __nfc_br __nfc_ifaces array_extendu "__nfc_${__nfc_br}_ifaces" __nfc_ifaces done # puis construire le tableau final array_new __nfc_confbrs for __nfc_br in "${__nfc_brs[@]}"; do array_add __nfc_confbrs "$__nfc_br:$(array_join "__nfc_${__nfc_br}_ifaces" ,)" done array_copy "${1:-confbrs}" __nfc_confbrs } function __network_resolve_mainiface() { local __nrm_mainiface="${1:-mainiface}" __nrm_mainconfbr="$2" __nrm_mainconfip="$3" [ -n "${!__nrm_mainiface}" ] || __network_parse_confbr "$__nrm_mainconfbr" "$__nrm_mainiface" [ -n "${!__nrm_mainiface}" ] || __network_parse_confip "$__nrm_mainconfip" "$__nrm_mainiface" [ -n "${!__nrm_mainiface}" ] || set_var "$__nrm_mainiface" eth0 } function __network_set_mainip() { eval "$(ip addr show dev "$1" | awk "BEGIN { mainipvar = \"${2:-mainip}\" netmaskvar = \"${3:-netmask}\" broadcastvar = \"${4:-broadcast}\" "' print mainipvar "=" print netmaskvar "=" print broadcastvar "=" } $1 == "inet" { mainip = ""; netmask = ""; broadcast = "" if (match($0, "inet ([^ ]*)/([^ ]*) ", vs) != 0) { mainip = vs[1] netmask = vs[2] } if (match($0, "brd ([^ ]*) ", vs) != 0) { broadcast = vs[1] } print mainipvar "=\"" mainip "\"" print netmaskvar "=\"" netmask "\"" print broadcastvar "=\"" broadcast "\"" exit 0 }')" } function __network_set_gateway() { eval "$(route -n | awk "BEGIN { iface = \"$1\" gatewayvar = \"${2:-gateway}\" "' print gatewayvar "=" } $1 == "0.0.0.0" && $8 == iface { print gatewayvar "=\"" $2 "\"" }')" } #XXX #local mainnetmask mainbroadcast maingateway #if [ "$mainip" == dhcp ]; then # # ne pas toucher aux adresses en dhcp # : #elif [ -z "$mainip" ]; then # # détecter les valeurs par rapport à l'environnement # __network_set_mainip "$mainiface" mainip mainnetmask mainbroadcast # __network_set_gateway "$mainiface" maingateway #fi # quelques pistes de réflexion pour la suite de l'implémentation: # après avoir classifiée les bridge et les interfaces non attachées à des # bridges, il faut: configurer les interfaces standard, configurer les # interfaces des bridges en manual, configurer les bridges # si l'interface principale est un bridge, il faut mettre les interfaces # concernées en manual et configurer les adresses ips du bridge # si l'interface principale est une interface standard, il suffit de # configurer les adresses pour cette interface. function __network_update_bridge() { # vérifier la configuration (interfaces de ifaces[@] en manual, présence du # bridge, bridge en auto, adresse ip principale statique ou en dhcp, # adresses ip supplémentaires), puis si nécessaire, supprimer l'ancienne # configuration et créer la nouvelle. awkrun -f iface="$1" ipspecs="${2:-ipspecs}[@]" ifaces="${3:-ifaces}[@]" ' { print } ' } function __network_update_iface() { # vérifier la configuration (présence de l'interface, interface en auto, # adresse ip principale statique ou en dhcp, adresses ip supplémentaires), # puis si nécessaire, supprimer l'ancienne configuration et créer la # nouvelle. awkrun -f iface="$1" ipspecs[@] ' { print } ' } function network_config() { # (Re)configurer le réseau sur l'hôte courant. # $1 (host) est le nom d'hôte. $2 (confips) est le nom d'un tableau # contenant la configuration des adresses ips pour les interfaces. $3 # (confbrs) est le nom d'un tableau contenant la configuration des bridges à # créer/mettre à jour. $4 (mainiface) est le nom de l'interface # principale. En principe, l'interface principale est le premier bridge # défini ou la première interface définie. # Si un des arguments n'est pas spécifié, il est ignoré. # Le tableau confips doit contenir des définitions d'une des formes # suivantes: # [iface:]address[/mask][+gateway],... # [iface:]dhcp # La deuxième forme est pour spécifier qu'une interface est configurée par # DHCP. iface vaut par défaut eth0, sauf si une définition de bridge # existe, auquel cas il s'agit du premier bridge défini. Pour chaque # interface, seule la première spécification d'adresse IP tient compte de # l'argument gateway. Les autres spécifications définissent des adresses IP # supplémentaires pour l'interface. # Le tableau brs doit contenir des définitions de la forme suivante: # br:ifaces,... # br est le nom du bridge, e.g. br0. ifaces est une liste d'interfaces # séparées par une virgule. e.g. br0:eth0,eth1 # Bien que ce soit techniquement possible, ce script interdit que l'on # définisse une adresse IP pour une interface faisant partie d'un bridge. urequire ipcalc conf local -a __nc_confips __nc_confbrs [ -n "$2" ] && array_copy __nc_confips "$2" [ -n "$3" ] && array_copy __nc_confbrs "$3" local host="$1" mainiface="$4" local -a confips confbrs array_copy confips __nc_confips array_copy confbrs __nc_confbrs __network_fix_confips confips __network_fix_confbrs confbrs local mainbr # bridge principal local mainip # adresse IP principale de l'interface principale local confbr confip br iface mask gateway local -a ipspecs __network_resolve_mainiface mainiface "${confbrs[0]}" "${confips[0]}" __network_parse_confbr "${confbrs[0]}" mainbr [ -n "$mainbr" ] || mainbr=br0 if [ -n "${confips[*]}" -o -n "${confbrs[*]}" ]; then # Vérifier qu'une interface avec une adresse IP ne figure pas dans les # bridges à configurer. en profiter pour classer les interfaces par # type: standard et bridges etitle "Configuration des interfaces réseau" local -a ifaces_with_ips ifaces local -a brifaces ifaces_with_ips=() for confip in "${confips[@]}"; do __network_parse_confip "$confip" iface array_addu ifaces_with_ips "$iface" done for confbr in "${confbrs[@]}"; do __network_parse_confbr "$confbr" br ifaces array_add brifaces "$br" for iface in "${ifaces[@]}"; do if array_contains ifaces_with_ips "$iface"; then eerror "$iface: Impossible de configurer une interface dans un bridge ET avec une adresse IP" return 1 fi done done local -a confstdips confbrips for confip in "${confips[@]}"; do __network_parse_confip "$confip" iface if array_contains brifaces "$iface"; then array_add confbrips "$confip" else array_add confstdips "$confip" fi done # maintenant, configurer /etc/network/interfaces: faire une copie de travail local interfaces workfile ac_set_tmpfile interfaces ac_set_tmpfile workfile cat /etc/network/interfaces >"$interfaces" # configurer chaque bridge local -a tmpifaces local tmpbr for confip in "${confbrips[@]}"; do __network_parse_confip "$confip" br ipspecs [ -n "$br" ] || br="$mainbr" if [ -z "$mainip" -a "$br" == "$mainiface" ]; then __network_parse_ipspec "${ipspecs[0]}" mainip mask gateway fi ifaces=() for confbr in "${confbrs[@]}"; do __network_parse_confbr "$confbr" tmpbr tmpifaces if [ "$tmpbr" == "$br" ]; then array_copy ifaces "$tmpifaces" break fi done __network_update_bridge "$br" ipspecs ifaces <"$interfaces" >"$workfile" cat "$workfile" >"$interfaces" done # configurer chaque interface classique for confip in "${confstdips[@]}"; do __network_parse_confip "$confip" iface ipspecs [ -n "$iface" ] || iface="$mainiface" if [ -z "$mainip" -a "$iface" == "$mainiface" ]; then __network_parse_ipspec "${ipspecs[0]}" mainip mask gateway fi __network_update_iface "$iface" ipspecs <"$interfaces" >"$workfile" cat "$workfile" >"$interfaces" done # Fin de traitement if [ -n "$__DEBIAN_NETWORK_DEVEL_SHOW_MODIFS" ]; then if testdiff "$interfaces" /etc/network/interfaces; then uecho "Setting /etc/network/interfaces to:" cat "$interfaces" | sed 's/^/ /g' 1>&2 else uecho "/etc/network/interfaces: pas de modifications" fi elif testdiff "$interfaces" /etc/network/interfaces; then cat "$interfaces" >/etc/network/interfaces fi ac_clean "$interfaces" "$workfile" eend fi # configurer le nom d'hôte if [ -n "$host" ]; then host="$(ipcalc_fqdn_maybe "$host")" etitle "Configuration du nom d'hôte: $host" # si on ne spécifie pas l'adresse ip principale, la résoudre ici. ceci # est nécessaire pour mettre à jour /etc/hosts if [ "$mainip" == dhcp ]; then # si l'adresse obtenue est en DHCP, ne pas mettre à jour /etc/hosts mainip= elif [ -z "$mainip" ]; then local -a mainips resolv_ips mainips "$host" [ -n "${mainips[*]}" ] || { eerror "$host: Impossible de résoudre ce nom d'hôte" return 1 } mainip="${mainips[0]}" fi estep "/etc/hostname" __network_hostname "$host" estep "/etc/mailname" __network_mailname "$host" if [ -f "/etc/exim4/update-exim4.conf.conf" ]; then estep "/etc/exim4/update-exim4.conf.conf" __network_fix_exim4 "$host" fi # XXX tester la présence éventuelle de postfix, et si nécessaire, # modifier la configuration if [ -n "$mainip" ]; then estep "/etc/hosts" __network_hosts "$host" "$mainip" fi eend fi return 0 }