Opennet Firmware
modules.sh
gehe zur Dokumentation dieser Datei
1 ## @defgroup modules Module
2 ## @brief Verwaltung der Opennet-Module für verschiedene Funktionen/Rollen
3 # Beginn der Doku-Gruppe
4 ## @{
5 
6 # Basis-URL für Opennet-Paketinstallationen
7 ON_OPKG_REPOSITORY_URL_PREFIX="https://downloads.opennet-initiative.de/openwrt"
8 # temporäre Datei für Installation von Opennet-Paketen
9 ON_OPKG_CONF_PATH="${IPKG_INSTROOT:-}/tmp/opkg-opennet.conf"
10 # shellcheck disable=SC2034
11 DEFAULT_MODULES_ENABLED="on-olsr2"
12 
13 
14 # Erzeuge die uci-Sektion "on-core.modules" und aktiviere Standard-Module.
15 _prepare_on_modules() {
16  [ -n "$(uci_get "on-core.modules")" ] && return
17  uci set "on-core.modules=modules"
18 }
19 
20 
21 ## @fn is_on_module_installed_and_enabled()
22 ## @brief Pruefe ob ein Modul sowohl installiert, als auch aktiv ist.
23 ## @param module Eins der Opennet-Pakete (siehe 'get_on_modules').
24 ## @details Die Aktivierung eines Modules wird anhand der uci-Einstellung "${module}.settings.enabled" geprueft.
25 ## Der Standardwert ist "false" (ausgeschaltet).
27  trap 'error_trap is_on_module_installed_and_enabled "$*"' EXIT
28  local module="$1"
29  _prepare_on_modules
30  is_on_module_installed "$module" && _is_on_module_enabled "$module" && return 0
31  trap "" EXIT && return 1
32 }
33 
34 
35 _is_on_module_enabled() {
36  local module="$1"
37  _prepare_on_modules
38  uci_is_in_list "on-core.modules.enabled" "$module" && return 0
39  trap "" EXIT && return 1
40 }
41 
42 
43 is_on_module_installed() {
44  local module="$1"
45  _prepare_on_modules
46  is_package_installed "$module" && return 0
47  trap "" EXIT && return 1
48 }
49 
50 
51 ## @fn enable_on_module()
52 ## @brief Aktiviere ein Opennet-Modul
53 ## @param module Eins der Opennet-Pakete (siehe 'get_on_modules').
55  trap 'error_trap enable_on_module "$*"' EXIT
56  local module="$1"
57  _prepare_on_modules
58  warn_if_unknown_module "$module"
59  warn_if_not_installed_module "$module"
60  uci_add_list "on-core.modules.enabled" "$module"
61  apply_changes "on-core" "$module"
62 }
63 
64 
65 ## @fn disable_on_module()
66 ## @brief Deaktiviere ein Opennet-Modul
67 ## @param module Eins der Opennet-Pakete (siehe 'get_on_modules').
69  trap 'error_trap disable_on_module "$*"' EXIT
70  local module="$1"
71  warn_if_unknown_module "$module"
72  _is_on_module_enabled "$module" || return 0
73  uci_delete_list "on-core.modules.enabled" "$module"
74  apply_changes "on-core" "$module"
75 }
76 
77 
78 ## @fn warn_if_unknown_module()
79 ## @brief Gib eine Warnung aus, falls der angegebene Modul-Name unbekannt ist.
80 ## @details Das Ergebnis der Prüfung ist nur für Warnmeldungen geeignet, da es im Laufe der Zeit
81 ## Veränderungen in der Liste der bekannten Module geben kann.
83  local module="$1"
84  get_on_modules | grep -qwF "$module" && return 0
85  echo >&2 "The opennet module name '$module' is unknown - probably misspelled?"
86  echo >&2 "The following module names are known: $(get_on_modules | xargs echo)"
87 }
88 
89 
90 warn_if_not_installed_module() {
91  local module="$1"
92  is_on_module_installed "$module" && return 0
93  echo >&2 "The opennet module name '$module' is not installed - maybe you want to install it?"
94 }
95 
96 
97 ## @fn get_on_modules()
98 ## @brief Liefere die Namen aller bekannten Opennet-Module zeilenweise getrennt zurück.
99 ## @details Die Liste kann in der Datei ON_CORE_DEFAULTS_FILE angepasst werden.
100 get_on_modules() {
101  # zeilenweise splitten (wir erwarten nur kleine Buchstaben und Zahlen im Namen)
102  get_on_core_default "on_modules" | sed 's/[^a-z0-9-]/\n/g' | grep -v "^$" || true
103 }
104 
105 
106 ## @fn get_not_installed_on_modules()
107 ## @brief Ermittle diejenigen Module, die aktuell nicht installiert sind.
109  local module
110  for module in $(get_on_modules); do
111  is_package_installed "$module" || echo "$module"
112  done
113 }
114 
115 
116 ## @fn was_on_module_installed_before()
117 ## @brief Prüfe ob ein Modul "früher" (vor der letzten manuellen Änderung durch den Benutzer) installiert war.
118 ## @details Diese Prüfung ist hilfreich für die Auswahl von nachträglich zu installierenden Paketen.
120  local module="$1"
121  uci_is_in_list "on-core.modules.installed" "$module" && return 0
122  trap "" EXIT && return 1
123 }
124 
125 
126 ## @fn get_missing_modules()
127 ## @brief Collect the names of modules that were probably installed before the last upgrade.
129  local module
130  for module in $(get_on_modules); do
131  is_on_module_installed_and_enabled "$module" && continue
132  is_package_installed "$module" && continue
133  was_on_module_installed_before "$module" && echo "$module"
134  true
135  done
136 }
137 
138 
139 ## @fn install_from_opennet_repository()
140 ## @param packages Ein oder mehrere zu installierende Software-Pakete
141 ## @returns Eventuelle Fehlermeldungen werden auf die Standardausgabe geschrieben. Der Exitcode ist immer Null.
142 ## @brief Installiere ein Paket aus den Opennet-Repositories.
143 ## @details Für die Installation von Opennet-relevanten Paketen wird eine separate opkg.conf-Datei verwendet.
144 ## Alle nicht-opennet-relevanten Pakete sollten - wie gewohnt - aus den openwrt-Repositories heraus installiert
145 ## werden, da deren Paket-Liste umfassender ist.
146 ## Die opkg.conf wird im tmpfs erzeugt, falls sie noch nicht vorhanden ist. Eventuelle manuelle Nachkorrekturen
147 ## bleiben also bis zum nächsten Reboot erhalten.
149  trap 'error_trap install_from_opennet_repository "$*"' EXIT
150  local package
151  local not_installed_packages
152  not_installed_packages=$(get_not_installed_on_modules)
153  run_opennet_opkg "update" && run_opennet_opkg "install" "$@"
154  for package in "$@"; do
155  if get_on_modules | grep -qwF "$package"; then
156  # Eventuell schlug die Installation fehl?
157  is_package_installed "$package" || continue
158  # Falls es ein opennet-Modul ist, dann aktiviere es automatisch nach der Installation.
159  # Dies dürfte für den Nutzer am wenigsten überraschend sein.
160  # Wichtig: "enable" in einem neuen Skript-Kontext ausführen, damit sichergestellt ist,
161  # dass die "apply_changes"-Aktion mit den eventuell neuen Funktionen
162  # ausgeführt werden kann.
163  on-function enable_on_module "$package"
164  fi
165  done
166  # wir wollen auch indirekt installierte Pakete aktivieren (z.B. on-openvpn via on-captive-portal)
167  for package in $not_installed_packages; do
168  # unveraendert nicht installiert? Ignorieren ...
169  is_package_installed "$package" || continue
170  on-function enable_on_module "$package"
171  done
172  # anschließend speichern wir den aktuellen Zustand, falls _alle_ Pakete installiert wurden
173  for package in "$@"; do
174  # Paket fehlt? aktuelle Liste nicht speichern, sondern einfach abbrechen
175  is_package_installed "$package" || return 0
176  done
177  save_on_modules_list
178 }
179 
180 
181 ## @fn remove_opennet_module()
182 ## @param module Name des oder der zu entfernenden Module
183 remove_opennet_modules() {
184  # "--force-remove" ist für on-monitoring notwendig, da sonst xinetd wegen einer Änderung
185  # /etc/xinet.d/munin nicht entfernt wird
186  run_opennet_opkg --autoremove --force-remove remove "$@"
187  save_on_modules_list
188 }
189 
190 
191 ## @fn redirect_to_opkg_opennet_logfile()
192 ## @brief Führe die gegebene Aktion aus und lenke ihre Ausgabe in die opennet-opkg-Logdatei um.
193 ## @details Als irrelevant bekannte Meldungen werden herausgefiltert.
194 redirect_to_opkg_opennet_logfile() {
195  local log_file
196  log_file=$(get_custom_log_filename "opkg_opennet")
197  "$@" 2>&1 \
198  | grep -vE 'resolve_conffiles: Existing conffile /etc/config/(openvpn|olsrd2) is different from the conffile in the new package\. The new conffile will be placed at /etc/config/(openvpn|olsrd2)-opkg\.' \
199  | grep -v '^Collected errors:$' >>"$log_file"
200 }
201 
202 
203 # Ausführung eines opkg-Kommnados mit der opennet-Repository-Konfiguration und minimaler Ausgabe (nur Fehler) auf stdout.
204 run_opennet_opkg() {
205  trap 'error_trap run_opennet_opkg "$*"' EXIT
206  # erzeuge Konfiguration, falls sie noch nicht vorhanden ist
207  [ -e "$ON_OPKG_CONF_PATH" ] || generate_opennet_opkg_config >"$ON_OPKG_CONF_PATH"
208  # Vor der opkg-Ausführung müssen wir das Verzeichnis /etc/opkg verdecken, da opkg fehlerhafterweise
209  # auch bei Verwendung von "--conf" die üblichen Orte nach Konfigurationsdateien durchsucht.
210  # TODO: opkg-Bug upstream berichten
211  mount -t tmpfs -o size=32k tmpfs /etc/opkg
212  # opkg ausfuehren und dabei die angegebene Fehlermeldung ignorieren (typisch fuer Paket-Installation nach Upgrade)
213  opkg --verbosity=1 --conf "$ON_OPKG_CONF_PATH" "$@" || true
214  umount /etc/opkg
215 }
216 
217 
218 ## @fn save_on_modules_list()
219 ## @brief Speichere die aktuelle Liste der installierten opennet-Module in der uci-Konfiguration.
220 ## @details Nach einer Aktualisierung ermöglicht diese Sicherung die Nachinstallation fehlender Pakete.
221 save_on_modules_list() {
222  local modname
223  _prepare_on_modules
224  [ -z "$(uci_get "on-core.modules")" ] && uci set "on-core.modules=modules"
225  for modname in $(get_on_modules); do
226  if is_package_installed "$modname"; then
227  echo "$modname"
228  fi
229  done | uci_replace_list "on-core.modules.installed"
230  apply_changes on-core
231 }
232 
233 
234 ## @fn clear_cache_opennet_opkg()
235 ## @brief Lösche die eventuell vorhandene opennet-opkg-Konfiguration (z.B. nach einem Update).
236 clear_cache_opennet_opkg() {
237  rm -f "$ON_OPKG_CONF_PATH"
238 }
239 
240 
241 ## @fn get_default_opennet_opkg_repository_base_url()
242 ## @brief Ermittle die automatisch ermittelte URL für die Nachinstallation von Paketen.
243 ## @returns Liefert die Basis-URL zurueck. Anzuhängen sind im Anschluss z.B. /packages/${arch_cpu_type} oder /targets/${arch}/generic/packages
244 get_default_opennet_opkg_repository_base_url() {
245  trap 'error_trap get_default_opennet_opkg_repository_base_url "$*"' EXIT
246  # ermittle die Firmware-Repository-URL
247  local firmware_version
248  firmware_version=$(get_on_firmware_version)
249  # leere Versionsnummer? Damit können wir nichts anfangen.
250  [ -z "$firmware_version" ] && msg_error "Failed to retrieve opennet firmware version for opkg repository URL" && return 0
251  # snapshots erkennen wir aktuell daran, dass auch Buchstaben in der Versionsnummer vorkommen
252  local version_path
253  if echo "$firmware_version" | grep -q "[a-zA-Z]"; then
254  # ein Buchstabe wurde entdeckt: unstable
255  version_path="testing/$firmware_version"
256  else
257  # kein Buchstabe wurde entdeckt: stable
258  # wir schneiden alles ab dem ersten Bindestrich ab
259  version_path="stable/$(echo "$firmware_version" | cut -f 1 -d -)"
260  fi
261  echo "$ON_OPKG_REPOSITORY_URL_PREFIX/$version_path"
262 }
263 
264 
265 ## @fn get_configured_opennet_opkg_repository_base_url()
266 ## @brief Ermittle die aktuell konfigurierte Repository-URL.
267 get_configured_opennet_opkg_repository_base_url() {
268  local url
269  _prepare_on_modules
270  url=$(uci_get "on-core.modules.repository_url")
271  if [ -n "$url" ]; then
272  echo "$url"
273  else
274  get_default_opennet_opkg_repository_base_url
275  fi
276 }
277 
278 
279 ## @fn set_configured_opennet_opkg_repository_url()
280 ## @param repo_url Die neue Repository-URL (bis einschliesslich "/packages").
281 ## @brief Ändere die aktuell konfigurierte Repository-URL.
282 ## @details Die URL wird via uci gespeichert. Falls sie identisch mit der Standard-URL ist, wird die Einstellung gelöscht.
283 set_configured_opennet_opkg_repository_url() {
284  local repo_url="$1"
285  _prepare_on_modules
286  if [ -z "$repo_url" ] || [ "$repo_url" = "$(get_default_opennet_opkg_repository_base_url "opennet")" ]; then
287  # Standard-Wert: loeschen
288  uci_delete "on-core.modules.repository_url"
289  else
290  uci set "on-core.modules.repository_url=$repo_url"
291  fi
292  clear_cache_opennet_opkg
293 }
294 
295 
296 ## @fn generate_opennet_opkg_config()
297 ## @brief Liefere den Inhalt einer opkg.conf für das Opennet-Paket-Repository zurück.
298 ## @details Die aktuelle Version wird aus dem openwrt-Versionsstring gelesen.
299 generate_opennet_opkg_config() {
300  trap 'error_trap generate_opennet_opkg_config "$*"' EXIT
301  # schreibe den Inahlt der neuen OPKG-Konfiguration
302  echo "dest root /"
303  echo "dest ram /tmp"
304  echo "lists_dir ext /var/opkg-lists-opennet"
305  echo "option overlay_root /overlay"
306  echo
307 
308  local base_url
309  base_url=$(get_configured_opennet_opkg_repository_base_url)
310 
311  # Füge non-core package hinzu (z.B. feeds routing,opennet,luci,...)
312  # Hole Architektur und CPU Type
313  local arch_cpu_type
314  arch_cpu_type=$(opkg status base-files | awk '/Architecture/ {print $2}')
315  local noncore_pkgs_url="$base_url/packages/$arch_cpu_type"
316 
317  local feed
318  for feed in base packages routing luci opennet; do
319  echo "src/gz on_$feed $noncore_pkgs_url/$feed"
320  done
321 
322  # Fuege zusaetzlich eine URL mit core packages hinzu (beinhaltet Kernel Module).
323  local arch_path
324  # shellcheck source=openwrt/package/base-files/files/etc/openwrt_release
325  arch_path=$(. /etc/openwrt_release; echo "$DISTRIB_TARGET")
326  local core_pkgs_url="$base_url/targets/$arch_path/packages"
327  echo "src/gz on_core $core_pkgs_url"
328 }
329 
330 
331 ## @fn is_package_installed()
332 ## @brief Prüfe, ob ein opkg-Paket installiert ist.
333 ## @param package Name des Pakets
334 is_package_installed() {
335  trap 'error_trap is_package_installed "$*"' EXIT
336  local package="$1"
337  local status
338  # Korrekte Prüfung: via "opkg list-installed" - leider erzeugt sie locking-Fehlermeldung
339  # bei parallelen Abläufen (z.B. Status-Seite).
340  #opkg list-installed | grep -q -w "^$package" && return 0
341  # schneller als via opkg
342  status=$(grep -A 10 "^Package: $package$" "${IPKG_INSTROOT:-}/usr/lib/opkg/status" \
343  | grep "^Status:" | head -1 | cut -f 2- -d :)
344  [ -z "$status" ] && trap "" EXIT && return 1
345  echo "$status" | grep -qE "(deinstall|not-installed)" && trap "" EXIT && return 1
346  return 0
347 }
348 
349 
350 ## @fn on_opkg_postinst_default()
351 ## @brief Übliche Nachbereitung einer on-Paket-Installation.
352 ## @details Caches löschen, uci-defaults anwenden, on-core-Bootskript ausführen
353 on_opkg_postinst_default() {
354  # Reset des Luci-Cache und Shell-Cache
355  clear_caches
356  # Paket-Initialisierungen durchfuehren, falls wir in einem echten System sind.
357  # In der Paket-Bau-Phase funktioniert die untenstehende Aktion nicht, da eine
358  # Datei fehlt, die in der /etc/init.d/boot geladen wird.
359  if [ -z "${IPKG_INSTROOT:-}" ]; then
360  msg_info "Applying uci-defaults after package installation"
361  # Die Angabe von IPKG_INSTROOT ist hier muessig - aber vielleicht
362  # koennen wir die obige Bedingung irgendwann entfernen.
363  (
364  # der Rest sollte ohne Vorsicht stattfinden
365  set +eu
366  # shellcheck source=openwrt/package/base-files/files/etc/init.d/boot
367  . "${IPKG_INSTROOT:-}/etc/init.d/boot"
368  uci_apply_defaults
369  # Boot-Skript aktivieren und ausführen (falls noch nicht geschehen)
370  /etc/init.d/on-core enable 2>/dev/null || true
371  /etc/init.d/on-core start
372  set -eu
373  )
374  fi
376 }
377 
378 
379 ## @fn on_opkg_postrm_default()
380 ## @brief Übliche Nachbereitung einer on-Paket-Entfernung
381 ## @details Caches löschen
382 on_opkg_postrm_default() {
383  clear_caches
385 }
386 
387 # Ende der Doku-Gruppe
388 ## @}
get_on_modules()
Liefere die Namen aller bekannten Opennet-Module zeilenweise getrennt zurück.
Definition: modules.sh:26
uci_delete(uci_path)
Lösche ein UCI-Element.
Definition: uci.sh:46
uci_is_in_list(uci_path, item)
Prüfe ob ein Element in einer Liste vorkommt.
Definition: uci.sh:27
enable_on_module(module)
Aktiviere ein Opennet-Modul.
Definition: modules.sh:13
disable_on_module(module)
Deaktiviere ein Opennet-Modul.
Definition: modules.sh:17
uci_add_list(uci_path, new_item)
Füge einen neuen Wert zu einer UCI-Liste hinzu und achte dabei auf Einmaligkeit.
Definition: uci.sh:10
uci_replace_list()
Replace the items in a list. Wanted items are expected via stdin (one per line, uci_path).
Definition: uci.sh:41
get_missing_modules()
Collect the names of modules that were probably installed before the last upgrade.
Definition: modules.sh:36
set eu grep root::etc shadow exit if command v chpasswd dev null
Definition: on-password:12
msg_info(message)
Informationen und Fehlermeldungen ins syslog schreiben.
Definition: core.sh:15
uci_delete_list(uci_path, value)
Lösche ein Element einer UCI-Liste.
Definition: uci.sh:33
get_not_installed_on_modules()
Ermittle diejenigen Module, die aktuell nicht installiert sind.
Definition: modules.sh:29
warn_if_unknown_module()
Gib eine Warnung aus, falls der angegebene Modul-Name unbekannt ist.
Definition: modules.sh:22
set eu on function print_services services log for dir in etc on services d var on services volatile d
Definition: services:13
msg_error(message)
Die Fehlermeldungen werden in die Standard-Fehlerausgabe und ins syslog geschrieben.
Definition: core.sh:22
done
Definition: core.sh:85
is_on_module_installed_and_enabled(module)
Pruefe ob ein Modul sowohl installiert, als auch aktiv ist.
Definition: modules.sh:9
was_on_module_installed_before()
Prüfe ob ein Modul "früher" (vor der letzten manuellen Änderung durch den Benutzer) installiert war...
Definition: modules.sh:33
clean_luci_restart()
Starte den Webserver neu und lösche alle luci-Cache-Dateien und Kompilate.
Definition: devel.sh:11
install_from_opennet_repository(packages)
Installiere ein Paket aus den Opennet-Repositories.
Definition: modules.sh:46