From 88452a0bff77a695d2f609112450fda5f66839c8 Mon Sep 17 00:00:00 2001 From: Manfred Aabye Date: Mon, 20 Apr 2026 11:35:05 +0200 Subject: [PATCH] 200420261134 --- LICENSE | 42 +- README.md | 402 +- modular/osmtool_cleanup.sh | 250 +- modular/osmtool_config.sh | 438 +- modular/osmtool_core.sh | 912 +- modular/osmtool_cron.sh | 406 +- modular/osmtool_data.sh | 340 +- modular/osmtool_health.sh | 536 +- modular/osmtool_install.sh | 2382 ++--- modular/osmtool_report.sh | 584 +- modular/osmtool_restore.sh | 520 +- modular/osmtool_smoke.sh | 380 +- modular/osmtool_startstop.sh | 790 +- modular/osmtool_update.sh | 522 +- osmtool.sh | 13838 ++++++++++++++--------------- osmtool_backup.sh | 1436 +-- osmtool_main.sh | 860 +- osmtool_restart.sh | 538 +- webphp/bin/osmtool_web_runner.sh | 84 +- 19 files changed, 12630 insertions(+), 12630 deletions(-) diff --git a/LICENSE b/LICENSE index 3a4be34..7525264 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,21 @@ -MIT License - -Copyright (c) 2025 ManfredAabye - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +MIT License + +Copyright (c) 2025 ManfredAabye + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index a4534ca..4bedabc 100644 --- a/README.md +++ b/README.md @@ -1,201 +1,201 @@ -# opensimMULTITOOL II V26.4.230.588 - -Diese README ist fuer Einsteiger geschrieben. - -Wenn du noch nie mit OpenSim oder Bash gearbeitet hast, starte mit den Schritten in diesem Dokument von oben nach unten. - -## 1. Was ist dieses Projekt? - -opensimMULTITOOLS-II hilft dir, einen OpenSim-Server zu: - -- installieren -- starten und stoppen -- neu starten -- sichern (Backups) -- warten und pruefen - -Das Projekt besteht aus zwei Hauptteilen: - -- CLI-Skripte (Konsole): fuer Administration per Terminal -- Web-Oberflaeche unter webphp/: fuer Bedienung im Browser - -Voraussetzungen - -- Linux Server - -## 2. Wichtige Sicherheitshinweise - -- Vor groesseren Aktionen immer Backup machen. -- Erst in einer Testumgebung pruefen, dann auf Produktivsystem nutzen. -- Die Web-Oberflaeche nur mit HTTPS und moeglichst mit IP-Einschraenkung betreiben. -- Standard-Passwoerter sofort aendern. - -## 3. Projektstruktur (kurz erklaert) - -- osmtool_main.sh: Hauptstarter fuer Module und Aktionen -- modular/: einzelne Fachmodule (install, startstop, backup, restore, ...) -- webphp/: Web-Oberflaeche (PHP) -- osmtool.sh: klassisches Hauptskript mit vielen Direktfunktionen - -## 4. Schnellstart fuer Einsteiger (CLI) - -Voraussetzung: Du arbeitest auf Linux und hast Zugriff auf das Projektverzeichnis. - -### Schritt 1: In das Projektverzeichnis wechseln - -```bash -cd /opt/opensimMULTITOOLS-II -``` - -### Schritt 2: Ubuntu vorbereiten - -```bash -bash osmtool_main.sh install-grid-sim -``` - -Hinweis: `install-grid-sim` fuehrt die komplette Installationskette fuer `grid-sim` aus. - -### Schritt 3: OpenSim-Abhaengigkeiten installieren - -```bash -bash osmtool_main.sh install-grid-sim -``` - -### Schritt 4: Server-Check ausfuehren - -```bash -bash osmtool_main.sh healthcheck -``` - -### Schritt 5: OpenSim installieren und konfigurieren - -```bash -bash osmtool_main.sh install-grid-sim -``` - -### Schritt 6: Datenbank einrichten - -```bash -export OSM_DB_PASS='DEIN_PASSWORT' -bash osmtool_main.sh dbsetup -``` - -### Schritt 7: Grid starten - -```bash -bash osmtool_main.sh opensimrestart -``` - -## 5. Alltagsbefehle (die wichtigsten) - -```bash -# Grid neu starten -bash osmtool_main.sh opensimrestart - -# Robust-Datenbank sichern -export OSM_DB_PASS='DEIN_PASSWORT' -bash osmtool_main.sh dbbackup - -# Cronjobs installieren (automatische Backups/Checks) -bash osmtool_main.sh croninstall -``` - -Unterstuetzte Kurzbefehle (Ein-Wort-Aufruf): - -- install-grid-sim -- opensimstart -- opensimstop -- opensimrestart -- healthcheck -- smoketest -- dailyreport -- croninstall -- cronlist -- janusinstall -- janusrestart -- dbsetup -- dbbackup - -## 6. Web-Oberflaeche (webphp) - -Die Web-Oberflaeche ist in webphp/ enthalten und zeigt unter anderem: - -- Modulaktionen -- Kommando-Vorschau -- Ausgabe der Befehle -- Live-Status (Screens, Ports, Artefakte) - -Detaillierte Web-Anleitung: webphp/README.md - -### Wichtige Konfigurationsregel - -Fuer die aktive Web-Konfiguration gilt: - -- webphp/src/config.php = wird wirklich benutzt -- webphp/src/config.sample.php = nur Vorlage - -Wenn du Ports oder Screens fuer den Live-Status aendern willst, musst du in config.php anpassen. - -## 7. Login-Sicherheit der Web-Oberflaeche - -Die Web-Oberflaeche hat einen Schutz gegen Brute-Force-Logins: - -- Nach mehreren falschen Passwortversuchen wird die IP temporaer gesperrt. -- Sperrzeit und Schwelle sind konfigurierbar. -- Login-Ereignisse koennen in einer Audit-Logdatei gespeichert werden. - -Wichtige Einstellungen in webphp/src/config.php: - -- auth_lockout_max_attempts -- auth_lockout_seconds -- optional: auth_store_path -- optional: auth_audit_log_path - -## 8. check_screens einfach erklaert - -Die Funktion check_screens in osmtool.sh: - -- prueft, ob wichtige Screen-Sessions laufen -- schreibt Ergebnisse in ProblemRestarts.log -- meldet auch, wenn ein Dienst laeuft -- startet ausgefallene Dienste neu (kritische Dienste mit Komplett-Neustart) - -## 9. Typische Fehler und schnelle Loesungen - -### Problem: Im Live-Status werden alte oder falsche Ports angezeigt - -Loesung: - -1. Ports in webphp/src/config.php aendern (nicht nur in config.sample.php). -2. Browser mit Hard-Reload neu laden (z. B. Ctrl+Shift+R). -3. Sicherstellen, dass du die richtige Instanz/den richtigen Server aufrufst. - -### Problem: Login gesperrt nach Fehlversuchen - -Loesung: - -- Sperrzeit in auth_lockout_seconds abwarten -- oder Sperrdaten in der konfigurierten Lockout-Datei pruefen - -## 10. Nuetzliche Dateien - -- osmtool_main.sh -- osmtool.sh -- modular/osmtool_startstop.sh -- modular/osmtool_install.sh -- webphp/public/index.php -- webphp/src/config.php -- webphp/src/runner.php -- webphp/src/web_init.php - -## 11. Hilfe - -- Wiki: [opensimMULTITOOLS-II Wiki](https://github.com/ManfredAabye/opensimMULTITOOLS-II/wiki) -- Web-Dokumentation: webphp/README.md - -## 12. Lizenz - -- Skriptname: osmtool.sh -- Version: V26.4.230.588 -- Autor: Manfred Aabye -- Lizenz: MIT +# opensimMULTITOOL II V26.4.230.588 + +Diese README ist fuer Einsteiger geschrieben. + +Wenn du noch nie mit OpenSim oder Bash gearbeitet hast, starte mit den Schritten in diesem Dokument von oben nach unten. + +## 1. Was ist dieses Projekt? + +opensimMULTITOOLS-II hilft dir, einen OpenSim-Server zu: + +- installieren +- starten und stoppen +- neu starten +- sichern (Backups) +- warten und pruefen + +Das Projekt besteht aus zwei Hauptteilen: + +- CLI-Skripte (Konsole): fuer Administration per Terminal +- Web-Oberflaeche unter webphp/: fuer Bedienung im Browser + +Voraussetzungen + +- Linux Server + +## 2. Wichtige Sicherheitshinweise + +- Vor groesseren Aktionen immer Backup machen. +- Erst in einer Testumgebung pruefen, dann auf Produktivsystem nutzen. +- Die Web-Oberflaeche nur mit HTTPS und moeglichst mit IP-Einschraenkung betreiben. +- Standard-Passwoerter sofort aendern. + +## 3. Projektstruktur (kurz erklaert) + +- osmtool_main.sh: Hauptstarter fuer Module und Aktionen +- modular/: einzelne Fachmodule (install, startstop, backup, restore, ...) +- webphp/: Web-Oberflaeche (PHP) +- osmtool.sh: klassisches Hauptskript mit vielen Direktfunktionen + +## 4. Schnellstart fuer Einsteiger (CLI) + +Voraussetzung: Du arbeitest auf Linux und hast Zugriff auf das Projektverzeichnis. + +### Schritt 1: In das Projektverzeichnis wechseln + +```bash +cd /opt/opensimMULTITOOLS-II +``` + +### Schritt 2: Ubuntu vorbereiten + +```bash +bash osmtool_main.sh install-grid-sim +``` + +Hinweis: `install-grid-sim` fuehrt die komplette Installationskette fuer `grid-sim` aus. + +### Schritt 3: OpenSim-Abhaengigkeiten installieren + +```bash +bash osmtool_main.sh install-grid-sim +``` + +### Schritt 4: Server-Check ausfuehren + +```bash +bash osmtool_main.sh healthcheck +``` + +### Schritt 5: OpenSim installieren und konfigurieren + +```bash +bash osmtool_main.sh install-grid-sim +``` + +### Schritt 6: Datenbank einrichten + +```bash +export OSM_DB_PASS='DEIN_PASSWORT' +bash osmtool_main.sh dbsetup +``` + +### Schritt 7: Grid starten + +```bash +bash osmtool_main.sh opensimrestart +``` + +## 5. Alltagsbefehle (die wichtigsten) + +```bash +# Grid neu starten +bash osmtool_main.sh opensimrestart + +# Robust-Datenbank sichern +export OSM_DB_PASS='DEIN_PASSWORT' +bash osmtool_main.sh dbbackup + +# Cronjobs installieren (automatische Backups/Checks) +bash osmtool_main.sh croninstall +``` + +Unterstuetzte Kurzbefehle (Ein-Wort-Aufruf): + +- install-grid-sim +- opensimstart +- opensimstop +- opensimrestart +- healthcheck +- smoketest +- dailyreport +- croninstall +- cronlist +- janusinstall +- janusrestart +- dbsetup +- dbbackup + +## 6. Web-Oberflaeche (webphp) + +Die Web-Oberflaeche ist in webphp/ enthalten und zeigt unter anderem: + +- Modulaktionen +- Kommando-Vorschau +- Ausgabe der Befehle +- Live-Status (Screens, Ports, Artefakte) + +Detaillierte Web-Anleitung: webphp/README.md + +### Wichtige Konfigurationsregel + +Fuer die aktive Web-Konfiguration gilt: + +- webphp/src/config.php = wird wirklich benutzt +- webphp/src/config.sample.php = nur Vorlage + +Wenn du Ports oder Screens fuer den Live-Status aendern willst, musst du in config.php anpassen. + +## 7. Login-Sicherheit der Web-Oberflaeche + +Die Web-Oberflaeche hat einen Schutz gegen Brute-Force-Logins: + +- Nach mehreren falschen Passwortversuchen wird die IP temporaer gesperrt. +- Sperrzeit und Schwelle sind konfigurierbar. +- Login-Ereignisse koennen in einer Audit-Logdatei gespeichert werden. + +Wichtige Einstellungen in webphp/src/config.php: + +- auth_lockout_max_attempts +- auth_lockout_seconds +- optional: auth_store_path +- optional: auth_audit_log_path + +## 8. check_screens einfach erklaert + +Die Funktion check_screens in osmtool.sh: + +- prueft, ob wichtige Screen-Sessions laufen +- schreibt Ergebnisse in ProblemRestarts.log +- meldet auch, wenn ein Dienst laeuft +- startet ausgefallene Dienste neu (kritische Dienste mit Komplett-Neustart) + +## 9. Typische Fehler und schnelle Loesungen + +### Problem: Im Live-Status werden alte oder falsche Ports angezeigt + +Loesung: + +1. Ports in webphp/src/config.php aendern (nicht nur in config.sample.php). +2. Browser mit Hard-Reload neu laden (z. B. Ctrl+Shift+R). +3. Sicherstellen, dass du die richtige Instanz/den richtigen Server aufrufst. + +### Problem: Login gesperrt nach Fehlversuchen + +Loesung: + +- Sperrzeit in auth_lockout_seconds abwarten +- oder Sperrdaten in der konfigurierten Lockout-Datei pruefen + +## 10. Nuetzliche Dateien + +- osmtool_main.sh +- osmtool.sh +- modular/osmtool_startstop.sh +- modular/osmtool_install.sh +- webphp/public/index.php +- webphp/src/config.php +- webphp/src/runner.php +- webphp/src/web_init.php + +## 11. Hilfe + +- Wiki: [opensimMULTITOOLS-II Wiki](https://github.com/ManfredAabye/opensimMULTITOOLS-II/wiki) +- Web-Dokumentation: webphp/README.md + +## 12. Lizenz + +- Skriptname: osmtool.sh +- Version: V26.4.230.588 +- Autor: Manfred Aabye +- Lizenz: MIT diff --git a/modular/osmtool_cleanup.sh b/modular/osmtool_cleanup.sh index adb3e2f..c45a7ea 100644 --- a/modular/osmtool_cleanup.sh +++ b/modular/osmtool_cleanup.sh @@ -1,125 +1,125 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_cleanup.sh [--workdir ] --action [--dry-run ] - -Examples: - osmtool_cleanup.sh --action log-clean --workdir /opt --dry-run true - osmtool_cleanup.sh --action cache-clean --workdir /opt/opensim -EOF - print_usage_common -} - -realpath_safe() { - local p="$1" - python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$p" 2>/dev/null || echo "$p" -} - -assert_safe_workdir() { - local rp - rp="$(realpath_safe "$WORKDIR")" - - [[ -n "$rp" ]] || die "Invalid workdir" - [[ "$rp" != "/" ]] || die "Refusing cleanup on root directory" - [[ "$rp" != "/opt" ]] || die "Refusing cleanup on /opt root; choose a dedicated OpenSim workdir" - [[ -d "$rp" ]] || die "Workdir not found: $rp" - - WORKDIR="$rp" -} - -run_delete() { - local path="$1" - - if [[ "$DRY_RUN" == "true" ]]; then - log INFO "[DRY-RUN] Would remove: $path" - else - rm -rf "$path" - log INFO "Removed: $path" - fi -} - -run_delete_file() { - local path="$1" - - if [[ "$DRY_RUN" == "true" ]]; then - log INFO "[DRY-RUN] Would delete file: $path" - else - rm -f "$path" - log INFO "Deleted file: $path" - fi -} - -cache_clean() { - log INFO "Cleaning map tiles and cache under $WORKDIR" - local d - while IFS= read -r d; do - [[ -n "$d" ]] || continue - run_delete "$d" - done < <(find "$WORKDIR" -mindepth 2 -type d \( -name "assetcache" -o -name "MapTiles" -o -name "cache" \)) -} - -log_clean() { - log INFO "Cleaning log files under $WORKDIR" - local f - while IFS= read -r f; do - [[ -n "$f" ]] || continue - run_delete_file "$f" - done < <(find "$WORKDIR" -type f \( -name "*.log" -o -name "OpenSim.log" -o -name "ProblemRestarts.log" \)) -} - -tmp_clean() { - log INFO "Cleaning temporary files under $WORKDIR" - local f - while IFS= read -r f; do - [[ -n "$f" ]] || continue - run_delete_file "$f" - done < <(find "$WORKDIR" -type f \( -name "*.tmp" -o -name "*.temp" \)) -} - -safe_reboot() { - if confirm "Reboot" "Reboot server now?"; then - log INFO "Reboot requested" - sudo reboot - else - log INFO "Reboot canceled" - fi -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" -DRY_RUN="false" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --dry-run) DRY_RUN="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed cleanup "$PROFILE" "$ACTION" -case "$DRY_RUN" in true|false) ;; *) die "--dry-run must be true or false" ;; esac -assert_safe_workdir -log INFO "Using profile: $PROFILE" -log INFO "Dry-run mode: $DRY_RUN" - -case "$ACTION" in - cache-clean) cache_clean ;; - log-clean) log_clean ;; - tmp-clean) tmp_clean ;; - reboot) safe_reboot ;; - *) die "Unsupported action: $ACTION" ;; -esac +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_cleanup.sh [--workdir ] --action [--dry-run ] + +Examples: + osmtool_cleanup.sh --action log-clean --workdir /opt --dry-run true + osmtool_cleanup.sh --action cache-clean --workdir /opt/opensim +EOF + print_usage_common +} + +realpath_safe() { + local p="$1" + python3 -c 'import os,sys; print(os.path.realpath(sys.argv[1]))' "$p" 2>/dev/null || echo "$p" +} + +assert_safe_workdir() { + local rp + rp="$(realpath_safe "$WORKDIR")" + + [[ -n "$rp" ]] || die "Invalid workdir" + [[ "$rp" != "/" ]] || die "Refusing cleanup on root directory" + [[ "$rp" != "/opt" ]] || die "Refusing cleanup on /opt root; choose a dedicated OpenSim workdir" + [[ -d "$rp" ]] || die "Workdir not found: $rp" + + WORKDIR="$rp" +} + +run_delete() { + local path="$1" + + if [[ "$DRY_RUN" == "true" ]]; then + log INFO "[DRY-RUN] Would remove: $path" + else + rm -rf "$path" + log INFO "Removed: $path" + fi +} + +run_delete_file() { + local path="$1" + + if [[ "$DRY_RUN" == "true" ]]; then + log INFO "[DRY-RUN] Would delete file: $path" + else + rm -f "$path" + log INFO "Deleted file: $path" + fi +} + +cache_clean() { + log INFO "Cleaning map tiles and cache under $WORKDIR" + local d + while IFS= read -r d; do + [[ -n "$d" ]] || continue + run_delete "$d" + done < <(find "$WORKDIR" -mindepth 2 -type d \( -name "assetcache" -o -name "MapTiles" -o -name "cache" \)) +} + +log_clean() { + log INFO "Cleaning log files under $WORKDIR" + local f + while IFS= read -r f; do + [[ -n "$f" ]] || continue + run_delete_file "$f" + done < <(find "$WORKDIR" -type f \( -name "*.log" -o -name "OpenSim.log" -o -name "ProblemRestarts.log" \)) +} + +tmp_clean() { + log INFO "Cleaning temporary files under $WORKDIR" + local f + while IFS= read -r f; do + [[ -n "$f" ]] || continue + run_delete_file "$f" + done < <(find "$WORKDIR" -type f \( -name "*.tmp" -o -name "*.temp" \)) +} + +safe_reboot() { + if confirm "Reboot" "Reboot server now?"; then + log INFO "Reboot requested" + sudo reboot + else + log INFO "Reboot canceled" + fi +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" +DRY_RUN="false" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --dry-run) DRY_RUN="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed cleanup "$PROFILE" "$ACTION" +case "$DRY_RUN" in true|false) ;; *) die "--dry-run must be true or false" ;; esac +assert_safe_workdir +log INFO "Using profile: $PROFILE" +log INFO "Dry-run mode: $DRY_RUN" + +case "$ACTION" in + cache-clean) cache_clean ;; + log-clean) log_clean ;; + tmp-clean) tmp_clean ;; + reboot) safe_reboot ;; + *) die "Unsupported action: $ACTION" ;; +esac diff --git a/modular/osmtool_config.sh b/modular/osmtool_config.sh index 115b946..5921cf1 100644 --- a/modular/osmtool_config.sh +++ b/modular/osmtool_config.sh @@ -1,220 +1,220 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_config.sh [--workdir ] --action - [--file ] [--strict ] - -Examples: - osmtool_config.sh --action init-config - osmtool_config.sh --action validate-file --file /opt/sim1/bin/OpenSim.ini - osmtool_config.sh --action validate-runtime --profile grid-sim --workdir /opt -EOF - print_usage_common -} - -trim() { - local value="$1" - value="${value#"${value%%[![:space:]]*}"}" - value="${value%"${value##*[![:space:]]}"}" - printf '%s' "$value" -} - -check_runtime_file() { - local file="$1" - local errors_before="$VALIDATION_ERRORS" - - if [[ ! -f "$file" ]]; then - log ERROR "Missing config file: $file" - VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) - return 1 - fi - - validate_file "$file" - if [[ "$VALIDATION_ERRORS" -gt "$errors_before" ]]; then - return 1 - fi - - return 0 -} - -validate_ini_file() { - local file="$1" - local line_number=0 - local line trimmed seen_section=false - - while IFS= read -r line || [[ -n "$line" ]]; do - line_number=$((line_number + 1)) - trimmed="$(trim "$line")" - - [[ -z "$trimmed" ]] && continue - case "$trimmed" in - ';'*|'#'*) continue ;; - '['*']') - seen_section=true - continue - ;; - *=*) - continue - ;; - .include*) - continue - ;; - *) - log ERROR "Invalid INI syntax in $file:$line_number -> $line" - VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) - ;; - esac - done < "$file" - - if [[ "$STRICT" == "true" && "$seen_section" == "false" ]]; then - log ERROR "INI file has no section headers: $file" - VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) - fi -} - -validate_json_file() { - local file="$1" - - if command -v jq >/dev/null 2>&1; then - if ! jq empty "$file" >/dev/null 2>&1; then - log ERROR "Invalid JSON syntax: $file" - VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) - fi - return 0 - fi - - if command -v python3 >/dev/null 2>&1; then - if ! python3 -m json.tool "$file" >/dev/null 2>&1; then - log ERROR "Invalid JSON syntax: $file" - VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) - fi - return 0 - fi - - die "validate-json requires jq or python3" -} - -validate_file() { - local file="$1" - - [[ -f "$file" ]] || die "Config file not found: $file" - - case "$file" in - *.ini|*.INI) - log INFO "Validating INI file: $file" - validate_ini_file "$file" - ;; - *.json|*.JSON) - log INFO "Validating JSON file: $file" - validate_json_file "$file" - ;; - *) - die "Unsupported config file type: $file" - ;; - esac -} - -validate_grid_runtime() { - local sim_ini - local sim_count=0 - - check_runtime_file "$WORKDIR/robust/bin/Robust.ini" - - shopt -s nullglob - for sim_ini in "$WORKDIR"/sim*/bin/OpenSim.ini; do - sim_count=$((sim_count + 1)) - check_runtime_file "$sim_ini" - done - shopt -u nullglob - - if [[ "$sim_count" -eq 0 ]]; then - log ERROR "No region runtime configs found under $WORKDIR/sim*/bin/OpenSim.ini" - VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) - fi -} - -validate_robust_runtime() { - check_runtime_file "$WORKDIR/robust/bin/Robust.ini" -} - -validate_standalone_runtime() { - check_runtime_file "$WORKDIR/standalone/bin/OpenSim.ini" -} - -validate_runtime() { - case "$PROFILE" in - grid-sim) validate_grid_runtime ;; - robust) validate_robust_runtime ;; - standalone) validate_standalone_runtime ;; - esac - - if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then - die "Configuration validation failed with $VALIDATION_ERRORS issue(s)" - fi - - log INFO "Configuration validation passed" -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" -FILE="" -STRICT="false" -VALIDATION_ERRORS=0 - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --file) FILE="$2"; shift 2 ;; - --strict) STRICT="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed config "$PROFILE" "$ACTION" - -if [[ "$ACTION" != "init-config" && ! -f "$OSMTOOL_CONFIG_FILE" ]]; then - if [[ -t 0 ]]; then - log INFO "Shared configuration not found. Starting interactive setup." - init_shared_config_interactive - else - log INFO "Shared configuration not found at $OSMTOOL_CONFIG_FILE (non-interactive mode)" - fi -fi - -case "$STRICT" in - true|false) ;; - *) die "--strict must be true or false" ;; -esac - -log INFO "Using profile: $PROFILE" - -case "$ACTION" in - init-config) - init_shared_config_interactive - ;; - validate-file) - [[ -n "$FILE" ]] || die "validate-file requires --file" - validate_file "$FILE" - if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then - die "Configuration validation failed with $VALIDATION_ERRORS issue(s)" - fi - log INFO "Configuration validation passed" - ;; - validate-runtime) - validate_runtime - ;; - *) die "Unsupported action: $ACTION" ;; +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_config.sh [--workdir ] --action + [--file ] [--strict ] + +Examples: + osmtool_config.sh --action init-config + osmtool_config.sh --action validate-file --file /opt/sim1/bin/OpenSim.ini + osmtool_config.sh --action validate-runtime --profile grid-sim --workdir /opt +EOF + print_usage_common +} + +trim() { + local value="$1" + value="${value#"${value%%[![:space:]]*}"}" + value="${value%"${value##*[![:space:]]}"}" + printf '%s' "$value" +} + +check_runtime_file() { + local file="$1" + local errors_before="$VALIDATION_ERRORS" + + if [[ ! -f "$file" ]]; then + log ERROR "Missing config file: $file" + VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) + return 1 + fi + + validate_file "$file" + if [[ "$VALIDATION_ERRORS" -gt "$errors_before" ]]; then + return 1 + fi + + return 0 +} + +validate_ini_file() { + local file="$1" + local line_number=0 + local line trimmed seen_section=false + + while IFS= read -r line || [[ -n "$line" ]]; do + line_number=$((line_number + 1)) + trimmed="$(trim "$line")" + + [[ -z "$trimmed" ]] && continue + case "$trimmed" in + ';'*|'#'*) continue ;; + '['*']') + seen_section=true + continue + ;; + *=*) + continue + ;; + .include*) + continue + ;; + *) + log ERROR "Invalid INI syntax in $file:$line_number -> $line" + VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) + ;; + esac + done < "$file" + + if [[ "$STRICT" == "true" && "$seen_section" == "false" ]]; then + log ERROR "INI file has no section headers: $file" + VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) + fi +} + +validate_json_file() { + local file="$1" + + if command -v jq >/dev/null 2>&1; then + if ! jq empty "$file" >/dev/null 2>&1; then + log ERROR "Invalid JSON syntax: $file" + VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) + fi + return 0 + fi + + if command -v python3 >/dev/null 2>&1; then + if ! python3 -m json.tool "$file" >/dev/null 2>&1; then + log ERROR "Invalid JSON syntax: $file" + VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) + fi + return 0 + fi + + die "validate-json requires jq or python3" +} + +validate_file() { + local file="$1" + + [[ -f "$file" ]] || die "Config file not found: $file" + + case "$file" in + *.ini|*.INI) + log INFO "Validating INI file: $file" + validate_ini_file "$file" + ;; + *.json|*.JSON) + log INFO "Validating JSON file: $file" + validate_json_file "$file" + ;; + *) + die "Unsupported config file type: $file" + ;; + esac +} + +validate_grid_runtime() { + local sim_ini + local sim_count=0 + + check_runtime_file "$WORKDIR/robust/bin/Robust.ini" + + shopt -s nullglob + for sim_ini in "$WORKDIR"/sim*/bin/OpenSim.ini; do + sim_count=$((sim_count + 1)) + check_runtime_file "$sim_ini" + done + shopt -u nullglob + + if [[ "$sim_count" -eq 0 ]]; then + log ERROR "No region runtime configs found under $WORKDIR/sim*/bin/OpenSim.ini" + VALIDATION_ERRORS=$((VALIDATION_ERRORS + 1)) + fi +} + +validate_robust_runtime() { + check_runtime_file "$WORKDIR/robust/bin/Robust.ini" +} + +validate_standalone_runtime() { + check_runtime_file "$WORKDIR/standalone/bin/OpenSim.ini" +} + +validate_runtime() { + case "$PROFILE" in + grid-sim) validate_grid_runtime ;; + robust) validate_robust_runtime ;; + standalone) validate_standalone_runtime ;; + esac + + if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then + die "Configuration validation failed with $VALIDATION_ERRORS issue(s)" + fi + + log INFO "Configuration validation passed" +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" +FILE="" +STRICT="false" +VALIDATION_ERRORS=0 + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --file) FILE="$2"; shift 2 ;; + --strict) STRICT="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed config "$PROFILE" "$ACTION" + +if [[ "$ACTION" != "init-config" && ! -f "$OSMTOOL_CONFIG_FILE" ]]; then + if [[ -t 0 ]]; then + log INFO "Shared configuration not found. Starting interactive setup." + init_shared_config_interactive + else + log INFO "Shared configuration not found at $OSMTOOL_CONFIG_FILE (non-interactive mode)" + fi +fi + +case "$STRICT" in + true|false) ;; + *) die "--strict must be true or false" ;; +esac + +log INFO "Using profile: $PROFILE" + +case "$ACTION" in + init-config) + init_shared_config_interactive + ;; + validate-file) + [[ -n "$FILE" ]] || die "validate-file requires --file" + validate_file "$FILE" + if [[ "$VALIDATION_ERRORS" -gt 0 ]]; then + die "Configuration validation failed with $VALIDATION_ERRORS issue(s)" + fi + log INFO "Configuration validation passed" + ;; + validate-runtime) + validate_runtime + ;; + *) die "Unsupported action: $ACTION" ;; esac \ No newline at end of file diff --git a/modular/osmtool_core.sh b/modular/osmtool_core.sh index 9252cf8..192a570 100644 --- a/modular/osmtool_core.sh +++ b/modular/osmtool_core.sh @@ -1,456 +1,456 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -export DEFAULT_WORKDIR="/opt" -export OSMTOOL_CONFIG_FILE="${OSMTOOL_CONFIG_FILE:-$ROOT_DIR/osmtool_config.json}" -LANG_DIR="$ROOT_DIR/lang" -APP_LANG="${OSM_LANG:-de}" - -LOG_FILE="${LOG_FILE:-$ROOT_DIR/osmtool_backup.log}" - -declare -A I18N_CURRENT=() -declare -A I18N_EN=() - -log() { - local level="$1" - shift - printf '[%s] [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$*" | tee -a "$LOG_FILE" -} - -die() { - log ERROR "$*" - exit 1 -} - -need_cmd() { - command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1" -} - -normalize_lang() { - case "$1" in - de|en|fr|es) echo "$1" ;; - *) echo "de" ;; - esac -} - -config_get_string() { - local key="$1" - local default_value="$2" - local value="" - - [[ -f "$OSMTOOL_CONFIG_FILE" ]] || { - printf '%s' "$default_value" - return - } - - if command -v jq >/dev/null 2>&1; then - value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)" - else - value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*\"([^\"]*)\"[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)" - fi - - if [[ -n "$value" ]]; then - printf '%s' "$value" - else - printf '%s' "$default_value" - fi -} - -config_get_bool() { - local key="$1" - local default_value="$2" - local value="" - - [[ -f "$OSMTOOL_CONFIG_FILE" ]] || { - printf '%s' "$default_value" - return - } - - if command -v jq >/dev/null 2>&1; then - value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)" - else - value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*(true|false)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)" - fi - - case "$value" in - true|false) printf '%s' "$value" ;; - *) printf '%s' "$default_value" ;; - esac -} - -config_get_int() { - local key="$1" - local default_value="$2" - local value="" - - [[ -f "$OSMTOOL_CONFIG_FILE" ]] || { - printf '%s' "$default_value" - return - } - - if command -v jq >/dev/null 2>&1; then - value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)" - else - value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*([0-9]+)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)" - fi - - if [[ "$value" =~ ^[0-9]+$ ]]; then - printf '%s' "$value" - else - printf '%s' "$default_value" - fi -} - -config_path_value() { - local value="$1" - if [[ "$value" = /* ]]; then - printf '%s' "$value" - else - printf '%s' "$ROOT_DIR/$value" - fi -} - -load_shared_config() { - local cfg_lang cfg_workdir - - cfg_lang="$(normalize_lang "$(config_get_string "language" "de")")" - cfg_workdir="$(config_get_string "path_workdir" "$DEFAULT_WORKDIR")" - - DEFAULT_WORKDIR="$cfg_workdir" - export DEFAULT_WORKDIR - - if [[ -z "${OSM_LANG:-}" ]]; then - APP_LANG="$cfg_lang" - fi - - CONFIG_DB_ROOT_USER="$(config_get_string "db_root_user" "root")" - CONFIG_DB_ROOT_PASS="$(config_get_string "db_root_pass" "")" - CONFIG_DB_USER="$(config_get_string "db_user" "opensimuser")" - CONFIG_DB_PASS="$(config_get_string "db_pass" "")" - CONFIG_PUBLIC_HOST="$(config_get_string "public_host" "127.0.0.1")" - CONFIG_GRIDNAME="$(config_get_string "gridname" "")" - CONFIG_JANUS_PREFIX="$(config_get_string "janus_prefix" "/opt/janus")" - CONFIG_OPENSIM_DIR="$(config_get_string "opensim_dir" "")" - - export CONFIG_DB_ROOT_USER CONFIG_DB_ROOT_PASS CONFIG_DB_USER CONFIG_DB_PASS - export CONFIG_PUBLIC_HOST CONFIG_GRIDNAME CONFIG_JANUS_PREFIX CONFIG_OPENSIM_DIR -} - -config_prompt_with_default() { - local prompt="$1" - local default_value="$2" - local answer="" - - read -r -p "$prompt [$default_value]: " answer - if [[ -z "$answer" ]]; then - printf '%s' "$default_value" - else - printf '%s' "$answer" - fi -} - -write_shared_config_file() { - local language="$1" - local workdir="$2" - local db_root_user="$3" - local db_root_pass="$4" - local db_user="$5" - local db_pass="$6" - local public_host="$7" - local gridname="$8" - local janus_prefix="$9" - local opensim_dir="${10}" - - cat > "$OSMTOOL_CONFIG_FILE" </dev/null 2>&1; then - echo "whiptail" - return - fi - - if command -v dialog >/dev/null 2>&1; then - echo "dialog" - return - fi - - echo "none" -} - -show_menu() { - local title="$1" - local text="$2" - shift 2 - local backend - backend="$(ui_backend)" - - case "$backend" in - whiptail) - whiptail --title "$title" --menu "$text" 20 80 12 "$@" 3>&1 1>&2 2>&3 - ;; - dialog) - dialog --clear --stdout --title "$title" --menu "$text" 20 80 12 "$@" - ;; - none) - die "$(msg ERR_NO_UI_BACKEND)" - ;; - esac -} - -confirm() { - local title="$1" - local text="$2" - local backend - backend="$(ui_backend)" - - case "$backend" in - whiptail) - whiptail --title "$title" --yesno "$text" 10 70 - ;; - dialog) - dialog --clear --title "$title" --yesno "$text" 10 70 - ;; - none) - return 1 - ;; - esac -} - -print_usage_common() { - cat <<'EOF' -Global options: - --workdir Base path (default: /opt) - --mode Run in CLI mode (default) or menu mode - --lang Language selection - --profile Runtime profile (grid-sim|robust|standalone) - --help Show help -EOF -} - -# Load shared settings before translations and module defaults are resolved. -load_shared_config - -# Ensure translations are available in every script that sources this core. -init_i18n +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +export DEFAULT_WORKDIR="/opt" +export OSMTOOL_CONFIG_FILE="${OSMTOOL_CONFIG_FILE:-$ROOT_DIR/osmtool_config.json}" +LANG_DIR="$ROOT_DIR/lang" +APP_LANG="${OSM_LANG:-de}" + +LOG_FILE="${LOG_FILE:-$ROOT_DIR/osmtool_backup.log}" + +declare -A I18N_CURRENT=() +declare -A I18N_EN=() + +log() { + local level="$1" + shift + printf '[%s] [%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$level" "$*" | tee -a "$LOG_FILE" +} + +die() { + log ERROR "$*" + exit 1 +} + +need_cmd() { + command -v "$1" >/dev/null 2>&1 || die "Missing required command: $1" +} + +normalize_lang() { + case "$1" in + de|en|fr|es) echo "$1" ;; + *) echo "de" ;; + esac +} + +config_get_string() { + local key="$1" + local default_value="$2" + local value="" + + [[ -f "$OSMTOOL_CONFIG_FILE" ]] || { + printf '%s' "$default_value" + return + } + + if command -v jq >/dev/null 2>&1; then + value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)" + else + value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*\"([^\"]*)\"[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)" + fi + + if [[ -n "$value" ]]; then + printf '%s' "$value" + else + printf '%s' "$default_value" + fi +} + +config_get_bool() { + local key="$1" + local default_value="$2" + local value="" + + [[ -f "$OSMTOOL_CONFIG_FILE" ]] || { + printf '%s' "$default_value" + return + } + + if command -v jq >/dev/null 2>&1; then + value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)" + else + value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*(true|false)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)" + fi + + case "$value" in + true|false) printf '%s' "$value" ;; + *) printf '%s' "$default_value" ;; + esac +} + +config_get_int() { + local key="$1" + local default_value="$2" + local value="" + + [[ -f "$OSMTOOL_CONFIG_FILE" ]] || { + printf '%s' "$default_value" + return + } + + if command -v jq >/dev/null 2>&1; then + value="$(jq -r --arg k "$key" '.[$k] // empty' "$OSMTOOL_CONFIG_FILE" 2>/dev/null || true)" + else + value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*([0-9]+)[[:space:]]*,?[[:space:]]*$/\1/p" "$OSMTOOL_CONFIG_FILE" | head -n1)" + fi + + if [[ "$value" =~ ^[0-9]+$ ]]; then + printf '%s' "$value" + else + printf '%s' "$default_value" + fi +} + +config_path_value() { + local value="$1" + if [[ "$value" = /* ]]; then + printf '%s' "$value" + else + printf '%s' "$ROOT_DIR/$value" + fi +} + +load_shared_config() { + local cfg_lang cfg_workdir + + cfg_lang="$(normalize_lang "$(config_get_string "language" "de")")" + cfg_workdir="$(config_get_string "path_workdir" "$DEFAULT_WORKDIR")" + + DEFAULT_WORKDIR="$cfg_workdir" + export DEFAULT_WORKDIR + + if [[ -z "${OSM_LANG:-}" ]]; then + APP_LANG="$cfg_lang" + fi + + CONFIG_DB_ROOT_USER="$(config_get_string "db_root_user" "root")" + CONFIG_DB_ROOT_PASS="$(config_get_string "db_root_pass" "")" + CONFIG_DB_USER="$(config_get_string "db_user" "opensimuser")" + CONFIG_DB_PASS="$(config_get_string "db_pass" "")" + CONFIG_PUBLIC_HOST="$(config_get_string "public_host" "127.0.0.1")" + CONFIG_GRIDNAME="$(config_get_string "gridname" "")" + CONFIG_JANUS_PREFIX="$(config_get_string "janus_prefix" "/opt/janus")" + CONFIG_OPENSIM_DIR="$(config_get_string "opensim_dir" "")" + + export CONFIG_DB_ROOT_USER CONFIG_DB_ROOT_PASS CONFIG_DB_USER CONFIG_DB_PASS + export CONFIG_PUBLIC_HOST CONFIG_GRIDNAME CONFIG_JANUS_PREFIX CONFIG_OPENSIM_DIR +} + +config_prompt_with_default() { + local prompt="$1" + local default_value="$2" + local answer="" + + read -r -p "$prompt [$default_value]: " answer + if [[ -z "$answer" ]]; then + printf '%s' "$default_value" + else + printf '%s' "$answer" + fi +} + +write_shared_config_file() { + local language="$1" + local workdir="$2" + local db_root_user="$3" + local db_root_pass="$4" + local db_user="$5" + local db_pass="$6" + local public_host="$7" + local gridname="$8" + local janus_prefix="$9" + local opensim_dir="${10}" + + cat > "$OSMTOOL_CONFIG_FILE" </dev/null 2>&1; then + echo "whiptail" + return + fi + + if command -v dialog >/dev/null 2>&1; then + echo "dialog" + return + fi + + echo "none" +} + +show_menu() { + local title="$1" + local text="$2" + shift 2 + local backend + backend="$(ui_backend)" + + case "$backend" in + whiptail) + whiptail --title "$title" --menu "$text" 20 80 12 "$@" 3>&1 1>&2 2>&3 + ;; + dialog) + dialog --clear --stdout --title "$title" --menu "$text" 20 80 12 "$@" + ;; + none) + die "$(msg ERR_NO_UI_BACKEND)" + ;; + esac +} + +confirm() { + local title="$1" + local text="$2" + local backend + backend="$(ui_backend)" + + case "$backend" in + whiptail) + whiptail --title "$title" --yesno "$text" 10 70 + ;; + dialog) + dialog --clear --title "$title" --yesno "$text" 10 70 + ;; + none) + return 1 + ;; + esac +} + +print_usage_common() { + cat <<'EOF' +Global options: + --workdir Base path (default: /opt) + --mode Run in CLI mode (default) or menu mode + --lang Language selection + --profile Runtime profile (grid-sim|robust|standalone) + --help Show help +EOF +} + +# Load shared settings before translations and module defaults are resolved. +load_shared_config + +# Ensure translations are available in every script that sources this core. +init_i18n diff --git a/modular/osmtool_cron.sh b/modular/osmtool_cron.sh index da23194..16eeae9 100644 --- a/modular/osmtool_cron.sh +++ b/modular/osmtool_cron.sh @@ -1,203 +1,203 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_cron.sh [--workdir ] --action - [--backup-schedule ""] [--restart-schedule ""] [--check-schedule ""] [--report-schedule ""] [--smoke-schedule ""] - [--db-user ] [--db-pass ] [--db-name ] - [--region ] [--session ] [--compress ] - -Examples: - osmtool_cron.sh --action list - osmtool_cron.sh --action install --backup-schedule "0 3 * * *" --db-user root --db-pass secret --db-name opensim --region sim1 - osmtool_cron.sh --action remove -EOF - print_usage_common -} - -need_crontab() { - need_cmd crontab -} - -quote_sq() { - local s="$1" - s="${s//\'/\'\"\'\"\'}" - printf "'%s'" "$s" -} - -build_backup_cmd() { - local cmd - cmd="bash $ROOT_DIR/osmtool_main.sh --module backup --profile $PROFILE --workdir $WORKDIR --action full-backup --db-user $DB_USER --db-name $DB_NAME --region $REGION --session $SESSION_NAME --compress $COMPRESS" - - if [[ -n "$DB_PASS" ]]; then - cmd+=" --db-pass $DB_PASS" - fi - - printf '%s' "$cmd" -} - -build_restart_cmd() { - printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module startstop --profile $PROFILE --workdir $WORKDIR --target grid --action restart" -} - -build_check_cmd() { - printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module install --profile $PROFILE --workdir $WORKDIR --action server-check" -} - -build_report_cmd() { - local cmd - cmd="bash $ROOT_DIR/osmtool_main.sh --module report --profile $PROFILE --workdir $WORKDIR --action generate --db-user $DB_USER --db-name $DB_NAME" - - if [[ -n "$DB_PASS" ]]; then - cmd+=" --db-pass $DB_PASS" - fi - - printf '%s' "$cmd" -} - -build_smoke_cmd() { - printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module smoke --profile $PROFILE --workdir $WORKDIR --action run" -} - -cron_block_start="# OSMTOOL_CRON_BEGIN" -cron_block_end="# OSMTOOL_CRON_END" - -emit_cron_block() { - local backup_cmd restart_cmd check_cmd report_cmd smoke_cmd - backup_cmd="$(build_backup_cmd)" - restart_cmd="$(build_restart_cmd)" - check_cmd="$(build_check_cmd)" - report_cmd="$(build_report_cmd)" - smoke_cmd="$(build_smoke_cmd)" - - echo "$cron_block_start" - echo "SHELL=/bin/bash" - echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" - echo "$BACKUP_SCHEDULE $backup_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" - echo "$RESTART_SCHEDULE $restart_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" - echo "$CHECK_SCHEDULE $check_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" - echo "$REPORT_SCHEDULE $report_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" - echo "$SMOKE_SCHEDULE $smoke_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" - echo "$cron_block_end" -} - -existing_crontab() { - crontab -l 2>/dev/null || true -} - -strip_osmtool_block() { - awk -v start="$cron_block_start" -v end="$cron_block_end" ' - $0 == start {inblock=1; next} - $0 == end {inblock=0; next} - !inblock {print} - ' -} - -install_cron() { - local current tmp - [[ -n "$DB_USER" && -n "$DB_NAME" ]] || die "install cron requires --db-user and --db-name" - - current="$(existing_crontab)" - tmp="$(mktemp)" - - printf '%s\n' "$current" | strip_osmtool_block > "$tmp" - if [[ -s "$tmp" ]]; then - echo >> "$tmp" - fi - emit_cron_block >> "$tmp" - - crontab "$tmp" - rm -f "$tmp" - log INFO "OSMTool cron jobs installed/updated" -} - -list_cron() { - local current - current="$(existing_crontab)" - - if printf '%s\n' "$current" | grep -q "^$cron_block_start$"; then - printf '%s\n' "$current" | awk -v start="$cron_block_start" -v end="$cron_block_end" ' - $0 == start {inblock=1; print; next} - $0 == end {print; inblock=0; next} - inblock {print} - ' - else - log INFO "No OSMTool cron block configured" - fi -} - -remove_cron() { - local current tmp - current="$(existing_crontab)" - tmp="$(mktemp)" - - printf '%s\n' "$current" | strip_osmtool_block > "$tmp" - crontab "$tmp" - rm -f "$tmp" - log INFO "OSMTool cron block removed" -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" - -BACKUP_SCHEDULE="0 3 * * *" -RESTART_SCHEDULE="0 5 * * 1" -CHECK_SCHEDULE="*/15 * * * *" -REPORT_SCHEDULE="30 6 * * *" -SMOKE_SCHEDULE="45 6 * * *" - -DB_USER="root" -DB_PASS="" -DB_NAME="opensim" -REGION="sim1" -SESSION_NAME="sim1" -COMPRESS="true" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --backup-schedule) BACKUP_SCHEDULE="$2"; shift 2 ;; - --restart-schedule) RESTART_SCHEDULE="$2"; shift 2 ;; - --check-schedule) CHECK_SCHEDULE="$2"; shift 2 ;; - --report-schedule) REPORT_SCHEDULE="$2"; shift 2 ;; - --smoke-schedule) SMOKE_SCHEDULE="$2"; shift 2 ;; - --db-user) DB_USER="$2"; shift 2 ;; - --db-pass) DB_PASS="$2"; shift 2 ;; - --db-name) DB_NAME="$2"; shift 2 ;; - --region) REGION="$2"; shift 2 ;; - --session) SESSION_NAME="$2"; shift 2 ;; - --compress) COMPRESS="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -need_crontab - -case "$ACTION" in - install|list|remove) ;; - *) die "Unsupported action: $ACTION" ;; -esac - -case "$COMPRESS" in - true|false) ;; - *) die "--compress must be true or false" ;; -esac - -case "$ACTION" in - install) install_cron ;; - list) list_cron ;; - remove) remove_cron ;; -esac +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_cron.sh [--workdir ] --action + [--backup-schedule ""] [--restart-schedule ""] [--check-schedule ""] [--report-schedule ""] [--smoke-schedule ""] + [--db-user ] [--db-pass ] [--db-name ] + [--region ] [--session ] [--compress ] + +Examples: + osmtool_cron.sh --action list + osmtool_cron.sh --action install --backup-schedule "0 3 * * *" --db-user root --db-pass secret --db-name opensim --region sim1 + osmtool_cron.sh --action remove +EOF + print_usage_common +} + +need_crontab() { + need_cmd crontab +} + +quote_sq() { + local s="$1" + s="${s//\'/\'\"\'\"\'}" + printf "'%s'" "$s" +} + +build_backup_cmd() { + local cmd + cmd="bash $ROOT_DIR/osmtool_main.sh --module backup --profile $PROFILE --workdir $WORKDIR --action full-backup --db-user $DB_USER --db-name $DB_NAME --region $REGION --session $SESSION_NAME --compress $COMPRESS" + + if [[ -n "$DB_PASS" ]]; then + cmd+=" --db-pass $DB_PASS" + fi + + printf '%s' "$cmd" +} + +build_restart_cmd() { + printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module startstop --profile $PROFILE --workdir $WORKDIR --target grid --action restart" +} + +build_check_cmd() { + printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module install --profile $PROFILE --workdir $WORKDIR --action server-check" +} + +build_report_cmd() { + local cmd + cmd="bash $ROOT_DIR/osmtool_main.sh --module report --profile $PROFILE --workdir $WORKDIR --action generate --db-user $DB_USER --db-name $DB_NAME" + + if [[ -n "$DB_PASS" ]]; then + cmd+=" --db-pass $DB_PASS" + fi + + printf '%s' "$cmd" +} + +build_smoke_cmd() { + printf '%s' "bash $ROOT_DIR/osmtool_main.sh --module smoke --profile $PROFILE --workdir $WORKDIR --action run" +} + +cron_block_start="# OSMTOOL_CRON_BEGIN" +cron_block_end="# OSMTOOL_CRON_END" + +emit_cron_block() { + local backup_cmd restart_cmd check_cmd report_cmd smoke_cmd + backup_cmd="$(build_backup_cmd)" + restart_cmd="$(build_restart_cmd)" + check_cmd="$(build_check_cmd)" + report_cmd="$(build_report_cmd)" + smoke_cmd="$(build_smoke_cmd)" + + echo "$cron_block_start" + echo "SHELL=/bin/bash" + echo "PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + echo "$BACKUP_SCHEDULE $backup_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" + echo "$RESTART_SCHEDULE $restart_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" + echo "$CHECK_SCHEDULE $check_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" + echo "$REPORT_SCHEDULE $report_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" + echo "$SMOKE_SCHEDULE $smoke_cmd >> $ROOT_DIR/osmtool_backup.log 2>&1" + echo "$cron_block_end" +} + +existing_crontab() { + crontab -l 2>/dev/null || true +} + +strip_osmtool_block() { + awk -v start="$cron_block_start" -v end="$cron_block_end" ' + $0 == start {inblock=1; next} + $0 == end {inblock=0; next} + !inblock {print} + ' +} + +install_cron() { + local current tmp + [[ -n "$DB_USER" && -n "$DB_NAME" ]] || die "install cron requires --db-user and --db-name" + + current="$(existing_crontab)" + tmp="$(mktemp)" + + printf '%s\n' "$current" | strip_osmtool_block > "$tmp" + if [[ -s "$tmp" ]]; then + echo >> "$tmp" + fi + emit_cron_block >> "$tmp" + + crontab "$tmp" + rm -f "$tmp" + log INFO "OSMTool cron jobs installed/updated" +} + +list_cron() { + local current + current="$(existing_crontab)" + + if printf '%s\n' "$current" | grep -q "^$cron_block_start$"; then + printf '%s\n' "$current" | awk -v start="$cron_block_start" -v end="$cron_block_end" ' + $0 == start {inblock=1; print; next} + $0 == end {print; inblock=0; next} + inblock {print} + ' + else + log INFO "No OSMTool cron block configured" + fi +} + +remove_cron() { + local current tmp + current="$(existing_crontab)" + tmp="$(mktemp)" + + printf '%s\n' "$current" | strip_osmtool_block > "$tmp" + crontab "$tmp" + rm -f "$tmp" + log INFO "OSMTool cron block removed" +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" + +BACKUP_SCHEDULE="0 3 * * *" +RESTART_SCHEDULE="0 5 * * 1" +CHECK_SCHEDULE="*/15 * * * *" +REPORT_SCHEDULE="30 6 * * *" +SMOKE_SCHEDULE="45 6 * * *" + +DB_USER="root" +DB_PASS="" +DB_NAME="opensim" +REGION="sim1" +SESSION_NAME="sim1" +COMPRESS="true" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --backup-schedule) BACKUP_SCHEDULE="$2"; shift 2 ;; + --restart-schedule) RESTART_SCHEDULE="$2"; shift 2 ;; + --check-schedule) CHECK_SCHEDULE="$2"; shift 2 ;; + --report-schedule) REPORT_SCHEDULE="$2"; shift 2 ;; + --smoke-schedule) SMOKE_SCHEDULE="$2"; shift 2 ;; + --db-user) DB_USER="$2"; shift 2 ;; + --db-pass) DB_PASS="$2"; shift 2 ;; + --db-name) DB_NAME="$2"; shift 2 ;; + --region) REGION="$2"; shift 2 ;; + --session) SESSION_NAME="$2"; shift 2 ;; + --compress) COMPRESS="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +need_crontab + +case "$ACTION" in + install|list|remove) ;; + *) die "Unsupported action: $ACTION" ;; +esac + +case "$COMPRESS" in + true|false) ;; + *) die "--compress must be true or false" ;; +esac + +case "$ACTION" in + install) install_cron ;; + list) list_cron ;; + remove) remove_cron ;; +esac diff --git a/modular/osmtool_data.sh b/modular/osmtool_data.sh index 030b063..79cca95 100644 --- a/modular/osmtool_data.sh +++ b/modular/osmtool_data.sh @@ -1,170 +1,170 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_data.sh [--workdir ] --action - [--db-user ] [--db-pass ] [--db-name ] - [--region ] [--session ] [--compress ] - -Examples: - osmtool_data.sh --action db-backup --db-user opensim --db-pass secret --db-name robust - osmtool_data.sh --action oar-backup --region sim1 --session sim1 --workdir /opt -EOF - print_usage_common -} - -timestamp() { - date '+%Y%m%d_%H%M%S' -} - -backup_dir() { - printf '%s' "$WORKDIR/backup" -} - -ensure_backup_dir() { - local dir - dir="$(backup_dir)" - - if mkdir -p "$dir" 2>/dev/null; then - return 0 - fi - - sudo mkdir -p "$dir" - sudo chown "$(id -u):$(id -g)" "$dir" -} - -compress_if_enabled() { - local file_path="$1" - - if [[ "$COMPRESS" != "true" ]]; then - printf '%s' "$file_path" - return 0 - fi - - need_cmd gzip - gzip -f "$file_path" - printf '%s.gz' "$file_path" -} - -resolve_default_session() { - if [[ -n "$SESSION_NAME" ]]; then - printf '%s' "$SESSION_NAME" - return 0 - fi - - if [[ -n "$REGION" ]]; then - printf '%s' "$REGION" - return 0 - fi - - printf 'sim1' -} - -screen_session_exists() { - local name="$1" - screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]" -} - -send_to_screen() { - local session_name="$1" - local command_text="$2" - - screen -S "$session_name" -p 0 -X stuff "${command_text}^M" -} - -db_backup_mysql() { - local out - need_cmd mysqldump - [[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-backup(mysql) requires --db-user --db-pass --db-name" - - ensure_backup_dir - out="$(backup_dir)/robust_${DB_NAME}_$(timestamp).sql" - log INFO "Creating MySQL backup: $out" - mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$out" - out="$(compress_if_enabled "$out")" - log INFO "DB backup created: $out" -} - -db_backup() { - db_backup_mysql -} - -oar_backup() { - local session_name out command_text - - [[ -n "$REGION" ]] || die "oar-backup requires --region" - session_name="$(resolve_default_session)" - - ensure_backup_dir - out="$(backup_dir)/${REGION}_$(timestamp).oar" - - if ! screen_session_exists "$session_name"; then - die "Screen session not running: $session_name" - fi - - # OpenSim console command to export current region as OAR. - command_text="save oar $out" - log INFO "Sending OAR export command to screen session '$session_name': $command_text" - send_to_screen "$session_name" "$command_text" - - log INFO "OAR export command sent. Validate completion in the session log/output." -} - -full_backup() { - db_backup - if [[ -n "$REGION" ]]; then - oar_backup - else - log INFO "No --region provided. DB backup only in full-backup mode." - fi -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -DB_USER="" -DB_PASS="" -DB_NAME="" -REGION="" -SESSION_NAME="" -COMPRESS="false" -PROFILE="grid-sim" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --db-user) DB_USER="$2"; shift 2 ;; - --db-pass) DB_PASS="$2"; shift 2 ;; - --db-name) DB_NAME="$2"; shift 2 ;; - --region) REGION="$2"; shift 2 ;; - --session) SESSION_NAME="$2"; shift 2 ;; - --compress) COMPRESS="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed backup "$PROFILE" "$ACTION" - -case "$COMPRESS" in - true|false) ;; - *) die "--compress must be true or false" ;; -esac - -log INFO "Using profile: $PROFILE" - -case "$ACTION" in - db-backup) db_backup ;; - oar-backup) oar_backup ;; - full-backup) full_backup ;; - *) die "Unsupported action: $ACTION" ;; -esac +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_data.sh [--workdir ] --action + [--db-user ] [--db-pass ] [--db-name ] + [--region ] [--session ] [--compress ] + +Examples: + osmtool_data.sh --action db-backup --db-user opensim --db-pass secret --db-name robust + osmtool_data.sh --action oar-backup --region sim1 --session sim1 --workdir /opt +EOF + print_usage_common +} + +timestamp() { + date '+%Y%m%d_%H%M%S' +} + +backup_dir() { + printf '%s' "$WORKDIR/backup" +} + +ensure_backup_dir() { + local dir + dir="$(backup_dir)" + + if mkdir -p "$dir" 2>/dev/null; then + return 0 + fi + + sudo mkdir -p "$dir" + sudo chown "$(id -u):$(id -g)" "$dir" +} + +compress_if_enabled() { + local file_path="$1" + + if [[ "$COMPRESS" != "true" ]]; then + printf '%s' "$file_path" + return 0 + fi + + need_cmd gzip + gzip -f "$file_path" + printf '%s.gz' "$file_path" +} + +resolve_default_session() { + if [[ -n "$SESSION_NAME" ]]; then + printf '%s' "$SESSION_NAME" + return 0 + fi + + if [[ -n "$REGION" ]]; then + printf '%s' "$REGION" + return 0 + fi + + printf 'sim1' +} + +screen_session_exists() { + local name="$1" + screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]" +} + +send_to_screen() { + local session_name="$1" + local command_text="$2" + + screen -S "$session_name" -p 0 -X stuff "${command_text}^M" +} + +db_backup_mysql() { + local out + need_cmd mysqldump + [[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-backup(mysql) requires --db-user --db-pass --db-name" + + ensure_backup_dir + out="$(backup_dir)/robust_${DB_NAME}_$(timestamp).sql" + log INFO "Creating MySQL backup: $out" + mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" > "$out" + out="$(compress_if_enabled "$out")" + log INFO "DB backup created: $out" +} + +db_backup() { + db_backup_mysql +} + +oar_backup() { + local session_name out command_text + + [[ -n "$REGION" ]] || die "oar-backup requires --region" + session_name="$(resolve_default_session)" + + ensure_backup_dir + out="$(backup_dir)/${REGION}_$(timestamp).oar" + + if ! screen_session_exists "$session_name"; then + die "Screen session not running: $session_name" + fi + + # OpenSim console command to export current region as OAR. + command_text="save oar $out" + log INFO "Sending OAR export command to screen session '$session_name': $command_text" + send_to_screen "$session_name" "$command_text" + + log INFO "OAR export command sent. Validate completion in the session log/output." +} + +full_backup() { + db_backup + if [[ -n "$REGION" ]]; then + oar_backup + else + log INFO "No --region provided. DB backup only in full-backup mode." + fi +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +DB_USER="" +DB_PASS="" +DB_NAME="" +REGION="" +SESSION_NAME="" +COMPRESS="false" +PROFILE="grid-sim" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --db-user) DB_USER="$2"; shift 2 ;; + --db-pass) DB_PASS="$2"; shift 2 ;; + --db-name) DB_NAME="$2"; shift 2 ;; + --region) REGION="$2"; shift 2 ;; + --session) SESSION_NAME="$2"; shift 2 ;; + --compress) COMPRESS="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed backup "$PROFILE" "$ACTION" + +case "$COMPRESS" in + true|false) ;; + *) die "--compress must be true or false" ;; +esac + +log INFO "Using profile: $PROFILE" + +case "$ACTION" in + db-backup) db_backup ;; + oar-backup) oar_backup ;; + full-backup) full_backup ;; + *) die "Unsupported action: $ACTION" ;; +esac diff --git a/modular/osmtool_health.sh b/modular/osmtool_health.sh index e1d89ad..dad3fef 100644 --- a/modular/osmtool_health.sh +++ b/modular/osmtool_health.sh @@ -1,268 +1,268 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_health.sh [--workdir ] --action - [--expected-screens ] [--ports ] [--db-user ] [--db-pass ] [--db-name ] - [--log-file ] [--warning-threshold ] - -Examples: - osmtool_health.sh --action run --workdir /opt - osmtool_health.sh --action run --workdir /opt --expected-screens robustserver,sim1 --ports 9000,8002,8088 -EOF - print_usage_common -} - -split_csv() { - local csv="$1" - local token - local IFS=',' - read -r -a _TOKENS <<< "$csv" - for token in "${_TOKENS[@]}"; do - token="${token## }" - token="${token%% }" - [[ -n "$token" ]] && printf '%s\n' "$token" - done -} - -report_ok() { - log INFO "[OK] $1" -} - -report_warn() { - log INFO "[WARN] $1" -} - -report_err() { - log ERROR "[FAIL] $1" -} - -check_screens() { - local fail_count=0 - local screen_name - - if [[ -z "$EXPECTED_SCREENS" ]]; then - report_warn "Screen check skipped (no expected screens configured)" - return 0 - fi - - while IFS= read -r screen_name; do - [[ -n "$screen_name" ]] || continue - if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then - report_ok "Screen session running: $screen_name" - else - report_err "Screen session missing: $screen_name" - fail_count=$((fail_count + 1)) - fi - done < <(split_csv "$EXPECTED_SCREENS") - - return "$fail_count" -} - -check_ports() { - local fail_count=0 - local port - local cmd_ss=0 - - if [[ -z "$PORTS" ]]; then - report_warn "Port check skipped (no ports configured)" - return 0 - fi - - if command -v ss >/dev/null 2>&1; then - cmd_ss=1 - elif ! command -v netstat >/dev/null 2>&1; then - report_warn "Port check skipped (neither ss nor netstat available)" - return 0 - fi - - while IFS= read -r port; do - [[ -n "$port" ]] || continue - if [[ "$cmd_ss" -eq 1 ]]; then - if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then - report_ok "Port listening: $port" - else - report_err "Port not listening: $port" - fail_count=$((fail_count + 1)) - fi - else - if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then - report_ok "Port listening: $port" - else - report_err "Port not listening: $port" - fail_count=$((fail_count + 1)) - fi - fi - done < <(split_csv "$PORTS") - - return "$fail_count" -} - -check_database() { - local fail_count=0 - - if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then - report_warn "Database check skipped (missing --db-user/--db-name)" - return 0 - fi - - if ! command -v mariadb >/dev/null 2>&1; then - report_err "Database check failed: mariadb client missing" - return 1 - fi - - if [[ -n "$DB_PASS" ]]; then - if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then - report_ok "Database reachable: $DB_NAME" - else - report_err "Database not reachable: $DB_NAME" - fail_count=$((fail_count + 1)) - fi - else - if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then - report_ok "Database reachable: $DB_NAME" - else - report_err "Database not reachable: $DB_NAME" - fail_count=$((fail_count + 1)) - fi - fi - - return "$fail_count" -} - -count_log_warnings() { - local file="$1" - grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || true -} - -check_logs() { - local warn_count total=0 - local default_logs=() - - if [[ -n "$LOG_FILE_PATH" ]]; then - default_logs+=("$LOG_FILE_PATH") - else - default_logs+=("$ROOT_DIR/osmtool_backup.log") - default_logs+=("$WORKDIR/robust/bin/OpenSim.log") - fi - - for logf in "${default_logs[@]}"; do - if [[ -f "$logf" ]]; then - warn_count="$(count_log_warnings "$logf")" - report_ok "Log scan: $logf -> $warn_count matches" - total=$((total + warn_count)) - else - report_warn "Log file not found, skipped: $logf" - fi - done - - if [[ "$total" -gt "$WARNING_THRESHOLD" ]]; then - report_err "Log warning threshold exceeded: $total > $WARNING_THRESHOLD" - return 1 - fi - - report_ok "Log warning threshold OK: $total <= $WARNING_THRESHOLD" - return 0 -} - -default_screens_for_profile() { - case "$1" in - grid-sim) echo "robustserver,sim1" ;; - robust) echo "robustserver" ;; - standalone) echo "standalone" ;; - esac -} - -default_ports_for_profile() { - case "$1" in - grid-sim) echo "8002,9000,9001,8088" ;; - robust) echo "8002,9000,9001" ;; - standalone) echo "9000" ;; - esac -} - -run_health() { - local fails=0 - - log INFO "Running health checks for profile: $PROFILE" - log INFO "Using workdir: $WORKDIR" - - if ! check_screens; then - fails=$((fails + 1)) - fi - - if ! check_ports; then - fails=$((fails + 1)) - fi - - if ! check_database; then - fails=$((fails + 1)) - fi - - if ! check_logs; then - fails=$((fails + 1)) - fi - - if [[ "$fails" -eq 0 ]]; then - report_ok "Healthcheck PASSED" - return 0 - fi - - report_err "Healthcheck FAILED with $fails failing check group(s)" - return 1 -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" -EXPECTED_SCREENS="" -PORTS="" -DB_USER="" -DB_PASS="" -DB_NAME="" -LOG_FILE_PATH="" -WARNING_THRESHOLD=50 - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;; - --ports) PORTS="$2"; shift 2 ;; - --db-user) DB_USER="$2"; shift 2 ;; - --db-pass) DB_PASS="$2"; shift 2 ;; - --db-name) DB_NAME="$2"; shift 2 ;; - --log-file) LOG_FILE_PATH="$2"; shift 2 ;; - --warning-threshold) WARNING_THRESHOLD="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed health "$PROFILE" "$ACTION" - -if [[ -z "$EXPECTED_SCREENS" ]]; then - EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")" -elif [[ "$EXPECTED_SCREENS" == "none" ]]; then - EXPECTED_SCREENS="" -fi -if [[ -z "$PORTS" ]]; then - PORTS="$(default_ports_for_profile "$PROFILE")" -elif [[ "$PORTS" == "none" ]]; then - PORTS="" -fi - -case "$ACTION" in - run) run_health ;; - *) die "Unsupported action: $ACTION" ;; -esac +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_health.sh [--workdir ] --action + [--expected-screens ] [--ports ] [--db-user ] [--db-pass ] [--db-name ] + [--log-file ] [--warning-threshold ] + +Examples: + osmtool_health.sh --action run --workdir /opt + osmtool_health.sh --action run --workdir /opt --expected-screens robustserver,sim1 --ports 9000,8002,8088 +EOF + print_usage_common +} + +split_csv() { + local csv="$1" + local token + local IFS=',' + read -r -a _TOKENS <<< "$csv" + for token in "${_TOKENS[@]}"; do + token="${token## }" + token="${token%% }" + [[ -n "$token" ]] && printf '%s\n' "$token" + done +} + +report_ok() { + log INFO "[OK] $1" +} + +report_warn() { + log INFO "[WARN] $1" +} + +report_err() { + log ERROR "[FAIL] $1" +} + +check_screens() { + local fail_count=0 + local screen_name + + if [[ -z "$EXPECTED_SCREENS" ]]; then + report_warn "Screen check skipped (no expected screens configured)" + return 0 + fi + + while IFS= read -r screen_name; do + [[ -n "$screen_name" ]] || continue + if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then + report_ok "Screen session running: $screen_name" + else + report_err "Screen session missing: $screen_name" + fail_count=$((fail_count + 1)) + fi + done < <(split_csv "$EXPECTED_SCREENS") + + return "$fail_count" +} + +check_ports() { + local fail_count=0 + local port + local cmd_ss=0 + + if [[ -z "$PORTS" ]]; then + report_warn "Port check skipped (no ports configured)" + return 0 + fi + + if command -v ss >/dev/null 2>&1; then + cmd_ss=1 + elif ! command -v netstat >/dev/null 2>&1; then + report_warn "Port check skipped (neither ss nor netstat available)" + return 0 + fi + + while IFS= read -r port; do + [[ -n "$port" ]] || continue + if [[ "$cmd_ss" -eq 1 ]]; then + if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then + report_ok "Port listening: $port" + else + report_err "Port not listening: $port" + fail_count=$((fail_count + 1)) + fi + else + if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then + report_ok "Port listening: $port" + else + report_err "Port not listening: $port" + fail_count=$((fail_count + 1)) + fi + fi + done < <(split_csv "$PORTS") + + return "$fail_count" +} + +check_database() { + local fail_count=0 + + if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then + report_warn "Database check skipped (missing --db-user/--db-name)" + return 0 + fi + + if ! command -v mariadb >/dev/null 2>&1; then + report_err "Database check failed: mariadb client missing" + return 1 + fi + + if [[ -n "$DB_PASS" ]]; then + if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then + report_ok "Database reachable: $DB_NAME" + else + report_err "Database not reachable: $DB_NAME" + fail_count=$((fail_count + 1)) + fi + else + if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then + report_ok "Database reachable: $DB_NAME" + else + report_err "Database not reachable: $DB_NAME" + fail_count=$((fail_count + 1)) + fi + fi + + return "$fail_count" +} + +count_log_warnings() { + local file="$1" + grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || true +} + +check_logs() { + local warn_count total=0 + local default_logs=() + + if [[ -n "$LOG_FILE_PATH" ]]; then + default_logs+=("$LOG_FILE_PATH") + else + default_logs+=("$ROOT_DIR/osmtool_backup.log") + default_logs+=("$WORKDIR/robust/bin/OpenSim.log") + fi + + for logf in "${default_logs[@]}"; do + if [[ -f "$logf" ]]; then + warn_count="$(count_log_warnings "$logf")" + report_ok "Log scan: $logf -> $warn_count matches" + total=$((total + warn_count)) + else + report_warn "Log file not found, skipped: $logf" + fi + done + + if [[ "$total" -gt "$WARNING_THRESHOLD" ]]; then + report_err "Log warning threshold exceeded: $total > $WARNING_THRESHOLD" + return 1 + fi + + report_ok "Log warning threshold OK: $total <= $WARNING_THRESHOLD" + return 0 +} + +default_screens_for_profile() { + case "$1" in + grid-sim) echo "robustserver,sim1" ;; + robust) echo "robustserver" ;; + standalone) echo "standalone" ;; + esac +} + +default_ports_for_profile() { + case "$1" in + grid-sim) echo "8002,9000,9001,8088" ;; + robust) echo "8002,9000,9001" ;; + standalone) echo "9000" ;; + esac +} + +run_health() { + local fails=0 + + log INFO "Running health checks for profile: $PROFILE" + log INFO "Using workdir: $WORKDIR" + + if ! check_screens; then + fails=$((fails + 1)) + fi + + if ! check_ports; then + fails=$((fails + 1)) + fi + + if ! check_database; then + fails=$((fails + 1)) + fi + + if ! check_logs; then + fails=$((fails + 1)) + fi + + if [[ "$fails" -eq 0 ]]; then + report_ok "Healthcheck PASSED" + return 0 + fi + + report_err "Healthcheck FAILED with $fails failing check group(s)" + return 1 +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" +EXPECTED_SCREENS="" +PORTS="" +DB_USER="" +DB_PASS="" +DB_NAME="" +LOG_FILE_PATH="" +WARNING_THRESHOLD=50 + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;; + --ports) PORTS="$2"; shift 2 ;; + --db-user) DB_USER="$2"; shift 2 ;; + --db-pass) DB_PASS="$2"; shift 2 ;; + --db-name) DB_NAME="$2"; shift 2 ;; + --log-file) LOG_FILE_PATH="$2"; shift 2 ;; + --warning-threshold) WARNING_THRESHOLD="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed health "$PROFILE" "$ACTION" + +if [[ -z "$EXPECTED_SCREENS" ]]; then + EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")" +elif [[ "$EXPECTED_SCREENS" == "none" ]]; then + EXPECTED_SCREENS="" +fi +if [[ -z "$PORTS" ]]; then + PORTS="$(default_ports_for_profile "$PROFILE")" +elif [[ "$PORTS" == "none" ]]; then + PORTS="" +fi + +case "$ACTION" in + run) run_health ;; + *) die "Unsupported action: $ACTION" ;; +esac diff --git a/modular/osmtool_install.sh b/modular/osmtool_install.sh index fa0e411..bc0819f 100644 --- a/modular/osmtool_install.sh +++ b/modular/osmtool_install.sh @@ -1,1191 +1,1191 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_install.sh [--workdir ] --action - [--opensim-dir ] [--opensim-repo ] [--opensim-branch ] [--repo-mode ] - [--tsassets-dir ] [--currency-dir ] [--data-backup-dir ] - [--deploy-binaries ] [--legacy-patch-dir ] - [--db-root-user ] [--db-root-pass ] [--db-user ] [--db-pass ] - [--janus-prefix ] [--janus-src ] [--public-host ] [--http-port ] - [--admin-port ] [--rtp-range ] [--enable-admin ] - [--api-secret ] [--admin-secret ] - -Actions: - init-config Create/update shared osmtool configuration interactively - server-check Validate server readiness and required dependencies - prepare-ubuntu Basic apt update/upgrade and base packages - install-opensim-deps Install OpenSim runtime dependencies - install-dotnet8 Install .NET SDK 8.0 for OpenSim build/runtime - install-opensim Clone/update, enrich, build and optionally deploy OpenSim - configure-opensim Generate required runtime ini files from example templates - configure-database Create MariaDB databases/users/grants for robust and sim* runtimes - compile-janus Build and install Janus Gateway - configure-janus Configure Janus for OpenSim usage - install-janus Compile + configure Janus in one run - -Examples: - osmtool_install.sh --action server-check --workdir /opt - osmtool_install.sh --action configure-opensim --profile grid-sim --workdir /opt - osmtool_install.sh --action configure-database --workdir /opt --db-user opensim --db-pass secret -EOF - print_usage_common -} - -has_dotnet8_sdk() { - if ! command -v dotnet >/dev/null 2>&1; then - return 1 - fi - - dotnet --list-sdks 2>/dev/null | awk '{print $1}' | grep -Eq '^8\.' -} - -package_available_in_apt() { - local pkg="$1" - apt-cache show "$pkg" >/dev/null 2>&1 -} - -resolve_package_token() { - local token="$1" - local candidate - local IFS='|' - read -r -a candidates <<< "$token" - - for candidate in "${candidates[@]}"; do - if dpkg -s "$candidate" >/dev/null 2>&1; then - echo "$candidate" - return 0 - fi - done - - for candidate in "${candidates[@]}"; do - if package_available_in_apt "$candidate"; then - echo "$candidate" - return 0 - fi - done - - return 1 -} - -ensure_user_writable_dir() { - local dir="$1" - - if mkdir -p "$dir" 2>/dev/null; then - return 0 - fi - - sudo mkdir -p "$dir" - sudo chown "$(id -u):$(id -g)" "$dir" -} - -ensure_user_owns_path() { - local path="$1" - - if [[ -e "$path" && ! -w "$path" ]]; then - sudo chown -R "$(id -u):$(id -g)" "$path" - fi -} - -sync_git_repo() { - local repo_url="$1" - local repo_dir="$2" - local branch="$3" - local repo_mode="$4" - local parent_dir - local active_branch - - parent_dir="$(dirname "$repo_dir")" - if [[ ! -d "$parent_dir" ]]; then - ensure_user_writable_dir "$parent_dir" - fi - - if [[ "$repo_mode" == "fresh" && -e "$repo_dir" ]]; then - log INFO "Removing existing repository for fresh checkout: $repo_dir" - rm -rf "$repo_dir" 2>/dev/null || sudo rm -rf "$repo_dir" - fi - - if [[ -d "$repo_dir/.git" ]]; then - ensure_user_owns_path "$repo_dir" - log INFO "Updating repository: $repo_dir" - git -C "$repo_dir" fetch --all --prune - active_branch="$branch" - if [[ -z "$active_branch" ]]; then - active_branch="$(git -C "$repo_dir" branch --show-current)" - fi - if [[ -z "$active_branch" ]]; then - active_branch="$(git -C "$repo_dir" symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')" - fi - if [[ -n "$active_branch" ]]; then - git -C "$repo_dir" checkout "$active_branch" - git -C "$repo_dir" pull --ff-only origin "$active_branch" - else - git -C "$repo_dir" pull --ff-only - fi - return 0 - fi - - if [[ -d "$repo_dir" && -z "$(ls -A "$repo_dir" 2>/dev/null)" ]]; then - rmdir "$repo_dir" 2>/dev/null || sudo rmdir "$repo_dir" - fi - - if [[ -e "$repo_dir" ]]; then - die "Path exists but is not a git repository: $repo_dir" - fi - - if [[ ! -w "$parent_dir" ]]; then - sudo mkdir -p "$repo_dir" - sudo chown "$(id -u):$(id -g)" "$repo_dir" - fi - - log INFO "Cloning repository $repo_url -> $repo_dir" - if [[ -n "$branch" ]]; then - git clone --branch "$branch" --single-branch "$repo_url" "$repo_dir" - else - git clone "$repo_url" "$repo_dir" - fi -} - -sync_support_repo() { - local repo_name="$1" - local repo_url="$2" - local repo_dir="$3" - - log INFO "Preparing support repository: $repo_name" - sync_git_repo "$repo_url" "$repo_dir" "" "$REPO_MODE" -} - -copy_tree_contents() { - local src_dir="$1" - local dst_dir="$2" - local label="$3" - - if [[ ! -d "$src_dir" ]]; then - log INFO "Skipping missing source for $label: $src_dir" - return 0 - fi - - mkdir -p "$dst_dir" - # Exclude .git to avoid permission issues on repeated runs - if command -v rsync >/dev/null 2>&1; then - rsync -a --exclude='.git' "$src_dir/" "$dst_dir/" - else - find "$src_dir" -maxdepth 1 -mindepth 1 ! -name '.git' \ - -exec cp -a {} "$dst_dir/" \; - fi - log INFO "Copied $label: $src_dir -> $dst_dir" -} - -apply_legacy_patches() { - local patch_dir="$1" - local patch_file - - [[ -n "$patch_dir" ]] || return 0 - - if [[ ! -d "$patch_dir" ]]; then - die "Legacy patch directory not found: $patch_dir" - fi - - shopt -s nullglob - local patches=("$patch_dir"/*.patch) - shopt -u nullglob - - if [[ ${#patches[@]} -eq 0 ]]; then - log INFO "No legacy patches found in $patch_dir" - return 0 - fi - - for patch_file in "${patches[@]}"; do - if git -C "$OPENSIM_DIR" apply --reverse --check "$patch_file" >/dev/null 2>&1; then - log INFO "Legacy patch already applied: $(basename "$patch_file")" - continue - fi - - log INFO "Applying legacy patch: $(basename "$patch_file")" - if ! git -C "$OPENSIM_DIR" apply "$patch_file"; then - git -C "$OPENSIM_DIR" apply --ignore-space-change --ignore-whitespace "$patch_file" \ - || die "Failed to apply legacy patch: $patch_file" - fi - done -} - -deploy_opensim_binaries() { - local src_bin="$OPENSIM_DIR/bin" - local deployed=0 - local sim_dir - - [[ -d "$src_bin" ]] || die "OpenSim build output missing: $src_bin" - - if [[ -d "$WORKDIR/robust/bin" ]]; then - copy_tree_contents "$src_bin" "$WORKDIR/robust/bin" "robust binaries" - deployed=1 - fi - - if [[ -d "$WORKDIR/standalone/bin" ]]; then - copy_tree_contents "$src_bin" "$WORKDIR/standalone/bin" "standalone binaries" - deployed=1 - fi - - shopt -s nullglob - for sim_dir in "$WORKDIR"/sim*; do - if [[ -d "$sim_dir/bin" ]]; then - copy_tree_contents "$src_bin" "$sim_dir/bin" "region binaries" - deployed=1 - fi - done - shopt -u nullglob - - if [[ "$deployed" -eq 0 ]]; then - log INFO "No target runtime directories found for binary deployment under $WORKDIR" - else - log INFO "OpenSim binaries deployed to available runtime directories" - fi -} - -install_dotnet8() { - need_cmd apt-get - need_cmd sudo - need_cmd wget - - if has_dotnet8_sdk; then - log INFO "dotnet SDK 8.x already installed" - return 0 - fi - - log INFO "Installing .NET SDK 8.0" - sudo apt-get update - sudo apt-get install -y apt-transport-https ca-certificates gnupg - - if ! apt-cache policy dotnet-sdk-8.0 | grep -q "Candidate:"; then - local version_id pkg_url pkg_file - version_id="$(awk -F= '/^VERSION_ID=/{gsub(/\"/,"",$2); print $2; exit}' /etc/os-release 2>/dev/null || true)" - [[ -n "$version_id" ]] || die "Could not detect VERSION_ID from /etc/os-release" - pkg_url="https://packages.microsoft.com/config/ubuntu/${version_id}/packages-microsoft-prod.deb" - pkg_file="/tmp/packages-microsoft-prod.deb" - - log INFO "Adding Microsoft package repository for Ubuntu ${version_id}" - wget -q -O "$pkg_file" "$pkg_url" - sudo dpkg -i "$pkg_file" - rm -f "$pkg_file" - sudo apt-get update - fi - - sudo apt-get install -y dotnet-sdk-8.0 - - if has_dotnet8_sdk; then - log INFO "dotnet SDK 8.x installed successfully" - return 0 - fi - - die "dotnet SDK 8.x installation failed" -} - -install_opensim_deps() { - local tokens=( - git zip screen libgdiplus zlib1g libunwind8 libgssapi-krb5-2 libstdc++6 - "mariadb-client|default-mysql-client|mysql-client" - "mariadb-server|mysql-server" - "libgcc-s1|libgcc1" - "libssl3|libssl1.1" - "libicu74|libicu72|libicu71|libicu70|libicu67" - "liblttng-ust1|liblttng-ust0" - ) - local to_install=() - local token resolved - - need_cmd apt-get - need_cmd sudo - - for token in "${tokens[@]}"; do - if resolve_package_token "$token" >/dev/null 2>&1; then - resolved="$(resolve_package_token "$token")" - if ! dpkg -s "$resolved" >/dev/null 2>&1; then - to_install+=("$resolved") - fi - else - die "No installable package found for token: $token" - fi - done - - if [[ ${#to_install[@]} -eq 0 ]]; then - log INFO "OpenSim runtime dependencies already installed" - return 0 - fi - - log INFO "Installing OpenSim dependencies: ${to_install[*]}" - sudo apt-get update - sudo apt-get install -y "${to_install[@]}" -} - -ensure_mariadb_service() { - need_cmd sudo - - if ! command -v mariadb >/dev/null 2>&1; then - die "MariaDB client not found after dependency install" - fi - - if command -v systemctl >/dev/null 2>&1; then - if systemctl list-unit-files 2>/dev/null | grep -q '^mariadb\.service'; then - log INFO "Ensuring mariadb.service is enabled and running" - sudo systemctl enable --now mariadb - if ! systemctl is-active --quiet mariadb; then - die "MariaDB service could not be started" - fi - return 0 - fi - fi - - if command -v service >/dev/null 2>&1; then - if service --status-all 2>/dev/null | grep -q mariadb; then - log INFO "Ensuring MariaDB service is running" - sudo service mariadb start - return 0 - fi - fi - - log INFO "No controllable MariaDB service unit detected; skipping service activation" -} - -copy_ini_if_missing() { - local bin_dir="$1" - local src_name="$2" - local dst_name="$3" - local src dst - - src="$bin_dir/$src_name" - dst="$bin_dir/$dst_name" - - [[ -d "$bin_dir" ]] || return 0 - - if [[ -f "$dst" ]]; then - log INFO "Keeping existing config: $dst" - return 0 - fi - - if [[ -f "$src" ]]; then - cp -a "$src" "$dst" - log INFO "Created config from template: $dst" - else - log INFO "Template not found, skipping: $src" - fi -} - -copy_example_if_missing() { - local bin_dir="$1" - local base_name="$2" - copy_ini_if_missing "$bin_dir" "${base_name}.example" "$base_name" -} - -set_ini_key_value() { - local file="$1" - local key="$2" - local value="$3" - local escaped - - [[ -f "$file" ]] || return 0 - escaped="${value//\\/\\\\}" - escaped="${escaped//&/\\&}" - sed -i -E "s|^([[:space:]]*${key}[[:space:]]*=[[:space:]]*).*$|\\1\"${escaped}\"|" "$file" -} - -set_architecture_include() { - local file="$1" - local include_value="$2" - - [[ -f "$file" ]] || return 0 - - if grep -qE '^[[:space:]]*Include-Architecture[[:space:]]*=' "$file"; then - sed -i -E "s|^([[:space:]]*Include-Architecture[[:space:]]*=[[:space:]]*).*$|\\1\"${include_value}\"|" "$file" - else - { - echo "" - echo "[Architecture]" - echo "Include-Architecture = \"${include_value}\"" - } >> "$file" - fi -} - -read_userinfo_credential() { - local file="$1" - local key="$2" - - [[ -f "$file" ]] || return 1 - awk -F '=' -v key="$key" ' - $1 ~ "^[[:space:]]*" key "[[:space:]]*$" { - sub(/^[[:space:]]+/, "", $2) - sub(/[[:space:]]+$/, "", $2) - print $2 - exit - } - ' "$file" -} - -configure_opensim_runtime() { - local sim_dir cfg_user cfg_pass userinfo_file sim_arch - - log INFO "Configuring OpenSim runtime ini files" - - copy_ini_if_missing "$WORKDIR/robust/bin" "Robust.HG.ini.example" "Robust.ini" - copy_ini_if_missing "$WORKDIR/robust/bin" "Robust.ini.example" "Robust.ini" - copy_ini_if_missing "$WORKDIR/robust/bin" "MoneyServer.ini.example" "MoneyServer.ini" - copy_example_if_missing "$WORKDIR/robust/bin/config-include" "GridCommon.ini" - copy_example_if_missing "$WORKDIR/robust/bin/config-include" "osslEnable.ini" - - copy_ini_if_missing "$WORKDIR/standalone/bin" "OpenSim.ini.example" "OpenSim.ini" - copy_example_if_missing "$WORKDIR/standalone/bin/config-include" "StandaloneCommon.ini" - copy_example_if_missing "$WORKDIR/standalone/bin/config-include" "osslEnable.ini" - - sim_arch="config-include/Grid.ini" - if [[ "$PROFILE" == "standalone" ]]; then - sim_arch="config-include/Standalone.ini" - fi - - shopt -s nullglob - for sim_dir in "$WORKDIR"/sim*/bin; do - copy_ini_if_missing "$sim_dir" "OpenSim.ini.example" "OpenSim.ini" - copy_example_if_missing "$sim_dir/config-include" "GridCommon.ini" - copy_example_if_missing "$sim_dir/config-include" "osslEnable.ini" - set_architecture_include "$sim_dir/OpenSim.ini" "$sim_arch" - done - shopt -u nullglob - - cfg_user="$DB_USER" - cfg_pass="$DB_PASS" - userinfo_file="$WORKDIR/UserInfo.ini" - - if [[ -z "$cfg_user" ]]; then - cfg_user="$(read_userinfo_credential "$userinfo_file" "DB_Benutzername" || true)" - fi - if [[ -z "$cfg_pass" ]]; then - cfg_pass="$(read_userinfo_credential "$userinfo_file" "DB_Passwort" || true)" - fi - - if [[ -n "$cfg_user" && -n "$cfg_pass" ]]; then - local db_conn_robust db_conn_sim sim_name_inner - - # MoneyServer Credentials - set_ini_key_value "$WORKDIR/robust/bin/MoneyServer.ini" "username" "$cfg_user" - set_ini_key_value "$WORKDIR/robust/bin/MoneyServer.ini" "password" "$cfg_pass" - - # Robust.ini ConnectionString (zwingend erforderlich für Datenbankverbindung) - db_conn_robust="Data Source=localhost;Database=robust;User ID=${cfg_user};Password=${cfg_pass};Old Guids=true;" - if [[ -f "$WORKDIR/robust/bin/Robust.ini" ]]; then - upsert_key "$WORKDIR/robust/bin/Robust.ini" "ConnectionString" "\"${db_conn_robust}\"" - fi - - # Jede simX/bin/OpenSim.ini ConnectionString (zwingend, sonst startet sim nicht) - shopt -s nullglob - for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do - sim_name_inner="$(basename "$(dirname "$sim_dir")")" - [[ "$sim_name_inner" =~ ^sim[0-9]+$ ]] || continue - [[ -f "$sim_dir/OpenSim.ini" ]] || continue - db_conn_sim="Data Source=localhost;Database=${sim_name_inner};User ID=${cfg_user};Password=${cfg_pass};Old Guids=true;" - upsert_key "$sim_dir/OpenSim.ini" "ConnectionString" "\"${db_conn_sim}\"" - done - shopt -u nullglob - - log INFO "Updated ConnectionStrings in Robust.ini, MoneyServer.ini und simX/OpenSim.ini" - else - log INFO "Keine DB-Credentials verfügbar — ConnectionString nicht gesetzt. Erst configure-database ausführen." - fi - - # Hostname/IP in alle Konfigurationsdateien einsetzen (YOURHOST ersetzen) - if [[ -n "$PUBLIC_HOST" && "$PUBLIC_HOST" != "127.0.0.1" ]]; then - local h_escaped - h_escaped="$(printf '%s' "$PUBLIC_HOST" | sed 's/[\/&]/\\&/g')" - local cfg_f - for cfg_f in \ - "$WORKDIR/robust/bin/Robust.ini" \ - "$WORKDIR/robust/bin/config-include/GridCommon.ini" \ - "$WORKDIR/standalone/bin/config-include/StandaloneCommon.ini"; do - [[ -f "$cfg_f" ]] || continue - sed -i "s|YOURHOST|${h_escaped}|g" "$cfg_f" - done - shopt -s nullglob - for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do - for cfg_f in "$sim_dir/OpenSim.ini" "$sim_dir/config-include/GridCommon.ini"; do - [[ -f "$cfg_f" ]] || continue - sed -i "s|YOURHOST|${h_escaped}|g" "$cfg_f" - done - done - shopt -u nullglob - log INFO "Hostname ($PUBLIC_HOST) in Konfigurationsdateien eingesetzt" - fi - - # Gridname in Konfigurationsdateien setzen - if [[ -n "$GRIDNAME" ]]; then - local cfg_f - for cfg_f in \ - "$WORKDIR/robust/bin/Robust.ini" \ - "$WORKDIR/robust/bin/config-include/GridCommon.ini" \ - "$WORKDIR/standalone/bin/config-include/StandaloneCommon.ini"; do - [[ -f "$cfg_f" ]] || continue - upsert_key "$cfg_f" "GridName" "\"${GRIDNAME}\"" - upsert_key "$cfg_f" "WelcomeMessage" "\"Willkommen bei ${GRIDNAME}\"" - done - log INFO "Gridname ($GRIDNAME) in Konfigurationsdateien gesetzt" - fi - - log INFO "OpenSim runtime ini Konfiguration abgeschlossen" -} - -sql_escape() { - local s="$1" - s="${s//\\/\\\\}" - s="${s//\'/\'\'}" - printf '%s' "$s" -} - -run_mariadb_sql() { - local sql="$1" - - if [[ -n "$DB_ROOT_PASS" ]]; then - mariadb -u"$DB_ROOT_USER" -p"$DB_ROOT_PASS" -e "$sql" - else - mariadb -u"$DB_ROOT_USER" -e "$sql" - fi -} - -discover_sim_databases() { - local sim_bin sim_name - local sim_dbs=() - - shopt -s nullglob - for sim_bin in "$WORKDIR"/sim*/bin; do - sim_name="$(basename "$(dirname "$sim_bin")")" - sim_dbs+=("$sim_name") - done - shopt -u nullglob - - printf '%s\n' "${sim_dbs[@]}" -} - -write_db_credentials_file() { - local file="$WORKDIR/UserInfo.ini" - - mkdir -p "$WORKDIR" 2>/dev/null || sudo mkdir -p "$WORKDIR" - if [[ ! -f "$file" ]]; then - : > "$file" 2>/dev/null || sudo touch "$file" - fi - - { - echo "[DatabaseData]" - echo "DB_Benutzername = $DB_USER" - echo "DB_Passwort = $DB_PASS" - } | sudo tee "$file" >/dev/null - - log INFO "Database credentials written: $file" -} - -configure_database() { - local escaped_user escaped_pass db_name - local db_ident - local sim_db_list - - need_cmd mariadb - need_cmd sudo - ensure_mariadb_service - - [[ -n "$DB_USER" ]] || die "--db-user is required for configure-database" - [[ -n "$DB_PASS" ]] || die "--db-pass is required for configure-database" - - escaped_user="$(sql_escape "$DB_USER")" - escaped_pass="$(sql_escape "$DB_PASS")" - - if ! run_mariadb_sql "SELECT 1" >/dev/null 2>&1; then - die "Cannot connect to MariaDB as '$DB_ROOT_USER'. Check --db-root-user/--db-root-pass and server state." - fi - - log INFO "Configuring MariaDB databases and grants" - - if [[ -d "$WORKDIR/robust" ]]; then - run_mariadb_sql "CREATE DATABASE IF NOT EXISTS robust CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" - log INFO "Ensured database: robust" - fi - - # Sim-Datenbanken: bei --sim-count N explizit, sonst Verzeichnisse ermitteln - local sim_db_list="" - if [[ "$SIM_COUNT" -gt 0 ]]; then - sim_db_list="$(for ((i=1; i<=SIM_COUNT; i++)); do echo "sim${i}"; done)" - log INFO "--sim-count $SIM_COUNT: erstelle Datenbanken sim1..sim${SIM_COUNT}" - else - sim_db_list="$(discover_sim_databases)" - if [[ -z "$sim_db_list" ]]; then - log INFO "Keine sim*-Verzeichnisse unter $WORKDIR gefunden — sim-Datenbanken übersprungen. Mit --sim-count N erzwingen." - fi - fi - - if [[ -n "$sim_db_list" ]]; then - while IFS= read -r db_name; do - [[ -n "$db_name" ]] || continue - local db_ident="\`$db_name\`" - run_mariadb_sql "CREATE DATABASE IF NOT EXISTS $db_ident CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" - log INFO "Datenbank sichergestellt: $db_name" - done <<< "$sim_db_list" - fi - - run_mariadb_sql "CREATE USER IF NOT EXISTS '$escaped_user'@'localhost' IDENTIFIED BY '$escaped_pass';" - run_mariadb_sql "ALTER USER '$escaped_user'@'localhost' IDENTIFIED BY '$escaped_pass';" - - if [[ -d "$WORKDIR/robust" ]]; then - run_mariadb_sql "GRANT ALL PRIVILEGES ON robust.* TO '$escaped_user'@'localhost';" - fi - - if [[ -n "$sim_db_list" ]]; then - while IFS= read -r db_name; do - [[ -n "$db_name" ]] || continue - local db_ident="\`$db_name\`" - run_mariadb_sql "GRANT ALL PRIVILEGES ON $db_ident.* TO '$escaped_user'@'localhost';" - done <<< "$sim_db_list" - fi - - run_mariadb_sql "FLUSH PRIVILEGES;" - - write_db_credentials_file - log INFO "MariaDB Datenbank-Setup abgeschlossen" -} - -server_check() { - local fail=0 - local os_id="" - local free_kb="0" - local missing_pkgs=() - local required_janus_pkgs=( - build-essential cmake git pkg-config automake libtool gengetopt - libmicrohttpd-dev libjansson-dev libssl-dev libsofia-sip-ua-dev libglib2.0-dev - libopus-dev libogg-dev libcurl4-openssl-dev liblua5.3-dev libconfig-dev - libwebsockets-dev libsrtp2-dev libnice-dev libsqlite3-dev - ) - local required_opensim_tokens=( - git zip screen libgdiplus zlib1g libunwind8 libgssapi-krb5-2 libstdc++6 - "mariadb-client|default-mysql-client|mysql-client" - "mariadb-server|mysql-server" - "libgcc-s1|libgcc1" - "libssl3|libssl1.1" - "libicu74|libicu72|libicu71|libicu70|libicu67" - "liblttng-ust1|liblttng-ust0" - ) - local pkg token - - log INFO "Running server readiness check" - - if [[ -f /etc/os-release ]]; then - os_id="$(awk -F= '/^ID=/{gsub(/\"/,"",$2); print $2; exit}' /etc/os-release 2>/dev/null || true)" - [[ -n "$os_id" ]] || os_id="unknown" - local os_pretty - os_pretty="$(awk -F= '/^PRETTY_NAME=/{gsub(/\"/,"",$2); print $2; exit}' /etc/os-release 2>/dev/null || true)" - [[ -n "$os_pretty" ]] || os_pretty="unknown" - log INFO "Detected OS: $os_pretty" - fi - - if [[ "$os_id" != "ubuntu" && "$os_id" != "debian" ]]; then - log ERROR "Unsupported OS for this automation: $os_id" - fail=1 - fi - - if command -v sudo >/dev/null 2>&1; then - if sudo -n true >/dev/null 2>&1; then - log INFO "sudo non-interactive check: OK" - else - log INFO "sudo available but password will be required" - fi - else - log ERROR "sudo not found" - fail=1 - fi - - if command -v apt-get >/dev/null 2>&1; then - log INFO "apt-get available" - else - log ERROR "apt-get missing" - fail=1 - fi - - if command -v curl >/dev/null 2>&1; then - if curl -Is https://github.com >/dev/null 2>&1; then - log INFO "Network check to github.com: OK" - else - log ERROR "Network check to github.com failed" - fail=1 - fi - else - log ERROR "curl missing" - fail=1 - fi - - free_kb="$(df -Pk /opt | awk 'NR==2 {print $4}')" - if [[ -n "$free_kb" && "$free_kb" -gt 2097152 ]]; then - log INFO "Disk space in /opt is sufficient" - else - log ERROR "Low disk space in /opt (need at least 2GB free)" - fail=1 - fi - - for pkg in "${required_janus_pkgs[@]}"; do - if ! dpkg -s "$pkg" >/dev/null 2>&1; then - missing_pkgs+=("$pkg") - fi - done - - for token in "${required_opensim_tokens[@]}"; do - if ! resolve_package_token "$token" >/dev/null 2>&1; then - missing_pkgs+=("$token") - fi - done - - if [[ ${#missing_pkgs[@]} -eq 0 ]]; then - log INFO "All required Janus/OpenSim dependency packages are installed" - else - log ERROR "Missing packages: ${missing_pkgs[*]}" - log INFO "Run: sudo apt-get update && sudo apt-get install -y ${missing_pkgs[*]}" - fail=1 - fi - - if has_dotnet8_sdk; then - log INFO "dotnet SDK 8.x found" - else - log ERROR "dotnet SDK 8.x missing (required for OpenSim build/runtime)" - fail=1 - fi - - if command -v mysqldump >/dev/null 2>&1; then - log INFO "mysqldump found (MariaDB backup tooling ready)" - else - log ERROR "mysqldump missing (MariaDB client tools are required)" - fail=1 - fi - - if [[ "$fail" -eq 0 ]]; then - log INFO "Server readiness check PASSED" - return 0 - fi - - die "Server readiness check FAILED" -} - -upsert_key() { - local file="$1" - local key="$2" - local value="$3" - - if grep -Eq "^[[:space:]]*;?[[:space:]]*${key}[[:space:]]*=" "$file"; then - sudo sed -i -E "s|^[[:space:]]*;?[[:space:]]*(${key})[[:space:]]*=.*|\1 = $value|" "$file" - else - echo "$key = $value" | sudo tee -a "$file" >/dev/null - fi -} - -generate_alnum_token() { - local length="${1:-32}" - if command -v openssl >/dev/null 2>&1; then - openssl rand -hex "$((length / 2))" | cut -c1-"$length" - return - fi - tr -dc 'A-Za-z0-9' /dev/null || sudo mkdir -p "$WORKDIR" - - # Vollstaendiges OpenSim/Robust-Snippet (entspricht config-janus-linux.sh) - cat </dev/null -; ========================================================== -; OpenSim WebRTC/Janus Config (generiert von osmtool) -; ========================================================== - -; ---------------------------- -; OpenSim.ini [WebRtcVoice] -; ---------------------------- -[WebRtcVoice] - Enabled = true - SpatialVoiceService = WebRtcVoice.dll:WebRtcVoiceServiceConnector - NonSpatialVoiceService = WebRtcVoice.dll:WebRtcVoiceServiceConnector - WebRtcVoiceServerURI = http://$PUBLIC_HOST:8003 - -; ---------------------------- -; Robust.ini [ServiceList] + [WebRtcVoice] + [JanusWebRtcVoice] -; ---------------------------- -[ServiceList] - VoiceServiceConnector = "8000/OpenSim.Server.Handlers.dll:OpenSim.Server.Handlers.WebRtcVoiceServerConnector" - -[WebRtcVoice] - Enabled = true - NonSpatialVoiceService = WebRtcJanusService.dll:WebRtcJanusService - -[JanusWebRtcVoice] - JanusGatewayURI = http://$PUBLIC_HOST:$HTTP_PORT/janus - APIToken = $api_secret -EOF - - if [[ "$ENABLE_ADMIN" == "true" ]]; then - cat </dev/null - JanusGatewayAdminURI = http://$PUBLIC_HOST:$ADMIN_PORT/admin - AdminAPIToken = $admin_secret -EOF - fi - - cat <<'EOF' | sudo tee -a "$snippet_file" >/dev/null - MessageDetails = false -EOF - - # Secrets sichern (analog janus_instal.sh) - { - echo "JANUS_API_SECRET=$api_secret" - [[ -n "$admin_secret" ]] && echo "JANUS_ADMIN_SECRET=$admin_secret" - echo "JANUS_HTTP_PORT=$HTTP_PORT" - echo "JANUS_PUBLIC_HOST=$PUBLIC_HOST" - } > "$secrets_file" - chmod 600 "$secrets_file" - log INFO "Janus Secrets gespeichert: $secrets_file (chmod 600)" - - cat </dev/null -JANUS_PREFIX=$JANUS_PREFIX -HTTP_PORT=$HTTP_PORT -ADMIN_PORT=$ADMIN_PORT -ENABLE_ADMIN=$ENABLE_ADMIN -RTP_RANGE=$RTP_RANGE -PUBLIC_HOST=$PUBLIC_HOST -EOF - - log INFO "Janus konfiguriert. Snippet: $snippet_file — Marker: $JANUS_PREFIX/.osmtool_janus_ready" - log INFO "Firewall oeffnen: TCP $HTTP_PORT, UDP ${RTP_RANGE%%-*}-${RTP_RANGE##*-}" - log INFO "Janus neu starten: sudo systemctl restart janus" - log INFO "Snippet-Inhalt in OpenSim.ini und Robust.ini uebernehmen." -} - -prepare_ubuntu() { - need_cmd apt-get - log INFO "Preparing Ubuntu server" - sudo apt-get update - sudo apt-get -y upgrade - sudo apt-get -y install curl git screen unzip jq wget - log INFO "Ubuntu base packages installed" -} - -install_opensim() { - need_cmd git - need_cmd dotnet - need_cmd bash - - log INFO "Starting OpenSim install/build flow" - log INFO "OpenSim repository: $OPENSIM_REPO" - log INFO "OpenSim branch: $OPENSIM_BRANCH" - log INFO "OpenSim directory: $OPENSIM_DIR" - - sync_git_repo "$OPENSIM_REPO" "$OPENSIM_DIR" "$OPENSIM_BRANCH" "$REPO_MODE" - ensure_user_owns_path "$OPENSIM_DIR" - - # Patch-Dateien nur mit Bestaetigung einspielen - if [[ -n "$LEGACY_PATCH_DIR" ]]; then - if confirm_addon "Patch-Dateien" "Verzeichnis: $LEGACY_PATCH_DIR"; then - apply_legacy_patches "$LEGACY_PATCH_DIR" - fi - fi - - # opensim-tsassets (Texturen/Assets) - if confirm_addon "opensim-tsassets" "$TSASSETS_REPO"; then - sync_support_repo "opensim-tsassets" "$TSASSETS_REPO" "$TSASSETS_DIR" - copy_tree_contents "$TSASSETS_DIR/bin" "$OPENSIM_DIR/bin" "tsassets bin content" - copy_tree_contents "$TSASSETS_DIR/OpenSim" "$OPENSIM_DIR/OpenSim" "tsassets OpenSim content" - fi - - # opensimcurrencyserver-dotnet (Geldsystem) - if confirm_addon "opensimcurrencyserver-dotnet" "$CURRENCY_REPO"; then - sync_support_repo "opensimcurrencyserver" "$CURRENCY_REPO" "$CURRENCY_DIR" - copy_tree_contents "$CURRENCY_DIR/addon-modules" "$OPENSIM_DIR/addon-modules" "currency addon modules" - copy_tree_contents "$CURRENCY_DIR/bin" "$OPENSIM_DIR/bin" "currency bin content" - fi - - # os-data-backup - if confirm_addon "os-data-backup" "$DATA_BACKUP_REPO"; then - sync_support_repo "os-data-backup" "$DATA_BACKUP_REPO" "$DATA_BACKUP_DIR" - copy_tree_contents "$DATA_BACKUP_DIR" "$OPENSIM_DIR/addon-modules/os-data-backup" "os-data-backup content" - fi - - log INFO "Running OpenSim prebuild" - ( - cd "$OPENSIM_DIR" - bash runprebuild.sh - dotnet build --configuration Release OpenSim.sln - ) - - [[ -f "$OPENSIM_DIR/bin/OpenSim.dll" ]] || die "OpenSim build output missing: $OPENSIM_DIR/bin/OpenSim.dll" - [[ -f "$OPENSIM_DIR/bin/Robust.dll" ]] || die "OpenSim build output missing: $OPENSIM_DIR/bin/Robust.dll" - - if [[ "$DEPLOY_BINARIES" == "true" ]]; then - deploy_opensim_binaries - configure_opensim_runtime - else - log INFO "Binary deployment skipped by configuration" - fi - - log INFO "OpenSim install/build flow completed" -} - -# Allgemeine Bestaetigungsfunktion fuer externe Addons. -# Umgebungsvariable ADDON_CONFIRMED=true ueberspringt die Abfrage (CI/Automation). -confirm_addon() { - local addon_name="${1:-Addon}" - local addon_desc="${2:-}" - local answer - - if [[ "${ADDON_CONFIRMED:-}" == "true" ]]; then - return 0 - fi - - echo - echo "=======================================================" - echo " $(msg PROMPT_EXTERNAL_ADDON): $addon_name" - [[ -n "$addon_desc" ]] && echo " $addon_desc" - echo " $(msg PROMPT_ADDON_INFO_1)" - echo " $(msg PROMPT_ADDON_INFO_2)" - echo "=======================================================" - read -r -p " $(msg PROMPT_INSTALL_YESNO) " answer - case "${answer,,}" in - j|ja|y|yes|o|oui|s|si|sí) return 0 ;; - *) - log INFO "$(msg INFO_ADDON_SKIPPED): $addon_name" - return 1 - ;; - esac -} - -confirm_janus() { - local action_label="${1:-Janus-Aktion}" - local answer - - # Im nicht-interaktiven Betrieb (z. B. CI) Var JANUS_CONFIRMED=true setzen - if [[ "${JANUS_CONFIRMED:-}" == "true" ]]; then - return 0 - fi - - echo - echo "=======================================================" - echo " $(msg PROMPT_JANUS_TITLE): $action_label" - echo "=======================================================" - echo " $(msg PROMPT_JANUS_INFO_1)" - echo " $(msg PROMPT_JANUS_INFO_2)" - echo " $(msg PROMPT_JANUS_INFO_3) $JANUS_PREFIX." - echo "=======================================================" - read -r -p " $(msg PROMPT_CONTINUE_YESNO) " answer - case "${answer,,}" in - j|ja|y|yes|o|oui|s|si|sí) return 0 ;; - *) - log INFO "$(msg INFO_JANUS_CANCELLED)" - exit 0 - ;; - esac -} - -install_janus() { - confirm_janus "Installation + Konfiguration" - compile_janus - configure_janus -} - -ensure_shared_config_for_install() { - if [[ -f "$OSMTOOL_CONFIG_FILE" ]]; then - return 0 - fi - - if [[ -t 0 ]]; then - log INFO "Shared configuration not found. Starting interactive setup." - init_shared_config_interactive - return 0 - fi - - log INFO "Shared configuration not found at $OSMTOOL_CONFIG_FILE (non-interactive mode)" - return 0 -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" -REPO_MODE="${REPO_MODE:-update}" -OPENSIM_REPO="${OPENSIM_REPO:-https://github.com/opensim/opensim.git}" -OPENSIM_BRANCH="${OPENSIM_BRANCH:-master}" -OPENSIM_DIR="${OPENSIM_DIR:-${CONFIG_OPENSIM_DIR:-$WORKDIR/opensim}}" -TSASSETS_REPO="${TSASSETS_REPO:-https://github.com/ManfredAabye/opensim-tsassets.git}" -TSASSETS_DIR="${TSASSETS_DIR:-$WORKDIR/opensim-tsassets}" -CURRENCY_REPO="${CURRENCY_REPO:-https://github.com/ManfredAabye/opensimcurrencyserver-dotnet.git}" -CURRENCY_DIR="${CURRENCY_DIR:-$WORKDIR/opensimcurrencyserver}" -DATA_BACKUP_REPO="${DATA_BACKUP_REPO:-https://github.com/ManfredAabye/os-data-backup.git}" -DATA_BACKUP_DIR="${DATA_BACKUP_DIR:-$WORKDIR/os-data-backup}" -DEPLOY_BINARIES="${DEPLOY_BINARIES:-true}" -LEGACY_PATCH_DIR="${LEGACY_PATCH_DIR:-}" -DB_ROOT_USER="${DB_ROOT_USER:-${CONFIG_DB_ROOT_USER:-root}}" -DB_ROOT_PASS="${DB_ROOT_PASS:-${CONFIG_DB_ROOT_PASS:-}}" -DB_USER="${DB_USER:-${CONFIG_DB_USER:-opensimuser}}" -DB_PASS="${DB_PASS:-${CONFIG_DB_PASS:-}}" -JANUS_PREFIX="${JANUS_PREFIX:-${CONFIG_JANUS_PREFIX:-/opt/janus}}" -JANUS_SRC="${JANUS_SRC:-$WORKDIR/janus-gateway}" -PUBLIC_HOST="${PUBLIC_HOST:-${CONFIG_PUBLIC_HOST:-127.0.0.1}}" -HTTP_PORT="${HTTP_PORT:-8088}" -ADMIN_PORT="${ADMIN_PORT:-7088}" -RTP_RANGE="${RTP_RANGE:-10000-10200}" -ENABLE_ADMIN="${ENABLE_ADMIN:-false}" -API_SECRET="${API_SECRET:-}" -ADMIN_SECRET="${ADMIN_SECRET:-}" -GRIDNAME="${GRIDNAME:-${CONFIG_GRIDNAME:-}}" -SIM_COUNT="${SIM_COUNT:-0}" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --opensim-dir) OPENSIM_DIR="$2"; shift 2 ;; - --opensim-repo) OPENSIM_REPO="$2"; shift 2 ;; - --opensim-branch) OPENSIM_BRANCH="$2"; shift 2 ;; - --repo-mode) REPO_MODE="$2"; shift 2 ;; - --tsassets-dir) TSASSETS_DIR="$2"; shift 2 ;; - --currency-dir) CURRENCY_DIR="$2"; shift 2 ;; - --data-backup-dir) DATA_BACKUP_DIR="$2"; shift 2 ;; - --deploy-binaries) DEPLOY_BINARIES="$2"; shift 2 ;; - --legacy-patch-dir) LEGACY_PATCH_DIR="$2"; shift 2 ;; - --db-root-user) DB_ROOT_USER="$2"; shift 2 ;; - --db-root-pass) DB_ROOT_PASS="$2"; shift 2 ;; - --db-user) DB_USER="$2"; shift 2 ;; - --db-pass) DB_PASS="$2"; shift 2 ;; - --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; - --janus-src) JANUS_SRC="$2"; shift 2 ;; - --public-host) PUBLIC_HOST="$2"; shift 2 ;; - --http-port) HTTP_PORT="$2"; shift 2 ;; - --admin-port) ADMIN_PORT="$2"; shift 2 ;; - --rtp-range) RTP_RANGE="$2"; shift 2 ;; - --enable-admin) ENABLE_ADMIN="$2"; shift 2 ;; - --api-secret) API_SECRET="$2"; shift 2 ;; - --admin-secret) ADMIN_SECRET="$2"; shift 2 ;; --gridname) GRIDNAME="$2"; shift 2 ;; - --sim-count) SIM_COUNT="$2"; shift 2 ;; --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed install "$PROFILE" "$ACTION" - -if [[ "$ACTION" != "init-config" ]]; then - ensure_shared_config_for_install -fi - -case "$REPO_MODE" in - update|fresh) ;; - *) die "Unsupported repo mode: $REPO_MODE" ;; -esac - -case "$DEPLOY_BINARIES" in - true|false) ;; - *) die "--deploy-binaries must be true or false" ;; -esac - -log INFO "Using workdir: $WORKDIR" -log INFO "Using profile: $PROFILE" -log INFO "Repo mode: $REPO_MODE" -log INFO "OpenSim dir: $OPENSIM_DIR" -log INFO "Janus prefix: $JANUS_PREFIX" - -case "$ACTION" in - init-config) - init_shared_config_interactive - ;; - server-check) server_check ;; - prepare-ubuntu) prepare_ubuntu ;; - install-opensim-deps) install_opensim_deps ;; - install-dotnet8) install_dotnet8 ;; - install-opensim) install_opensim ;; - configure-opensim) configure_opensim_runtime ;; - configure-database) configure_database ;; - compile-janus) - confirm_janus "Kompilierung" - compile_janus - ;; - configure-janus) - confirm_janus "Konfiguration" - configure_janus - ;; - install-janus) install_janus ;; - *) die "Unsupported action: $ACTION" ;; -esac +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_install.sh [--workdir ] --action + [--opensim-dir ] [--opensim-repo ] [--opensim-branch ] [--repo-mode ] + [--tsassets-dir ] [--currency-dir ] [--data-backup-dir ] + [--deploy-binaries ] [--legacy-patch-dir ] + [--db-root-user ] [--db-root-pass ] [--db-user ] [--db-pass ] + [--janus-prefix ] [--janus-src ] [--public-host ] [--http-port ] + [--admin-port ] [--rtp-range ] [--enable-admin ] + [--api-secret ] [--admin-secret ] + +Actions: + init-config Create/update shared osmtool configuration interactively + server-check Validate server readiness and required dependencies + prepare-ubuntu Basic apt update/upgrade and base packages + install-opensim-deps Install OpenSim runtime dependencies + install-dotnet8 Install .NET SDK 8.0 for OpenSim build/runtime + install-opensim Clone/update, enrich, build and optionally deploy OpenSim + configure-opensim Generate required runtime ini files from example templates + configure-database Create MariaDB databases/users/grants for robust and sim* runtimes + compile-janus Build and install Janus Gateway + configure-janus Configure Janus for OpenSim usage + install-janus Compile + configure Janus in one run + +Examples: + osmtool_install.sh --action server-check --workdir /opt + osmtool_install.sh --action configure-opensim --profile grid-sim --workdir /opt + osmtool_install.sh --action configure-database --workdir /opt --db-user opensim --db-pass secret +EOF + print_usage_common +} + +has_dotnet8_sdk() { + if ! command -v dotnet >/dev/null 2>&1; then + return 1 + fi + + dotnet --list-sdks 2>/dev/null | awk '{print $1}' | grep -Eq '^8\.' +} + +package_available_in_apt() { + local pkg="$1" + apt-cache show "$pkg" >/dev/null 2>&1 +} + +resolve_package_token() { + local token="$1" + local candidate + local IFS='|' + read -r -a candidates <<< "$token" + + for candidate in "${candidates[@]}"; do + if dpkg -s "$candidate" >/dev/null 2>&1; then + echo "$candidate" + return 0 + fi + done + + for candidate in "${candidates[@]}"; do + if package_available_in_apt "$candidate"; then + echo "$candidate" + return 0 + fi + done + + return 1 +} + +ensure_user_writable_dir() { + local dir="$1" + + if mkdir -p "$dir" 2>/dev/null; then + return 0 + fi + + sudo mkdir -p "$dir" + sudo chown "$(id -u):$(id -g)" "$dir" +} + +ensure_user_owns_path() { + local path="$1" + + if [[ -e "$path" && ! -w "$path" ]]; then + sudo chown -R "$(id -u):$(id -g)" "$path" + fi +} + +sync_git_repo() { + local repo_url="$1" + local repo_dir="$2" + local branch="$3" + local repo_mode="$4" + local parent_dir + local active_branch + + parent_dir="$(dirname "$repo_dir")" + if [[ ! -d "$parent_dir" ]]; then + ensure_user_writable_dir "$parent_dir" + fi + + if [[ "$repo_mode" == "fresh" && -e "$repo_dir" ]]; then + log INFO "Removing existing repository for fresh checkout: $repo_dir" + rm -rf "$repo_dir" 2>/dev/null || sudo rm -rf "$repo_dir" + fi + + if [[ -d "$repo_dir/.git" ]]; then + ensure_user_owns_path "$repo_dir" + log INFO "Updating repository: $repo_dir" + git -C "$repo_dir" fetch --all --prune + active_branch="$branch" + if [[ -z "$active_branch" ]]; then + active_branch="$(git -C "$repo_dir" branch --show-current)" + fi + if [[ -z "$active_branch" ]]; then + active_branch="$(git -C "$repo_dir" symbolic-ref --quiet --short refs/remotes/origin/HEAD 2>/dev/null | sed 's|^origin/||')" + fi + if [[ -n "$active_branch" ]]; then + git -C "$repo_dir" checkout "$active_branch" + git -C "$repo_dir" pull --ff-only origin "$active_branch" + else + git -C "$repo_dir" pull --ff-only + fi + return 0 + fi + + if [[ -d "$repo_dir" && -z "$(ls -A "$repo_dir" 2>/dev/null)" ]]; then + rmdir "$repo_dir" 2>/dev/null || sudo rmdir "$repo_dir" + fi + + if [[ -e "$repo_dir" ]]; then + die "Path exists but is not a git repository: $repo_dir" + fi + + if [[ ! -w "$parent_dir" ]]; then + sudo mkdir -p "$repo_dir" + sudo chown "$(id -u):$(id -g)" "$repo_dir" + fi + + log INFO "Cloning repository $repo_url -> $repo_dir" + if [[ -n "$branch" ]]; then + git clone --branch "$branch" --single-branch "$repo_url" "$repo_dir" + else + git clone "$repo_url" "$repo_dir" + fi +} + +sync_support_repo() { + local repo_name="$1" + local repo_url="$2" + local repo_dir="$3" + + log INFO "Preparing support repository: $repo_name" + sync_git_repo "$repo_url" "$repo_dir" "" "$REPO_MODE" +} + +copy_tree_contents() { + local src_dir="$1" + local dst_dir="$2" + local label="$3" + + if [[ ! -d "$src_dir" ]]; then + log INFO "Skipping missing source for $label: $src_dir" + return 0 + fi + + mkdir -p "$dst_dir" + # Exclude .git to avoid permission issues on repeated runs + if command -v rsync >/dev/null 2>&1; then + rsync -a --exclude='.git' "$src_dir/" "$dst_dir/" + else + find "$src_dir" -maxdepth 1 -mindepth 1 ! -name '.git' \ + -exec cp -a {} "$dst_dir/" \; + fi + log INFO "Copied $label: $src_dir -> $dst_dir" +} + +apply_legacy_patches() { + local patch_dir="$1" + local patch_file + + [[ -n "$patch_dir" ]] || return 0 + + if [[ ! -d "$patch_dir" ]]; then + die "Legacy patch directory not found: $patch_dir" + fi + + shopt -s nullglob + local patches=("$patch_dir"/*.patch) + shopt -u nullglob + + if [[ ${#patches[@]} -eq 0 ]]; then + log INFO "No legacy patches found in $patch_dir" + return 0 + fi + + for patch_file in "${patches[@]}"; do + if git -C "$OPENSIM_DIR" apply --reverse --check "$patch_file" >/dev/null 2>&1; then + log INFO "Legacy patch already applied: $(basename "$patch_file")" + continue + fi + + log INFO "Applying legacy patch: $(basename "$patch_file")" + if ! git -C "$OPENSIM_DIR" apply "$patch_file"; then + git -C "$OPENSIM_DIR" apply --ignore-space-change --ignore-whitespace "$patch_file" \ + || die "Failed to apply legacy patch: $patch_file" + fi + done +} + +deploy_opensim_binaries() { + local src_bin="$OPENSIM_DIR/bin" + local deployed=0 + local sim_dir + + [[ -d "$src_bin" ]] || die "OpenSim build output missing: $src_bin" + + if [[ -d "$WORKDIR/robust/bin" ]]; then + copy_tree_contents "$src_bin" "$WORKDIR/robust/bin" "robust binaries" + deployed=1 + fi + + if [[ -d "$WORKDIR/standalone/bin" ]]; then + copy_tree_contents "$src_bin" "$WORKDIR/standalone/bin" "standalone binaries" + deployed=1 + fi + + shopt -s nullglob + for sim_dir in "$WORKDIR"/sim*; do + if [[ -d "$sim_dir/bin" ]]; then + copy_tree_contents "$src_bin" "$sim_dir/bin" "region binaries" + deployed=1 + fi + done + shopt -u nullglob + + if [[ "$deployed" -eq 0 ]]; then + log INFO "No target runtime directories found for binary deployment under $WORKDIR" + else + log INFO "OpenSim binaries deployed to available runtime directories" + fi +} + +install_dotnet8() { + need_cmd apt-get + need_cmd sudo + need_cmd wget + + if has_dotnet8_sdk; then + log INFO "dotnet SDK 8.x already installed" + return 0 + fi + + log INFO "Installing .NET SDK 8.0" + sudo apt-get update + sudo apt-get install -y apt-transport-https ca-certificates gnupg + + if ! apt-cache policy dotnet-sdk-8.0 | grep -q "Candidate:"; then + local version_id pkg_url pkg_file + version_id="$(awk -F= '/^VERSION_ID=/{gsub(/\"/,"",$2); print $2; exit}' /etc/os-release 2>/dev/null || true)" + [[ -n "$version_id" ]] || die "Could not detect VERSION_ID from /etc/os-release" + pkg_url="https://packages.microsoft.com/config/ubuntu/${version_id}/packages-microsoft-prod.deb" + pkg_file="/tmp/packages-microsoft-prod.deb" + + log INFO "Adding Microsoft package repository for Ubuntu ${version_id}" + wget -q -O "$pkg_file" "$pkg_url" + sudo dpkg -i "$pkg_file" + rm -f "$pkg_file" + sudo apt-get update + fi + + sudo apt-get install -y dotnet-sdk-8.0 + + if has_dotnet8_sdk; then + log INFO "dotnet SDK 8.x installed successfully" + return 0 + fi + + die "dotnet SDK 8.x installation failed" +} + +install_opensim_deps() { + local tokens=( + git zip screen libgdiplus zlib1g libunwind8 libgssapi-krb5-2 libstdc++6 + "mariadb-client|default-mysql-client|mysql-client" + "mariadb-server|mysql-server" + "libgcc-s1|libgcc1" + "libssl3|libssl1.1" + "libicu74|libicu72|libicu71|libicu70|libicu67" + "liblttng-ust1|liblttng-ust0" + ) + local to_install=() + local token resolved + + need_cmd apt-get + need_cmd sudo + + for token in "${tokens[@]}"; do + if resolve_package_token "$token" >/dev/null 2>&1; then + resolved="$(resolve_package_token "$token")" + if ! dpkg -s "$resolved" >/dev/null 2>&1; then + to_install+=("$resolved") + fi + else + die "No installable package found for token: $token" + fi + done + + if [[ ${#to_install[@]} -eq 0 ]]; then + log INFO "OpenSim runtime dependencies already installed" + return 0 + fi + + log INFO "Installing OpenSim dependencies: ${to_install[*]}" + sudo apt-get update + sudo apt-get install -y "${to_install[@]}" +} + +ensure_mariadb_service() { + need_cmd sudo + + if ! command -v mariadb >/dev/null 2>&1; then + die "MariaDB client not found after dependency install" + fi + + if command -v systemctl >/dev/null 2>&1; then + if systemctl list-unit-files 2>/dev/null | grep -q '^mariadb\.service'; then + log INFO "Ensuring mariadb.service is enabled and running" + sudo systemctl enable --now mariadb + if ! systemctl is-active --quiet mariadb; then + die "MariaDB service could not be started" + fi + return 0 + fi + fi + + if command -v service >/dev/null 2>&1; then + if service --status-all 2>/dev/null | grep -q mariadb; then + log INFO "Ensuring MariaDB service is running" + sudo service mariadb start + return 0 + fi + fi + + log INFO "No controllable MariaDB service unit detected; skipping service activation" +} + +copy_ini_if_missing() { + local bin_dir="$1" + local src_name="$2" + local dst_name="$3" + local src dst + + src="$bin_dir/$src_name" + dst="$bin_dir/$dst_name" + + [[ -d "$bin_dir" ]] || return 0 + + if [[ -f "$dst" ]]; then + log INFO "Keeping existing config: $dst" + return 0 + fi + + if [[ -f "$src" ]]; then + cp -a "$src" "$dst" + log INFO "Created config from template: $dst" + else + log INFO "Template not found, skipping: $src" + fi +} + +copy_example_if_missing() { + local bin_dir="$1" + local base_name="$2" + copy_ini_if_missing "$bin_dir" "${base_name}.example" "$base_name" +} + +set_ini_key_value() { + local file="$1" + local key="$2" + local value="$3" + local escaped + + [[ -f "$file" ]] || return 0 + escaped="${value//\\/\\\\}" + escaped="${escaped//&/\\&}" + sed -i -E "s|^([[:space:]]*${key}[[:space:]]*=[[:space:]]*).*$|\\1\"${escaped}\"|" "$file" +} + +set_architecture_include() { + local file="$1" + local include_value="$2" + + [[ -f "$file" ]] || return 0 + + if grep -qE '^[[:space:]]*Include-Architecture[[:space:]]*=' "$file"; then + sed -i -E "s|^([[:space:]]*Include-Architecture[[:space:]]*=[[:space:]]*).*$|\\1\"${include_value}\"|" "$file" + else + { + echo "" + echo "[Architecture]" + echo "Include-Architecture = \"${include_value}\"" + } >> "$file" + fi +} + +read_userinfo_credential() { + local file="$1" + local key="$2" + + [[ -f "$file" ]] || return 1 + awk -F '=' -v key="$key" ' + $1 ~ "^[[:space:]]*" key "[[:space:]]*$" { + sub(/^[[:space:]]+/, "", $2) + sub(/[[:space:]]+$/, "", $2) + print $2 + exit + } + ' "$file" +} + +configure_opensim_runtime() { + local sim_dir cfg_user cfg_pass userinfo_file sim_arch + + log INFO "Configuring OpenSim runtime ini files" + + copy_ini_if_missing "$WORKDIR/robust/bin" "Robust.HG.ini.example" "Robust.ini" + copy_ini_if_missing "$WORKDIR/robust/bin" "Robust.ini.example" "Robust.ini" + copy_ini_if_missing "$WORKDIR/robust/bin" "MoneyServer.ini.example" "MoneyServer.ini" + copy_example_if_missing "$WORKDIR/robust/bin/config-include" "GridCommon.ini" + copy_example_if_missing "$WORKDIR/robust/bin/config-include" "osslEnable.ini" + + copy_ini_if_missing "$WORKDIR/standalone/bin" "OpenSim.ini.example" "OpenSim.ini" + copy_example_if_missing "$WORKDIR/standalone/bin/config-include" "StandaloneCommon.ini" + copy_example_if_missing "$WORKDIR/standalone/bin/config-include" "osslEnable.ini" + + sim_arch="config-include/Grid.ini" + if [[ "$PROFILE" == "standalone" ]]; then + sim_arch="config-include/Standalone.ini" + fi + + shopt -s nullglob + for sim_dir in "$WORKDIR"/sim*/bin; do + copy_ini_if_missing "$sim_dir" "OpenSim.ini.example" "OpenSim.ini" + copy_example_if_missing "$sim_dir/config-include" "GridCommon.ini" + copy_example_if_missing "$sim_dir/config-include" "osslEnable.ini" + set_architecture_include "$sim_dir/OpenSim.ini" "$sim_arch" + done + shopt -u nullglob + + cfg_user="$DB_USER" + cfg_pass="$DB_PASS" + userinfo_file="$WORKDIR/UserInfo.ini" + + if [[ -z "$cfg_user" ]]; then + cfg_user="$(read_userinfo_credential "$userinfo_file" "DB_Benutzername" || true)" + fi + if [[ -z "$cfg_pass" ]]; then + cfg_pass="$(read_userinfo_credential "$userinfo_file" "DB_Passwort" || true)" + fi + + if [[ -n "$cfg_user" && -n "$cfg_pass" ]]; then + local db_conn_robust db_conn_sim sim_name_inner + + # MoneyServer Credentials + set_ini_key_value "$WORKDIR/robust/bin/MoneyServer.ini" "username" "$cfg_user" + set_ini_key_value "$WORKDIR/robust/bin/MoneyServer.ini" "password" "$cfg_pass" + + # Robust.ini ConnectionString (zwingend erforderlich für Datenbankverbindung) + db_conn_robust="Data Source=localhost;Database=robust;User ID=${cfg_user};Password=${cfg_pass};Old Guids=true;" + if [[ -f "$WORKDIR/robust/bin/Robust.ini" ]]; then + upsert_key "$WORKDIR/robust/bin/Robust.ini" "ConnectionString" "\"${db_conn_robust}\"" + fi + + # Jede simX/bin/OpenSim.ini ConnectionString (zwingend, sonst startet sim nicht) + shopt -s nullglob + for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do + sim_name_inner="$(basename "$(dirname "$sim_dir")")" + [[ "$sim_name_inner" =~ ^sim[0-9]+$ ]] || continue + [[ -f "$sim_dir/OpenSim.ini" ]] || continue + db_conn_sim="Data Source=localhost;Database=${sim_name_inner};User ID=${cfg_user};Password=${cfg_pass};Old Guids=true;" + upsert_key "$sim_dir/OpenSim.ini" "ConnectionString" "\"${db_conn_sim}\"" + done + shopt -u nullglob + + log INFO "Updated ConnectionStrings in Robust.ini, MoneyServer.ini und simX/OpenSim.ini" + else + log INFO "Keine DB-Credentials verfügbar — ConnectionString nicht gesetzt. Erst configure-database ausführen." + fi + + # Hostname/IP in alle Konfigurationsdateien einsetzen (YOURHOST ersetzen) + if [[ -n "$PUBLIC_HOST" && "$PUBLIC_HOST" != "127.0.0.1" ]]; then + local h_escaped + h_escaped="$(printf '%s' "$PUBLIC_HOST" | sed 's/[\/&]/\\&/g')" + local cfg_f + for cfg_f in \ + "$WORKDIR/robust/bin/Robust.ini" \ + "$WORKDIR/robust/bin/config-include/GridCommon.ini" \ + "$WORKDIR/standalone/bin/config-include/StandaloneCommon.ini"; do + [[ -f "$cfg_f" ]] || continue + sed -i "s|YOURHOST|${h_escaped}|g" "$cfg_f" + done + shopt -s nullglob + for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do + for cfg_f in "$sim_dir/OpenSim.ini" "$sim_dir/config-include/GridCommon.ini"; do + [[ -f "$cfg_f" ]] || continue + sed -i "s|YOURHOST|${h_escaped}|g" "$cfg_f" + done + done + shopt -u nullglob + log INFO "Hostname ($PUBLIC_HOST) in Konfigurationsdateien eingesetzt" + fi + + # Gridname in Konfigurationsdateien setzen + if [[ -n "$GRIDNAME" ]]; then + local cfg_f + for cfg_f in \ + "$WORKDIR/robust/bin/Robust.ini" \ + "$WORKDIR/robust/bin/config-include/GridCommon.ini" \ + "$WORKDIR/standalone/bin/config-include/StandaloneCommon.ini"; do + [[ -f "$cfg_f" ]] || continue + upsert_key "$cfg_f" "GridName" "\"${GRIDNAME}\"" + upsert_key "$cfg_f" "WelcomeMessage" "\"Willkommen bei ${GRIDNAME}\"" + done + log INFO "Gridname ($GRIDNAME) in Konfigurationsdateien gesetzt" + fi + + log INFO "OpenSim runtime ini Konfiguration abgeschlossen" +} + +sql_escape() { + local s="$1" + s="${s//\\/\\\\}" + s="${s//\'/\'\'}" + printf '%s' "$s" +} + +run_mariadb_sql() { + local sql="$1" + + if [[ -n "$DB_ROOT_PASS" ]]; then + mariadb -u"$DB_ROOT_USER" -p"$DB_ROOT_PASS" -e "$sql" + else + mariadb -u"$DB_ROOT_USER" -e "$sql" + fi +} + +discover_sim_databases() { + local sim_bin sim_name + local sim_dbs=() + + shopt -s nullglob + for sim_bin in "$WORKDIR"/sim*/bin; do + sim_name="$(basename "$(dirname "$sim_bin")")" + sim_dbs+=("$sim_name") + done + shopt -u nullglob + + printf '%s\n' "${sim_dbs[@]}" +} + +write_db_credentials_file() { + local file="$WORKDIR/UserInfo.ini" + + mkdir -p "$WORKDIR" 2>/dev/null || sudo mkdir -p "$WORKDIR" + if [[ ! -f "$file" ]]; then + : > "$file" 2>/dev/null || sudo touch "$file" + fi + + { + echo "[DatabaseData]" + echo "DB_Benutzername = $DB_USER" + echo "DB_Passwort = $DB_PASS" + } | sudo tee "$file" >/dev/null + + log INFO "Database credentials written: $file" +} + +configure_database() { + local escaped_user escaped_pass db_name + local db_ident + local sim_db_list + + need_cmd mariadb + need_cmd sudo + ensure_mariadb_service + + [[ -n "$DB_USER" ]] || die "--db-user is required for configure-database" + [[ -n "$DB_PASS" ]] || die "--db-pass is required for configure-database" + + escaped_user="$(sql_escape "$DB_USER")" + escaped_pass="$(sql_escape "$DB_PASS")" + + if ! run_mariadb_sql "SELECT 1" >/dev/null 2>&1; then + die "Cannot connect to MariaDB as '$DB_ROOT_USER'. Check --db-root-user/--db-root-pass and server state." + fi + + log INFO "Configuring MariaDB databases and grants" + + if [[ -d "$WORKDIR/robust" ]]; then + run_mariadb_sql "CREATE DATABASE IF NOT EXISTS robust CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + log INFO "Ensured database: robust" + fi + + # Sim-Datenbanken: bei --sim-count N explizit, sonst Verzeichnisse ermitteln + local sim_db_list="" + if [[ "$SIM_COUNT" -gt 0 ]]; then + sim_db_list="$(for ((i=1; i<=SIM_COUNT; i++)); do echo "sim${i}"; done)" + log INFO "--sim-count $SIM_COUNT: erstelle Datenbanken sim1..sim${SIM_COUNT}" + else + sim_db_list="$(discover_sim_databases)" + if [[ -z "$sim_db_list" ]]; then + log INFO "Keine sim*-Verzeichnisse unter $WORKDIR gefunden — sim-Datenbanken übersprungen. Mit --sim-count N erzwingen." + fi + fi + + if [[ -n "$sim_db_list" ]]; then + while IFS= read -r db_name; do + [[ -n "$db_name" ]] || continue + local db_ident="\`$db_name\`" + run_mariadb_sql "CREATE DATABASE IF NOT EXISTS $db_ident CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" + log INFO "Datenbank sichergestellt: $db_name" + done <<< "$sim_db_list" + fi + + run_mariadb_sql "CREATE USER IF NOT EXISTS '$escaped_user'@'localhost' IDENTIFIED BY '$escaped_pass';" + run_mariadb_sql "ALTER USER '$escaped_user'@'localhost' IDENTIFIED BY '$escaped_pass';" + + if [[ -d "$WORKDIR/robust" ]]; then + run_mariadb_sql "GRANT ALL PRIVILEGES ON robust.* TO '$escaped_user'@'localhost';" + fi + + if [[ -n "$sim_db_list" ]]; then + while IFS= read -r db_name; do + [[ -n "$db_name" ]] || continue + local db_ident="\`$db_name\`" + run_mariadb_sql "GRANT ALL PRIVILEGES ON $db_ident.* TO '$escaped_user'@'localhost';" + done <<< "$sim_db_list" + fi + + run_mariadb_sql "FLUSH PRIVILEGES;" + + write_db_credentials_file + log INFO "MariaDB Datenbank-Setup abgeschlossen" +} + +server_check() { + local fail=0 + local os_id="" + local free_kb="0" + local missing_pkgs=() + local required_janus_pkgs=( + build-essential cmake git pkg-config automake libtool gengetopt + libmicrohttpd-dev libjansson-dev libssl-dev libsofia-sip-ua-dev libglib2.0-dev + libopus-dev libogg-dev libcurl4-openssl-dev liblua5.3-dev libconfig-dev + libwebsockets-dev libsrtp2-dev libnice-dev libsqlite3-dev + ) + local required_opensim_tokens=( + git zip screen libgdiplus zlib1g libunwind8 libgssapi-krb5-2 libstdc++6 + "mariadb-client|default-mysql-client|mysql-client" + "mariadb-server|mysql-server" + "libgcc-s1|libgcc1" + "libssl3|libssl1.1" + "libicu74|libicu72|libicu71|libicu70|libicu67" + "liblttng-ust1|liblttng-ust0" + ) + local pkg token + + log INFO "Running server readiness check" + + if [[ -f /etc/os-release ]]; then + os_id="$(awk -F= '/^ID=/{gsub(/\"/,"",$2); print $2; exit}' /etc/os-release 2>/dev/null || true)" + [[ -n "$os_id" ]] || os_id="unknown" + local os_pretty + os_pretty="$(awk -F= '/^PRETTY_NAME=/{gsub(/\"/,"",$2); print $2; exit}' /etc/os-release 2>/dev/null || true)" + [[ -n "$os_pretty" ]] || os_pretty="unknown" + log INFO "Detected OS: $os_pretty" + fi + + if [[ "$os_id" != "ubuntu" && "$os_id" != "debian" ]]; then + log ERROR "Unsupported OS for this automation: $os_id" + fail=1 + fi + + if command -v sudo >/dev/null 2>&1; then + if sudo -n true >/dev/null 2>&1; then + log INFO "sudo non-interactive check: OK" + else + log INFO "sudo available but password will be required" + fi + else + log ERROR "sudo not found" + fail=1 + fi + + if command -v apt-get >/dev/null 2>&1; then + log INFO "apt-get available" + else + log ERROR "apt-get missing" + fail=1 + fi + + if command -v curl >/dev/null 2>&1; then + if curl -Is https://github.com >/dev/null 2>&1; then + log INFO "Network check to github.com: OK" + else + log ERROR "Network check to github.com failed" + fail=1 + fi + else + log ERROR "curl missing" + fail=1 + fi + + free_kb="$(df -Pk /opt | awk 'NR==2 {print $4}')" + if [[ -n "$free_kb" && "$free_kb" -gt 2097152 ]]; then + log INFO "Disk space in /opt is sufficient" + else + log ERROR "Low disk space in /opt (need at least 2GB free)" + fail=1 + fi + + for pkg in "${required_janus_pkgs[@]}"; do + if ! dpkg -s "$pkg" >/dev/null 2>&1; then + missing_pkgs+=("$pkg") + fi + done + + for token in "${required_opensim_tokens[@]}"; do + if ! resolve_package_token "$token" >/dev/null 2>&1; then + missing_pkgs+=("$token") + fi + done + + if [[ ${#missing_pkgs[@]} -eq 0 ]]; then + log INFO "All required Janus/OpenSim dependency packages are installed" + else + log ERROR "Missing packages: ${missing_pkgs[*]}" + log INFO "Run: sudo apt-get update && sudo apt-get install -y ${missing_pkgs[*]}" + fail=1 + fi + + if has_dotnet8_sdk; then + log INFO "dotnet SDK 8.x found" + else + log ERROR "dotnet SDK 8.x missing (required for OpenSim build/runtime)" + fail=1 + fi + + if command -v mysqldump >/dev/null 2>&1; then + log INFO "mysqldump found (MariaDB backup tooling ready)" + else + log ERROR "mysqldump missing (MariaDB client tools are required)" + fail=1 + fi + + if [[ "$fail" -eq 0 ]]; then + log INFO "Server readiness check PASSED" + return 0 + fi + + die "Server readiness check FAILED" +} + +upsert_key() { + local file="$1" + local key="$2" + local value="$3" + + if grep -Eq "^[[:space:]]*;?[[:space:]]*${key}[[:space:]]*=" "$file"; then + sudo sed -i -E "s|^[[:space:]]*;?[[:space:]]*(${key})[[:space:]]*=.*|\1 = $value|" "$file" + else + echo "$key = $value" | sudo tee -a "$file" >/dev/null + fi +} + +generate_alnum_token() { + local length="${1:-32}" + if command -v openssl >/dev/null 2>&1; then + openssl rand -hex "$((length / 2))" | cut -c1-"$length" + return + fi + tr -dc 'A-Za-z0-9' /dev/null || sudo mkdir -p "$WORKDIR" + + # Vollstaendiges OpenSim/Robust-Snippet (entspricht config-janus-linux.sh) + cat </dev/null +; ========================================================== +; OpenSim WebRTC/Janus Config (generiert von osmtool) +; ========================================================== + +; ---------------------------- +; OpenSim.ini [WebRtcVoice] +; ---------------------------- +[WebRtcVoice] + Enabled = true + SpatialVoiceService = WebRtcVoice.dll:WebRtcVoiceServiceConnector + NonSpatialVoiceService = WebRtcVoice.dll:WebRtcVoiceServiceConnector + WebRtcVoiceServerURI = http://$PUBLIC_HOST:8003 + +; ---------------------------- +; Robust.ini [ServiceList] + [WebRtcVoice] + [JanusWebRtcVoice] +; ---------------------------- +[ServiceList] + VoiceServiceConnector = "8000/OpenSim.Server.Handlers.dll:OpenSim.Server.Handlers.WebRtcVoiceServerConnector" + +[WebRtcVoice] + Enabled = true + NonSpatialVoiceService = WebRtcJanusService.dll:WebRtcJanusService + +[JanusWebRtcVoice] + JanusGatewayURI = http://$PUBLIC_HOST:$HTTP_PORT/janus + APIToken = $api_secret +EOF + + if [[ "$ENABLE_ADMIN" == "true" ]]; then + cat </dev/null + JanusGatewayAdminURI = http://$PUBLIC_HOST:$ADMIN_PORT/admin + AdminAPIToken = $admin_secret +EOF + fi + + cat <<'EOF' | sudo tee -a "$snippet_file" >/dev/null + MessageDetails = false +EOF + + # Secrets sichern (analog janus_instal.sh) + { + echo "JANUS_API_SECRET=$api_secret" + [[ -n "$admin_secret" ]] && echo "JANUS_ADMIN_SECRET=$admin_secret" + echo "JANUS_HTTP_PORT=$HTTP_PORT" + echo "JANUS_PUBLIC_HOST=$PUBLIC_HOST" + } > "$secrets_file" + chmod 600 "$secrets_file" + log INFO "Janus Secrets gespeichert: $secrets_file (chmod 600)" + + cat </dev/null +JANUS_PREFIX=$JANUS_PREFIX +HTTP_PORT=$HTTP_PORT +ADMIN_PORT=$ADMIN_PORT +ENABLE_ADMIN=$ENABLE_ADMIN +RTP_RANGE=$RTP_RANGE +PUBLIC_HOST=$PUBLIC_HOST +EOF + + log INFO "Janus konfiguriert. Snippet: $snippet_file — Marker: $JANUS_PREFIX/.osmtool_janus_ready" + log INFO "Firewall oeffnen: TCP $HTTP_PORT, UDP ${RTP_RANGE%%-*}-${RTP_RANGE##*-}" + log INFO "Janus neu starten: sudo systemctl restart janus" + log INFO "Snippet-Inhalt in OpenSim.ini und Robust.ini uebernehmen." +} + +prepare_ubuntu() { + need_cmd apt-get + log INFO "Preparing Ubuntu server" + sudo apt-get update + sudo apt-get -y upgrade + sudo apt-get -y install curl git screen unzip jq wget + log INFO "Ubuntu base packages installed" +} + +install_opensim() { + need_cmd git + need_cmd dotnet + need_cmd bash + + log INFO "Starting OpenSim install/build flow" + log INFO "OpenSim repository: $OPENSIM_REPO" + log INFO "OpenSim branch: $OPENSIM_BRANCH" + log INFO "OpenSim directory: $OPENSIM_DIR" + + sync_git_repo "$OPENSIM_REPO" "$OPENSIM_DIR" "$OPENSIM_BRANCH" "$REPO_MODE" + ensure_user_owns_path "$OPENSIM_DIR" + + # Patch-Dateien nur mit Bestaetigung einspielen + if [[ -n "$LEGACY_PATCH_DIR" ]]; then + if confirm_addon "Patch-Dateien" "Verzeichnis: $LEGACY_PATCH_DIR"; then + apply_legacy_patches "$LEGACY_PATCH_DIR" + fi + fi + + # opensim-tsassets (Texturen/Assets) + if confirm_addon "opensim-tsassets" "$TSASSETS_REPO"; then + sync_support_repo "opensim-tsassets" "$TSASSETS_REPO" "$TSASSETS_DIR" + copy_tree_contents "$TSASSETS_DIR/bin" "$OPENSIM_DIR/bin" "tsassets bin content" + copy_tree_contents "$TSASSETS_DIR/OpenSim" "$OPENSIM_DIR/OpenSim" "tsassets OpenSim content" + fi + + # opensimcurrencyserver-dotnet (Geldsystem) + if confirm_addon "opensimcurrencyserver-dotnet" "$CURRENCY_REPO"; then + sync_support_repo "opensimcurrencyserver" "$CURRENCY_REPO" "$CURRENCY_DIR" + copy_tree_contents "$CURRENCY_DIR/addon-modules" "$OPENSIM_DIR/addon-modules" "currency addon modules" + copy_tree_contents "$CURRENCY_DIR/bin" "$OPENSIM_DIR/bin" "currency bin content" + fi + + # os-data-backup + if confirm_addon "os-data-backup" "$DATA_BACKUP_REPO"; then + sync_support_repo "os-data-backup" "$DATA_BACKUP_REPO" "$DATA_BACKUP_DIR" + copy_tree_contents "$DATA_BACKUP_DIR" "$OPENSIM_DIR/addon-modules/os-data-backup" "os-data-backup content" + fi + + log INFO "Running OpenSim prebuild" + ( + cd "$OPENSIM_DIR" + bash runprebuild.sh + dotnet build --configuration Release OpenSim.sln + ) + + [[ -f "$OPENSIM_DIR/bin/OpenSim.dll" ]] || die "OpenSim build output missing: $OPENSIM_DIR/bin/OpenSim.dll" + [[ -f "$OPENSIM_DIR/bin/Robust.dll" ]] || die "OpenSim build output missing: $OPENSIM_DIR/bin/Robust.dll" + + if [[ "$DEPLOY_BINARIES" == "true" ]]; then + deploy_opensim_binaries + configure_opensim_runtime + else + log INFO "Binary deployment skipped by configuration" + fi + + log INFO "OpenSim install/build flow completed" +} + +# Allgemeine Bestaetigungsfunktion fuer externe Addons. +# Umgebungsvariable ADDON_CONFIRMED=true ueberspringt die Abfrage (CI/Automation). +confirm_addon() { + local addon_name="${1:-Addon}" + local addon_desc="${2:-}" + local answer + + if [[ "${ADDON_CONFIRMED:-}" == "true" ]]; then + return 0 + fi + + echo + echo "=======================================================" + echo " $(msg PROMPT_EXTERNAL_ADDON): $addon_name" + [[ -n "$addon_desc" ]] && echo " $addon_desc" + echo " $(msg PROMPT_ADDON_INFO_1)" + echo " $(msg PROMPT_ADDON_INFO_2)" + echo "=======================================================" + read -r -p " $(msg PROMPT_INSTALL_YESNO) " answer + case "${answer,,}" in + j|ja|y|yes|o|oui|s|si|sí) return 0 ;; + *) + log INFO "$(msg INFO_ADDON_SKIPPED): $addon_name" + return 1 + ;; + esac +} + +confirm_janus() { + local action_label="${1:-Janus-Aktion}" + local answer + + # Im nicht-interaktiven Betrieb (z. B. CI) Var JANUS_CONFIRMED=true setzen + if [[ "${JANUS_CONFIRMED:-}" == "true" ]]; then + return 0 + fi + + echo + echo "=======================================================" + echo " $(msg PROMPT_JANUS_TITLE): $action_label" + echo "=======================================================" + echo " $(msg PROMPT_JANUS_INFO_1)" + echo " $(msg PROMPT_JANUS_INFO_2)" + echo " $(msg PROMPT_JANUS_INFO_3) $JANUS_PREFIX." + echo "=======================================================" + read -r -p " $(msg PROMPT_CONTINUE_YESNO) " answer + case "${answer,,}" in + j|ja|y|yes|o|oui|s|si|sí) return 0 ;; + *) + log INFO "$(msg INFO_JANUS_CANCELLED)" + exit 0 + ;; + esac +} + +install_janus() { + confirm_janus "Installation + Konfiguration" + compile_janus + configure_janus +} + +ensure_shared_config_for_install() { + if [[ -f "$OSMTOOL_CONFIG_FILE" ]]; then + return 0 + fi + + if [[ -t 0 ]]; then + log INFO "Shared configuration not found. Starting interactive setup." + init_shared_config_interactive + return 0 + fi + + log INFO "Shared configuration not found at $OSMTOOL_CONFIG_FILE (non-interactive mode)" + return 0 +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" +REPO_MODE="${REPO_MODE:-update}" +OPENSIM_REPO="${OPENSIM_REPO:-https://github.com/opensim/opensim.git}" +OPENSIM_BRANCH="${OPENSIM_BRANCH:-master}" +OPENSIM_DIR="${OPENSIM_DIR:-${CONFIG_OPENSIM_DIR:-$WORKDIR/opensim}}" +TSASSETS_REPO="${TSASSETS_REPO:-https://github.com/ManfredAabye/opensim-tsassets.git}" +TSASSETS_DIR="${TSASSETS_DIR:-$WORKDIR/opensim-tsassets}" +CURRENCY_REPO="${CURRENCY_REPO:-https://github.com/ManfredAabye/opensimcurrencyserver-dotnet.git}" +CURRENCY_DIR="${CURRENCY_DIR:-$WORKDIR/opensimcurrencyserver}" +DATA_BACKUP_REPO="${DATA_BACKUP_REPO:-https://github.com/ManfredAabye/os-data-backup.git}" +DATA_BACKUP_DIR="${DATA_BACKUP_DIR:-$WORKDIR/os-data-backup}" +DEPLOY_BINARIES="${DEPLOY_BINARIES:-true}" +LEGACY_PATCH_DIR="${LEGACY_PATCH_DIR:-}" +DB_ROOT_USER="${DB_ROOT_USER:-${CONFIG_DB_ROOT_USER:-root}}" +DB_ROOT_PASS="${DB_ROOT_PASS:-${CONFIG_DB_ROOT_PASS:-}}" +DB_USER="${DB_USER:-${CONFIG_DB_USER:-opensimuser}}" +DB_PASS="${DB_PASS:-${CONFIG_DB_PASS:-}}" +JANUS_PREFIX="${JANUS_PREFIX:-${CONFIG_JANUS_PREFIX:-/opt/janus}}" +JANUS_SRC="${JANUS_SRC:-$WORKDIR/janus-gateway}" +PUBLIC_HOST="${PUBLIC_HOST:-${CONFIG_PUBLIC_HOST:-127.0.0.1}}" +HTTP_PORT="${HTTP_PORT:-8088}" +ADMIN_PORT="${ADMIN_PORT:-7088}" +RTP_RANGE="${RTP_RANGE:-10000-10200}" +ENABLE_ADMIN="${ENABLE_ADMIN:-false}" +API_SECRET="${API_SECRET:-}" +ADMIN_SECRET="${ADMIN_SECRET:-}" +GRIDNAME="${GRIDNAME:-${CONFIG_GRIDNAME:-}}" +SIM_COUNT="${SIM_COUNT:-0}" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --opensim-dir) OPENSIM_DIR="$2"; shift 2 ;; + --opensim-repo) OPENSIM_REPO="$2"; shift 2 ;; + --opensim-branch) OPENSIM_BRANCH="$2"; shift 2 ;; + --repo-mode) REPO_MODE="$2"; shift 2 ;; + --tsassets-dir) TSASSETS_DIR="$2"; shift 2 ;; + --currency-dir) CURRENCY_DIR="$2"; shift 2 ;; + --data-backup-dir) DATA_BACKUP_DIR="$2"; shift 2 ;; + --deploy-binaries) DEPLOY_BINARIES="$2"; shift 2 ;; + --legacy-patch-dir) LEGACY_PATCH_DIR="$2"; shift 2 ;; + --db-root-user) DB_ROOT_USER="$2"; shift 2 ;; + --db-root-pass) DB_ROOT_PASS="$2"; shift 2 ;; + --db-user) DB_USER="$2"; shift 2 ;; + --db-pass) DB_PASS="$2"; shift 2 ;; + --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; + --janus-src) JANUS_SRC="$2"; shift 2 ;; + --public-host) PUBLIC_HOST="$2"; shift 2 ;; + --http-port) HTTP_PORT="$2"; shift 2 ;; + --admin-port) ADMIN_PORT="$2"; shift 2 ;; + --rtp-range) RTP_RANGE="$2"; shift 2 ;; + --enable-admin) ENABLE_ADMIN="$2"; shift 2 ;; + --api-secret) API_SECRET="$2"; shift 2 ;; + --admin-secret) ADMIN_SECRET="$2"; shift 2 ;; --gridname) GRIDNAME="$2"; shift 2 ;; + --sim-count) SIM_COUNT="$2"; shift 2 ;; --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed install "$PROFILE" "$ACTION" + +if [[ "$ACTION" != "init-config" ]]; then + ensure_shared_config_for_install +fi + +case "$REPO_MODE" in + update|fresh) ;; + *) die "Unsupported repo mode: $REPO_MODE" ;; +esac + +case "$DEPLOY_BINARIES" in + true|false) ;; + *) die "--deploy-binaries must be true or false" ;; +esac + +log INFO "Using workdir: $WORKDIR" +log INFO "Using profile: $PROFILE" +log INFO "Repo mode: $REPO_MODE" +log INFO "OpenSim dir: $OPENSIM_DIR" +log INFO "Janus prefix: $JANUS_PREFIX" + +case "$ACTION" in + init-config) + init_shared_config_interactive + ;; + server-check) server_check ;; + prepare-ubuntu) prepare_ubuntu ;; + install-opensim-deps) install_opensim_deps ;; + install-dotnet8) install_dotnet8 ;; + install-opensim) install_opensim ;; + configure-opensim) configure_opensim_runtime ;; + configure-database) configure_database ;; + compile-janus) + confirm_janus "Kompilierung" + compile_janus + ;; + configure-janus) + confirm_janus "Konfiguration" + configure_janus + ;; + install-janus) install_janus ;; + *) die "Unsupported action: $ACTION" ;; +esac diff --git a/modular/osmtool_report.sh b/modular/osmtool_report.sh index afbe7b1..c055855 100644 --- a/modular/osmtool_report.sh +++ b/modular/osmtool_report.sh @@ -1,293 +1,293 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_report.sh [--workdir ] --action - [--output ] [--expected-screens ] [--ports ] - [--db-user ] [--db-pass ] [--db-name ] [--log-file ] - -Examples: - osmtool_report.sh --action generate --workdir /opt --db-user opensim --db-pass secret --db-name robust - osmtool_report.sh --action generate --workdir /opt --output /opt/reports/manual_report.txt -EOF - print_usage_common -} - -timestamp_compact() { - date '+%Y%m%d_%H%M%S' -} - -timestamp_iso() { - date '+%Y-%m-%d %H:%M:%S' -} - -split_csv() { - local csv="$1" - local token - local IFS=',' - read -r -a _TOKENS <<< "$csv" - for token in "${_TOKENS[@]}"; do - token="${token## }" - token="${token%% }" - [[ -n "$token" ]] && printf '%s\n' "$token" - done -} - -reports_dir() { - printf '%s' "$WORKDIR/reports" -} - -ensure_reports_dir() { - local dir - dir="$(reports_dir)" - - if mkdir -p "$dir" 2>/dev/null; then - return 0 - fi - - sudo mkdir -p "$dir" - sudo chown "$(id -u):$(id -g)" "$dir" -} - -latest_file() { - local dir="$1" - local pattern="$2" - - [[ -d "$dir" ]] || return 0 - find "$dir" -maxdepth 1 -type f -name "$pattern" -printf '%T@ %p\n' 2>/dev/null | \ - sort -rn | head -1 | cut -d' ' -f2- -} - -format_file_age_hours() { - local path="$1" - local now ts age - - [[ -f "$path" ]] || { - printf 'n/a' - return 0 - } - - now="$(date +%s)" - ts="$(stat -c %Y "$path" 2>/dev/null || echo 0)" - if [[ "$ts" -le 0 ]]; then - printf 'n/a' - return 0 - fi - - age=$(( (now - ts) / 3600 )) - printf '%sh' "$age" -} - -screen_status_lines() { - local screen_name - - if [[ -z "$EXPECTED_SCREENS" ]]; then - printf 'screen: skipped\n' - return 0 - fi - - while IFS= read -r screen_name; do - [[ -n "$screen_name" ]] || continue - if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then - printf 'screen:%s=up\n' "$screen_name" - else - printf 'screen:%s=down\n' "$screen_name" - fi - done < <(split_csv "$EXPECTED_SCREENS") -} - -port_status_lines() { - local port - local use_ss=0 - - if [[ -z "$PORTS" ]]; then - printf 'port: skipped\n' - return 0 - fi - - if command -v ss >/dev/null 2>&1; then - use_ss=1 - elif ! command -v netstat >/dev/null 2>&1; then - printf 'port: unavailable (no ss/netstat)\n' - return 0 - fi - - while IFS= read -r port; do - [[ -n "$port" ]] || continue - if [[ "$use_ss" -eq 1 ]]; then - if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then - printf 'port:%s=listen\n' "$port" - else - printf 'port:%s=closed\n' "$port" - fi - else - if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then - printf 'port:%s=listen\n' "$port" - else - printf 'port:%s=closed\n' "$port" - fi - fi - done < <(split_csv "$PORTS") -} - -database_status() { - if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then - printf 'db: skipped\n' - return 0 - fi - - if ! command -v mariadb >/dev/null 2>&1; then - printf 'db:%s=client-missing\n' "$DB_NAME" - return 0 - fi - - if [[ -n "$DB_PASS" ]]; then - if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then - printf 'db:%s=ok\n' "$DB_NAME" - else - printf 'db:%s=fail\n' "$DB_NAME" - fi - else - if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then - printf 'db:%s=ok\n' "$DB_NAME" - else - printf 'db:%s=fail\n' "$DB_NAME" - fi - fi -} - -log_warning_count() { - local file="$1" - [[ -f "$file" ]] || { - printf 'n/a' - return 0 - } - - grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || printf '0' -} - -default_screens_for_profile() { - case "$1" in - grid-sim) echo "robustserver,sim1" ;; - robust) echo "robustserver" ;; - standalone) echo "standalone" ;; - esac -} - -default_ports_for_profile() { - case "$1" in - grid-sim) echo "8002,9000,9001,8088" ;; - robust) echo "8002,9000,9001" ;; - standalone) echo "9000" ;; - esac -} - -generate_report() { - local out report_title log_target - local newest_sql newest_oar newest_rollback - - ensure_reports_dir - - if [[ -n "$OUTPUT_FILE" ]]; then - out="$OUTPUT_FILE" - else - out="$(reports_dir)/osm_report_$(timestamp_compact).txt" - fi - - newest_sql="$(latest_file "$WORKDIR/backup" 'robust_*.sql*')" - newest_oar="$(latest_file "$WORKDIR/backup" '*.oar')" - newest_rollback="$(latest_file "$WORKDIR/rollback" '*.manifest')" - log_target="$LOG_FILE_PATH" - if [[ -z "$log_target" ]]; then - log_target="$ROOT_DIR/osmtool_backup.log" - fi - - report_title="OSMTool Daily Status Report" - - { - printf '%s\n' "$report_title" - printf 'generated_at: %s\n' "$(timestamp_iso)" - printf 'profile: %s\n' "$PROFILE" - printf 'workdir: %s\n' "$WORKDIR" - printf '\n' - printf '[runtime]\n' - screen_status_lines - port_status_lines - database_status - printf '\n' - printf '[backup]\n' - printf 'sql_latest: %s\n' "${newest_sql:-none}" - printf 'sql_age: %s\n' "$(format_file_age_hours "${newest_sql:-}")" - printf 'oar_latest: %s\n' "${newest_oar:-none}" - printf 'oar_age: %s\n' "$(format_file_age_hours "${newest_oar:-}")" - printf '\n' - printf '[rollback]\n' - printf 'latest_manifest: %s\n' "${newest_rollback:-none}" - printf 'manifest_age: %s\n' "$(format_file_age_hours "${newest_rollback:-}")" - printf '\n' - printf '[logs]\n' - printf 'file: %s\n' "$log_target" - printf 'warning_matches: %s\n' "$(log_warning_count "$log_target")" - } > "$out" - - log INFO "Report generated: $out" - cat "$out" -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" -OUTPUT_FILE="" -EXPECTED_SCREENS="" -PORTS="" -DB_USER="" -DB_PASS="" -DB_NAME="" -LOG_FILE_PATH="" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --output) OUTPUT_FILE="$2"; shift 2 ;; - --expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;; - --ports) PORTS="$2"; shift 2 ;; - --db-user) DB_USER="$2"; shift 2 ;; - --db-pass) DB_PASS="$2"; shift 2 ;; - --db-name) DB_NAME="$2"; shift 2 ;; - --log-file) LOG_FILE_PATH="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed report "$PROFILE" "$ACTION" - -if [[ -z "$EXPECTED_SCREENS" ]]; then - EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")" -elif [[ "$EXPECTED_SCREENS" == "none" ]]; then - EXPECTED_SCREENS="" -fi - -if [[ -z "$PORTS" ]]; then - PORTS="$(default_ports_for_profile "$PROFILE")" -elif [[ "$PORTS" == "none" ]]; then - PORTS="" -fi - -log INFO "Using profile: $PROFILE" - -case "$ACTION" in - generate) generate_report ;; - *) die "Unsupported action: $ACTION" ;; +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_report.sh [--workdir ] --action + [--output ] [--expected-screens ] [--ports ] + [--db-user ] [--db-pass ] [--db-name ] [--log-file ] + +Examples: + osmtool_report.sh --action generate --workdir /opt --db-user opensim --db-pass secret --db-name robust + osmtool_report.sh --action generate --workdir /opt --output /opt/reports/manual_report.txt +EOF + print_usage_common +} + +timestamp_compact() { + date '+%Y%m%d_%H%M%S' +} + +timestamp_iso() { + date '+%Y-%m-%d %H:%M:%S' +} + +split_csv() { + local csv="$1" + local token + local IFS=',' + read -r -a _TOKENS <<< "$csv" + for token in "${_TOKENS[@]}"; do + token="${token## }" + token="${token%% }" + [[ -n "$token" ]] && printf '%s\n' "$token" + done +} + +reports_dir() { + printf '%s' "$WORKDIR/reports" +} + +ensure_reports_dir() { + local dir + dir="$(reports_dir)" + + if mkdir -p "$dir" 2>/dev/null; then + return 0 + fi + + sudo mkdir -p "$dir" + sudo chown "$(id -u):$(id -g)" "$dir" +} + +latest_file() { + local dir="$1" + local pattern="$2" + + [[ -d "$dir" ]] || return 0 + find "$dir" -maxdepth 1 -type f -name "$pattern" -printf '%T@ %p\n' 2>/dev/null | \ + sort -rn | head -1 | cut -d' ' -f2- +} + +format_file_age_hours() { + local path="$1" + local now ts age + + [[ -f "$path" ]] || { + printf 'n/a' + return 0 + } + + now="$(date +%s)" + ts="$(stat -c %Y "$path" 2>/dev/null || echo 0)" + if [[ "$ts" -le 0 ]]; then + printf 'n/a' + return 0 + fi + + age=$(( (now - ts) / 3600 )) + printf '%sh' "$age" +} + +screen_status_lines() { + local screen_name + + if [[ -z "$EXPECTED_SCREENS" ]]; then + printf 'screen: skipped\n' + return 0 + fi + + while IFS= read -r screen_name; do + [[ -n "$screen_name" ]] || continue + if screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]"; then + printf 'screen:%s=up\n' "$screen_name" + else + printf 'screen:%s=down\n' "$screen_name" + fi + done < <(split_csv "$EXPECTED_SCREENS") +} + +port_status_lines() { + local port + local use_ss=0 + + if [[ -z "$PORTS" ]]; then + printf 'port: skipped\n' + return 0 + fi + + if command -v ss >/dev/null 2>&1; then + use_ss=1 + elif ! command -v netstat >/dev/null 2>&1; then + printf 'port: unavailable (no ss/netstat)\n' + return 0 + fi + + while IFS= read -r port; do + [[ -n "$port" ]] || continue + if [[ "$use_ss" -eq 1 ]]; then + if ss -ltnH | awk '{print $4}' | grep -qE "[:.]${port}$"; then + printf 'port:%s=listen\n' "$port" + else + printf 'port:%s=closed\n' "$port" + fi + else + if netstat -ltn 2>/dev/null | awk '{print $4}' | grep -qE "[:.]${port}$"; then + printf 'port:%s=listen\n' "$port" + else + printf 'port:%s=closed\n' "$port" + fi + fi + done < <(split_csv "$PORTS") +} + +database_status() { + if [[ -z "$DB_USER" || -z "$DB_NAME" ]]; then + printf 'db: skipped\n' + return 0 + fi + + if ! command -v mariadb >/dev/null 2>&1; then + printf 'db:%s=client-missing\n' "$DB_NAME" + return 0 + fi + + if [[ -n "$DB_PASS" ]]; then + if mariadb -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then + printf 'db:%s=ok\n' "$DB_NAME" + else + printf 'db:%s=fail\n' "$DB_NAME" + fi + else + if mariadb -u"$DB_USER" "$DB_NAME" -e "SELECT 1" >/dev/null 2>&1; then + printf 'db:%s=ok\n' "$DB_NAME" + else + printf 'db:%s=fail\n' "$DB_NAME" + fi + fi +} + +log_warning_count() { + local file="$1" + [[ -f "$file" ]] || { + printf 'n/a' + return 0 + } + + grep -Eic 'error|warn|exception|fatal' "$file" 2>/dev/null || printf '0' +} + +default_screens_for_profile() { + case "$1" in + grid-sim) echo "robustserver,sim1" ;; + robust) echo "robustserver" ;; + standalone) echo "standalone" ;; + esac +} + +default_ports_for_profile() { + case "$1" in + grid-sim) echo "8002,9000,9001,8088" ;; + robust) echo "8002,9000,9001" ;; + standalone) echo "9000" ;; + esac +} + +generate_report() { + local out report_title log_target + local newest_sql newest_oar newest_rollback + + ensure_reports_dir + + if [[ -n "$OUTPUT_FILE" ]]; then + out="$OUTPUT_FILE" + else + out="$(reports_dir)/osm_report_$(timestamp_compact).txt" + fi + + newest_sql="$(latest_file "$WORKDIR/backup" 'robust_*.sql*')" + newest_oar="$(latest_file "$WORKDIR/backup" '*.oar')" + newest_rollback="$(latest_file "$WORKDIR/rollback" '*.manifest')" + log_target="$LOG_FILE_PATH" + if [[ -z "$log_target" ]]; then + log_target="$ROOT_DIR/osmtool_backup.log" + fi + + report_title="OSMTool Daily Status Report" + + { + printf '%s\n' "$report_title" + printf 'generated_at: %s\n' "$(timestamp_iso)" + printf 'profile: %s\n' "$PROFILE" + printf 'workdir: %s\n' "$WORKDIR" + printf '\n' + printf '[runtime]\n' + screen_status_lines + port_status_lines + database_status + printf '\n' + printf '[backup]\n' + printf 'sql_latest: %s\n' "${newest_sql:-none}" + printf 'sql_age: %s\n' "$(format_file_age_hours "${newest_sql:-}")" + printf 'oar_latest: %s\n' "${newest_oar:-none}" + printf 'oar_age: %s\n' "$(format_file_age_hours "${newest_oar:-}")" + printf '\n' + printf '[rollback]\n' + printf 'latest_manifest: %s\n' "${newest_rollback:-none}" + printf 'manifest_age: %s\n' "$(format_file_age_hours "${newest_rollback:-}")" + printf '\n' + printf '[logs]\n' + printf 'file: %s\n' "$log_target" + printf 'warning_matches: %s\n' "$(log_warning_count "$log_target")" + } > "$out" + + log INFO "Report generated: $out" + cat "$out" +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" +OUTPUT_FILE="" +EXPECTED_SCREENS="" +PORTS="" +DB_USER="" +DB_PASS="" +DB_NAME="" +LOG_FILE_PATH="" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --output) OUTPUT_FILE="$2"; shift 2 ;; + --expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;; + --ports) PORTS="$2"; shift 2 ;; + --db-user) DB_USER="$2"; shift 2 ;; + --db-pass) DB_PASS="$2"; shift 2 ;; + --db-name) DB_NAME="$2"; shift 2 ;; + --log-file) LOG_FILE_PATH="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed report "$PROFILE" "$ACTION" + +if [[ -z "$EXPECTED_SCREENS" ]]; then + EXPECTED_SCREENS="$(default_screens_for_profile "$PROFILE")" +elif [[ "$EXPECTED_SCREENS" == "none" ]]; then + EXPECTED_SCREENS="" +fi + +if [[ -z "$PORTS" ]]; then + PORTS="$(default_ports_for_profile "$PROFILE")" +elif [[ "$PORTS" == "none" ]]; then + PORTS="" +fi + +log INFO "Using profile: $PROFILE" + +case "$ACTION" in + generate) generate_report ;; + *) die "Unsupported action: $ACTION" ;; esac \ No newline at end of file diff --git a/modular/osmtool_restore.sh b/modular/osmtool_restore.sh index 845e371..f7a54ee 100644 --- a/modular/osmtool_restore.sh +++ b/modular/osmtool_restore.sh @@ -1,260 +1,260 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_restore.sh [--workdir ] --action - [--db-user ] [--db-pass ] [--db-name ] - [--region ] [--session ] [--file ] - [--dry-run ] - -Examples: - osmtool_restore.sh --action list-backups --workdir /opt - osmtool_restore.sh --action db-restore --db-user opensim --db-pass secret --db-name robust --file /opt/backup/robust_robust_20260401_120000.sql -EOF - print_usage_common -} - -backup_dir() { - printf '%s' "$WORKDIR/backup" -} - -ensure_backup_dir() { - local dir - dir="$(backup_dir)" - - if [[ ! -d "$dir" ]]; then - die "Backup directory does not exist: $dir" - fi - - return 0 -} - -list_backups() { - local dir - dir="$(backup_dir)" - - if [[ ! -d "$dir" ]]; then - log INFO "No backup directory found: $dir" - return 0 - fi - - log INFO "SQL Backups:" - find "$dir" -maxdepth 1 -name "robust_*.sql*" -type f -printf '%T@ %p\n' 2>/dev/null | \ - sort -rn | cut -d' ' -f2- | head -5 || true - - log INFO "OAR Backups:" - find "$dir" -maxdepth 1 -name "*.oar" -type f -printf '%T@ %p\n' 2>/dev/null | \ - sort -rn | cut -d' ' -f2- | head -5 || true -} - -resolve_default_session() { - if [[ -n "$SESSION_NAME" ]]; then - printf '%s' "$SESSION_NAME" - return 0 - fi - - if [[ -n "$REGION" ]]; then - printf '%s' "$REGION" - return 0 - fi - - printf 'sim1' -} - -screen_session_exists() { - local name="$1" - screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]" -} - -send_to_screen() { - local session_name="$1" - local command_text="$2" - - screen -S "$session_name" -p 0 -X stuff "${command_text}^M" -} - -validate_sql_file() { - local file="$1" - - if [[ ! -f "$file" ]]; then - die "SQL backup file not found: $file" - fi - - # Check for gzip compression - if [[ "$file" =~ \.gz$ ]]; then - need_cmd zcat - return 0 - fi - - return 0 -} - -validate_oar_file() { - local file="$1" - - if [[ ! -f "$file" ]]; then - die "OAR backup file not found: $file" - fi - - if [[ ! "$file" =~ \.oar$ ]]; then - die "File does not appear to be an OAR backup: $file" - fi - - return 0 -} - -db_restore_mysql() { - local file sql_cmd - - [[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-restore requires --db-user --db-pass --db-name" - [[ -n "$FILE" ]] || die "db-restore requires --file" - - file="$FILE" - validate_sql_file "$file" - - need_cmd mysql - - if [[ "$file" =~ \.gz$ ]]; then - sql_cmd="zcat '$file' | mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME'" - else - sql_cmd="mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME' < '$file'" - fi - - log INFO "Database restore command:" - log INFO "$sql_cmd" - - if [[ "$DRY_RUN" == "true" ]]; then - log INFO "[DRY-RUN] Not executing database restore" - return 0 - fi - - log INFO "Restoring database from: $file" - if [[ "$file" =~ \.gz$ ]]; then - zcat "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" || die "Database restore failed" - else - mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$file" || die "Database restore failed" - fi - - log INFO "Database restore completed successfully from: $file" -} - -db_restore() { - db_restore_mysql -} - -oar_restore() { - local session_name file cmd - - [[ -n "$REGION" ]] || die "oar-restore requires --region" - [[ -n "$FILE" ]] || die "oar-restore requires --file" - - file="$FILE" - validate_oar_file "$file" - - session_name="$(resolve_default_session)" - - if ! screen_session_exists "$session_name"; then - die "Screen session not running: $session_name" - fi - - cmd="load oar $file" - log INFO "OAR restore command:" - log INFO "$cmd" - - if [[ "$DRY_RUN" == "true" ]]; then - log INFO "[DRY-RUN] Not executing OAR restore" - log INFO "To complete restore, region '$session_name' must be running and responsive" - return 0 - fi - - log INFO "Sending OAR restore command to screen session '$session_name'" - send_to_screen "$session_name" "$cmd" - log INFO "OAR restore command sent. Region import may take some time. Check session output for completion." -} - -full_restore() { - local has_sql has_oar - - has_sql=false - has_oar=false - - # Try to detect which restores to perform based on parameters - if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.(sql|gz)$ ]]; then - has_sql=true - fi - - if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.oar$ ]]; then - has_oar=true - fi - - if [[ "$has_sql" == "true" ]]; then - log INFO "Detected SQL backup file, proceeding with database restore..." - db_restore - fi - - if [[ "$has_oar" == "true" ]]; then - log INFO "Detected OAR backup file, proceeding with OAR restore..." - if [[ -n "$REGION" ]]; then - oar_restore - else - log WARN "OAR file provided but no --region specified. Skipping OAR restore." - fi - fi - - if [[ "$has_sql" == "false" && "$has_oar" == "false" ]]; then - die "full-restore requires --file with .sql/.sql.gz or .oar extension" - fi -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -DB_USER="" -DB_PASS="" -DB_NAME="" -REGION="" -SESSION_NAME="" -FILE="" -DRY_RUN="false" -PROFILE="grid-sim" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --db-user) DB_USER="$2"; shift 2 ;; - --db-pass) DB_PASS="$2"; shift 2 ;; - --db-name) DB_NAME="$2"; shift 2 ;; - --region) REGION="$2"; shift 2 ;; - --session) SESSION_NAME="$2"; shift 2 ;; - --file) FILE="$2"; shift 2 ;; - --dry-run) DRY_RUN="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed restore "$PROFILE" "$ACTION" - -case "$DRY_RUN" in - true|false) ;; - *) die "--dry-run must be true or false" ;; -esac - -log INFO "Using profile: $PROFILE" - -case "$ACTION" in - db-restore) db_restore ;; - oar-restore) oar_restore ;; - full-restore) full_restore ;; - list-backups) ensure_backup_dir; list_backups ;; - *) die "Unsupported action: $ACTION" ;; -esac +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_restore.sh [--workdir ] --action + [--db-user ] [--db-pass ] [--db-name ] + [--region ] [--session ] [--file ] + [--dry-run ] + +Examples: + osmtool_restore.sh --action list-backups --workdir /opt + osmtool_restore.sh --action db-restore --db-user opensim --db-pass secret --db-name robust --file /opt/backup/robust_robust_20260401_120000.sql +EOF + print_usage_common +} + +backup_dir() { + printf '%s' "$WORKDIR/backup" +} + +ensure_backup_dir() { + local dir + dir="$(backup_dir)" + + if [[ ! -d "$dir" ]]; then + die "Backup directory does not exist: $dir" + fi + + return 0 +} + +list_backups() { + local dir + dir="$(backup_dir)" + + if [[ ! -d "$dir" ]]; then + log INFO "No backup directory found: $dir" + return 0 + fi + + log INFO "SQL Backups:" + find "$dir" -maxdepth 1 -name "robust_*.sql*" -type f -printf '%T@ %p\n' 2>/dev/null | \ + sort -rn | cut -d' ' -f2- | head -5 || true + + log INFO "OAR Backups:" + find "$dir" -maxdepth 1 -name "*.oar" -type f -printf '%T@ %p\n' 2>/dev/null | \ + sort -rn | cut -d' ' -f2- | head -5 || true +} + +resolve_default_session() { + if [[ -n "$SESSION_NAME" ]]; then + printf '%s' "$SESSION_NAME" + return 0 + fi + + if [[ -n "$REGION" ]]; then + printf '%s' "$REGION" + return 0 + fi + + printf 'sim1' +} + +screen_session_exists() { + local name="$1" + screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]" +} + +send_to_screen() { + local session_name="$1" + local command_text="$2" + + screen -S "$session_name" -p 0 -X stuff "${command_text}^M" +} + +validate_sql_file() { + local file="$1" + + if [[ ! -f "$file" ]]; then + die "SQL backup file not found: $file" + fi + + # Check for gzip compression + if [[ "$file" =~ \.gz$ ]]; then + need_cmd zcat + return 0 + fi + + return 0 +} + +validate_oar_file() { + local file="$1" + + if [[ ! -f "$file" ]]; then + die "OAR backup file not found: $file" + fi + + if [[ ! "$file" =~ \.oar$ ]]; then + die "File does not appear to be an OAR backup: $file" + fi + + return 0 +} + +db_restore_mysql() { + local file sql_cmd + + [[ -n "$DB_USER" && -n "$DB_PASS" && -n "$DB_NAME" ]] || die "db-restore requires --db-user --db-pass --db-name" + [[ -n "$FILE" ]] || die "db-restore requires --file" + + file="$FILE" + validate_sql_file "$file" + + need_cmd mysql + + if [[ "$file" =~ \.gz$ ]]; then + sql_cmd="zcat '$file' | mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME'" + else + sql_cmd="mysql -u'$DB_USER' -p'$DB_PASS' '$DB_NAME' < '$file'" + fi + + log INFO "Database restore command:" + log INFO "$sql_cmd" + + if [[ "$DRY_RUN" == "true" ]]; then + log INFO "[DRY-RUN] Not executing database restore" + return 0 + fi + + log INFO "Restoring database from: $file" + if [[ "$file" =~ \.gz$ ]]; then + zcat "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" || die "Database restore failed" + else + mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" < "$file" || die "Database restore failed" + fi + + log INFO "Database restore completed successfully from: $file" +} + +db_restore() { + db_restore_mysql +} + +oar_restore() { + local session_name file cmd + + [[ -n "$REGION" ]] || die "oar-restore requires --region" + [[ -n "$FILE" ]] || die "oar-restore requires --file" + + file="$FILE" + validate_oar_file "$file" + + session_name="$(resolve_default_session)" + + if ! screen_session_exists "$session_name"; then + die "Screen session not running: $session_name" + fi + + cmd="load oar $file" + log INFO "OAR restore command:" + log INFO "$cmd" + + if [[ "$DRY_RUN" == "true" ]]; then + log INFO "[DRY-RUN] Not executing OAR restore" + log INFO "To complete restore, region '$session_name' must be running and responsive" + return 0 + fi + + log INFO "Sending OAR restore command to screen session '$session_name'" + send_to_screen "$session_name" "$cmd" + log INFO "OAR restore command sent. Region import may take some time. Check session output for completion." +} + +full_restore() { + local has_sql has_oar + + has_sql=false + has_oar=false + + # Try to detect which restores to perform based on parameters + if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.(sql|gz)$ ]]; then + has_sql=true + fi + + if [[ -n "$FILE" ]] && [[ "$FILE" =~ \.oar$ ]]; then + has_oar=true + fi + + if [[ "$has_sql" == "true" ]]; then + log INFO "Detected SQL backup file, proceeding with database restore..." + db_restore + fi + + if [[ "$has_oar" == "true" ]]; then + log INFO "Detected OAR backup file, proceeding with OAR restore..." + if [[ -n "$REGION" ]]; then + oar_restore + else + log WARN "OAR file provided but no --region specified. Skipping OAR restore." + fi + fi + + if [[ "$has_sql" == "false" && "$has_oar" == "false" ]]; then + die "full-restore requires --file with .sql/.sql.gz or .oar extension" + fi +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +DB_USER="" +DB_PASS="" +DB_NAME="" +REGION="" +SESSION_NAME="" +FILE="" +DRY_RUN="false" +PROFILE="grid-sim" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --db-user) DB_USER="$2"; shift 2 ;; + --db-pass) DB_PASS="$2"; shift 2 ;; + --db-name) DB_NAME="$2"; shift 2 ;; + --region) REGION="$2"; shift 2 ;; + --session) SESSION_NAME="$2"; shift 2 ;; + --file) FILE="$2"; shift 2 ;; + --dry-run) DRY_RUN="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed restore "$PROFILE" "$ACTION" + +case "$DRY_RUN" in + true|false) ;; + *) die "--dry-run must be true or false" ;; +esac + +log INFO "Using profile: $PROFILE" + +case "$ACTION" in + db-restore) db_restore ;; + oar-restore) oar_restore ;; + full-restore) full_restore ;; + list-backups) ensure_backup_dir; list_backups ;; + *) die "Unsupported action: $ACTION" ;; +esac diff --git a/modular/osmtool_smoke.sh b/modular/osmtool_smoke.sh index ef0f28a..6407feb 100644 --- a/modular/osmtool_smoke.sh +++ b/modular/osmtool_smoke.sh @@ -1,191 +1,191 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_smoke.sh [--workdir ] --action - [--target ] [--name ] - [--expected-screens ] [--wait-after-start ] [--wait-after-stop ] - [--janus-prefix ] - -Examples: - osmtool_smoke.sh --action run --profile grid-sim --workdir /opt - osmtool_smoke.sh --action run --profile robust --workdir /opt --expected-screens robustserver -EOF - print_usage_common -} - -split_csv() { - local csv="$1" - local token - local IFS=',' - read -r -a _TOKENS <<< "$csv" - for token in "${_TOKENS[@]}"; do - token="${token## }" - token="${token%% }" - [[ -n "$token" ]] && printf '%s\n' "$token" - done -} - -default_target_for_profile() { - case "$1" in - grid-sim) echo "grid" ;; - robust) echo "robust" ;; - standalone) echo "standalone" ;; - esac -} - -default_expected_screens_for_target() { - case "$1" in - grid) echo "robustserver,sim1" ;; - robust) echo "robustserver" ;; - sim1) echo "sim1" ;; - standalone) echo "standalone" ;; - janus) echo "janus_gateway" ;; - region) [[ -n "$NAME" ]] && echo "$NAME" || echo "" ;; - *) echo "" ;; - esac -} - -screen_session_exists() { - local name="$1" - screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]" -} - -verify_screens_up() { - local name failed=0 - - [[ -n "$EXPECTED_SCREENS" ]] || { - log INFO "No expected screens configured; skipping UP verification" - return 0 - } - - while IFS= read -r name; do - [[ -n "$name" ]] || continue - if screen_session_exists "$name"; then - log INFO "[SMOKE][OK] screen up: $name" - else - log ERROR "[SMOKE][FAIL] screen not running: $name" - failed=$((failed + 1)) - fi - done < <(split_csv "$EXPECTED_SCREENS") - - return "$failed" -} - -verify_screens_down() { - local name failed=0 - - [[ -n "$EXPECTED_SCREENS" ]] || { - log INFO "No expected screens configured; skipping DOWN verification" - return 0 - } - - while IFS= read -r name; do - [[ -n "$name" ]] || continue - if screen_session_exists "$name"; then - log ERROR "[SMOKE][FAIL] screen still running: $name" - failed=$((failed + 1)) - else - log INFO "[SMOKE][OK] screen down: $name" - fi - done < <(split_csv "$EXPECTED_SCREENS") - - return "$failed" -} - -run_startstop() { - local action="$1" - local -a cmd - - cmd=(bash "$ROOT_DIR/osmtool_main.sh" --module startstop --profile "$PROFILE" --workdir "$WORKDIR" --target "$TARGET" --action "$action") - if [[ "$TARGET" == "region" && -n "$NAME" ]]; then - cmd+=(--name "$NAME") - fi - if [[ -n "$JANUS_PREFIX" ]]; then - cmd+=(--janus-prefix "$JANUS_PREFIX") - fi - - "${cmd[@]}" -} - -run_smoke() { - local failures=0 - - log INFO "[SMOKE] profile=$PROFILE target=$TARGET workdir=$WORKDIR" - log INFO "[SMOKE] expected_screens=$EXPECTED_SCREENS" - - run_startstop start || failures=$((failures + 1)) - sleep "$WAIT_AFTER_START" - verify_screens_up || failures=$((failures + 1)) - - run_startstop restart || failures=$((failures + 1)) - sleep "$WAIT_AFTER_START" - verify_screens_up || failures=$((failures + 1)) - - run_startstop stop || failures=$((failures + 1)) - sleep "$WAIT_AFTER_STOP" - verify_screens_down || failures=$((failures + 1)) - - if [[ "$failures" -eq 0 ]]; then - log INFO "[SMOKE][PASS] Start/Restart/Stop smoke test successful" - return 0 - fi - - log ERROR "[SMOKE][FAIL] Smoke test failed with $failures issue group(s)" - return 1 -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" -TARGET="" -NAME="" -EXPECTED_SCREENS="" -WAIT_AFTER_START="3" -WAIT_AFTER_STOP="8" -JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --target) TARGET="$2"; shift 2 ;; - --name) NAME="$2"; shift 2 ;; - --expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;; - --wait-after-start) WAIT_AFTER_START="$2"; shift 2 ;; - --wait-after-stop) WAIT_AFTER_STOP="$2"; shift 2 ;; - --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed smoke "$PROFILE" "$ACTION" - -if [[ -z "$TARGET" ]]; then - TARGET="$(default_target_for_profile "$PROFILE")" -fi -ensure_profile_target_allowed "$PROFILE" "$TARGET" - -if [[ "$TARGET" == "region" && -z "$NAME" ]]; then - die "--name is required for --target region" -fi - -if [[ -z "$EXPECTED_SCREENS" ]]; then - EXPECTED_SCREENS="$(default_expected_screens_for_target "$TARGET")" -fi - -case "$ACTION" in - run) run_smoke ;; - *) die "Unsupported action: $ACTION" ;; +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_smoke.sh [--workdir ] --action + [--target ] [--name ] + [--expected-screens ] [--wait-after-start ] [--wait-after-stop ] + [--janus-prefix ] + +Examples: + osmtool_smoke.sh --action run --profile grid-sim --workdir /opt + osmtool_smoke.sh --action run --profile robust --workdir /opt --expected-screens robustserver +EOF + print_usage_common +} + +split_csv() { + local csv="$1" + local token + local IFS=',' + read -r -a _TOKENS <<< "$csv" + for token in "${_TOKENS[@]}"; do + token="${token## }" + token="${token%% }" + [[ -n "$token" ]] && printf '%s\n' "$token" + done +} + +default_target_for_profile() { + case "$1" in + grid-sim) echo "grid" ;; + robust) echo "robust" ;; + standalone) echo "standalone" ;; + esac +} + +default_expected_screens_for_target() { + case "$1" in + grid) echo "robustserver,sim1" ;; + robust) echo "robustserver" ;; + sim1) echo "sim1" ;; + standalone) echo "standalone" ;; + janus) echo "janus_gateway" ;; + region) [[ -n "$NAME" ]] && echo "$NAME" || echo "" ;; + *) echo "" ;; + esac +} + +screen_session_exists() { + local name="$1" + screen -list 2>/dev/null | grep -qE "\\.${name}[[:space:]]" +} + +verify_screens_up() { + local name failed=0 + + [[ -n "$EXPECTED_SCREENS" ]] || { + log INFO "No expected screens configured; skipping UP verification" + return 0 + } + + while IFS= read -r name; do + [[ -n "$name" ]] || continue + if screen_session_exists "$name"; then + log INFO "[SMOKE][OK] screen up: $name" + else + log ERROR "[SMOKE][FAIL] screen not running: $name" + failed=$((failed + 1)) + fi + done < <(split_csv "$EXPECTED_SCREENS") + + return "$failed" +} + +verify_screens_down() { + local name failed=0 + + [[ -n "$EXPECTED_SCREENS" ]] || { + log INFO "No expected screens configured; skipping DOWN verification" + return 0 + } + + while IFS= read -r name; do + [[ -n "$name" ]] || continue + if screen_session_exists "$name"; then + log ERROR "[SMOKE][FAIL] screen still running: $name" + failed=$((failed + 1)) + else + log INFO "[SMOKE][OK] screen down: $name" + fi + done < <(split_csv "$EXPECTED_SCREENS") + + return "$failed" +} + +run_startstop() { + local action="$1" + local -a cmd + + cmd=(bash "$ROOT_DIR/osmtool_main.sh" --module startstop --profile "$PROFILE" --workdir "$WORKDIR" --target "$TARGET" --action "$action") + if [[ "$TARGET" == "region" && -n "$NAME" ]]; then + cmd+=(--name "$NAME") + fi + if [[ -n "$JANUS_PREFIX" ]]; then + cmd+=(--janus-prefix "$JANUS_PREFIX") + fi + + "${cmd[@]}" +} + +run_smoke() { + local failures=0 + + log INFO "[SMOKE] profile=$PROFILE target=$TARGET workdir=$WORKDIR" + log INFO "[SMOKE] expected_screens=$EXPECTED_SCREENS" + + run_startstop start || failures=$((failures + 1)) + sleep "$WAIT_AFTER_START" + verify_screens_up || failures=$((failures + 1)) + + run_startstop restart || failures=$((failures + 1)) + sleep "$WAIT_AFTER_START" + verify_screens_up || failures=$((failures + 1)) + + run_startstop stop || failures=$((failures + 1)) + sleep "$WAIT_AFTER_STOP" + verify_screens_down || failures=$((failures + 1)) + + if [[ "$failures" -eq 0 ]]; then + log INFO "[SMOKE][PASS] Start/Restart/Stop smoke test successful" + return 0 + fi + + log ERROR "[SMOKE][FAIL] Smoke test failed with $failures issue group(s)" + return 1 +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" +TARGET="" +NAME="" +EXPECTED_SCREENS="" +WAIT_AFTER_START="3" +WAIT_AFTER_STOP="8" +JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --target) TARGET="$2"; shift 2 ;; + --name) NAME="$2"; shift 2 ;; + --expected-screens) EXPECTED_SCREENS="$2"; shift 2 ;; + --wait-after-start) WAIT_AFTER_START="$2"; shift 2 ;; + --wait-after-stop) WAIT_AFTER_STOP="$2"; shift 2 ;; + --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed smoke "$PROFILE" "$ACTION" + +if [[ -z "$TARGET" ]]; then + TARGET="$(default_target_for_profile "$PROFILE")" +fi +ensure_profile_target_allowed "$PROFILE" "$TARGET" + +if [[ "$TARGET" == "region" && -z "$NAME" ]]; then + die "--name is required for --target region" +fi + +if [[ -z "$EXPECTED_SCREENS" ]]; then + EXPECTED_SCREENS="$(default_expected_screens_for_target "$TARGET")" +fi + +case "$ACTION" in + run) run_smoke ;; + *) die "Unsupported action: $ACTION" ;; esac \ No newline at end of file diff --git a/modular/osmtool_startstop.sh b/modular/osmtool_startstop.sh index 39d588e..7a7c93d 100644 --- a/modular/osmtool_startstop.sh +++ b/modular/osmtool_startstop.sh @@ -1,395 +1,395 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -msgf() { - local key="$1" - shift - # shellcheck disable=SC2059 - printf "$(msg "$key")" "$@" -} - -usage() { - cat <<'EOF' -Usage: - osmtool_startstop.sh [--workdir ] [--profile ] --target --action [--name ] - [--janus-prefix ] - -Examples: - osmtool_startstop.sh --profile grid-sim --target grid --action start --workdir /opt - osmtool_startstop.sh --profile robust --target robust --action restart --workdir /opt -EOF - print_usage_common -} - -run_screen_cmd() { - local screen_name="$1" - local command_text="$2" - screen -S "$screen_name" -p 0 -X stuff "${command_text}^M" -} - -screen_session_exists() { - local screen_name="$1" - screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]" -} - -stop_screen_session() { - local screen_name="$1" - local grace_seconds="${2:-$SIMULATOR_STOP_WAIT}" - - if ! screen_session_exists "$screen_name"; then - log INFO "$(msgf STARTSTOP_NOT_RUNNING "$screen_name")" - return 0 - fi - - run_screen_cmd "$screen_name" "shutdown" - log INFO "$(msgf STARTSTOP_SENT_SHUTDOWN "$screen_name")" - sleep "$grace_seconds" - - if screen_session_exists "$screen_name"; then - log INFO "$(msgf STARTSTOP_FORCE_QUIT "$screen_name")" - screen -S "$screen_name" -X quit || true - sleep 1 - fi - - if screen_session_exists "$screen_name"; then - log ERROR "$(msgf STARTSTOP_STOP_FAILED "$screen_name")" - return 1 - fi - - log INFO "$(msgf STARTSTOP_STOPPED "$screen_name")" - return 0 -} - -ensure_janus_ready() { - local marker="$JANUS_PREFIX/.osmtool_janus_ready" - local core_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg" - local core_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.cfg" - local http_cfg="$JANUS_PREFIX/etc/janus/janus.transport.http.jcfg" - local http_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.transport.http.cfg" - - [[ -f "$JANUS_PREFIX/bin/janus" ]] || die "$(msgf STARTSTOP_JANUS_BIN_MISSING "$JANUS_PREFIX/bin/janus")" - - if [[ ! -f "$core_cfg" && ! -f "$core_cfg_legacy" ]]; then - die "$(msgf STARTSTOP_JANUS_CORE_CFG_MISSING "$JANUS_PREFIX/etc/janus")" - fi - - if [[ ! -f "$http_cfg" && ! -f "$http_cfg_legacy" ]]; then - die "$(msgf STARTSTOP_JANUS_HTTP_CFG_MISSING "$JANUS_PREFIX/etc/janus")" - fi - - [[ -f "$marker" ]] || log INFO "$(msgf STARTSTOP_JANUS_MARKER_MISSING "$marker")" -} - -janus_service_action() { - local action="$1" - local janus_bin janus_cfg - - janus_bin="$JANUS_PREFIX/bin/janus" - janus_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg" - [[ -f "$janus_cfg" ]] || janus_cfg="$JANUS_PREFIX/etc/janus/janus.cfg" - - if command -v systemctl >/dev/null 2>&1; then - if systemctl list-unit-files 2>/dev/null | grep -q '^janus\.service'; then - sudo systemctl "$action" janus - return 0 - fi - fi - - if command -v service >/dev/null 2>&1; then - if service --status-all 2>/dev/null | grep -q janus; then - sudo service janus "$action" - return 0 - fi - fi - - if [[ -x "$WORKDIR/janus.sh" ]]; then - "$WORKDIR/janus.sh" "${action}_janus" || "$WORKDIR/janus.sh" "$action" - return 0 - fi - - if [[ -x "$WORKDIR/janus/janus.sh" ]]; then - "$WORKDIR/janus/janus.sh" "${action}_janus" || "$WORKDIR/janus/janus.sh" "$action" - return 0 - fi - - # Fallback: control Janus directly from installed binary. - if [[ -x "$janus_bin" ]]; then - case "$action" in - start) - if pgrep -f "$janus_bin" >/dev/null 2>&1; then - log INFO "$(msg STARTSTOP_JANUS_ALREADY_RUNNING)" - return 0 - fi - if command -v screen >/dev/null 2>&1; then - screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg" - else - nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 & - fi - return 0 - ;; - stop) - pkill -f "$janus_bin" >/dev/null 2>&1 || true - if command -v screen >/dev/null 2>&1; then - if screen -list | grep -q "janus_gateway"; then - screen -S janus_gateway -X quit || true - fi - fi - return 0 - ;; - restart) - pkill -f "$janus_bin" >/dev/null 2>&1 || true - sleep 1 - if command -v screen >/dev/null 2>&1; then - screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg" - else - nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 & - fi - return 0 - ;; - esac - fi - - die "$(msg STARTSTOP_JANUS_CONTROL_NOT_CONFIGURED)" -} - -require_ini() { - local bin_dir="$1" - local ini_file="$2" - local label="$3" - - if [[ ! -f "$bin_dir/$ini_file" ]]; then - die "$(msgf STARTSTOP_REQUIRED_INI_MISSING "$label" "$bin_dir/$ini_file")" - fi -} - -screen_start() { - local screen_name="$1" - local bin_dir="$2" - local dll="$3" - local pat="\\.${screen_name}[[:space:]]" - - if screen -list 2>/dev/null | grep -qE "$pat"; then - log INFO "$(msgf STARTSTOP_ALREADY_RUNNING "$screen_name")" - return 0 - fi - - log INFO "$(msgf STARTSTOP_STARTING_FROM "$screen_name" "$bin_dir")" - (cd "$bin_dir" && screen -fa -S "$screen_name" -d -U -m dotnet "$dll") - sleep 0.5 - - if screen -list 2>/dev/null | grep -qE "$pat"; then - log INFO "$(msgf STARTSTOP_STARTED_OK "$screen_name")" - return 0 - else - log ERROR "$(msgf STARTSTOP_START_FAILED "$screen_name")" - return 1 - fi -} - -list_sim_names_asc() { - local sim_dir sim_name - local sim_names=() - - shopt -s nullglob - for sim_dir in "$WORKDIR"/sim[0-9]*; do - [[ -d "$sim_dir/bin" ]] || continue - sim_name="$(basename "$sim_dir")" - [[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue - sim_names+=("$sim_name") - done - shopt -u nullglob - - if [[ ${#sim_names[@]} -eq 0 ]]; then - return 0 - fi - - printf '%s\n' "${sim_names[@]}" | sort -V -} - -start_grid() { - local sim_name - local sim_count=0 - - log INFO "$(msgf STARTSTOP_GRID_STARTING "$WORKDIR")" - - [[ -d "$WORKDIR/robust/bin" ]] || die "$(msgf STARTSTOP_ROBUST_DIR_MISSING "$WORKDIR/robust/bin")" - require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer" - screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll" || die "$(msg STARTSTOP_ROBUST_START_FAILED)" - sleep "$ROBUSTSERVER_START_WAIT" - - [[ -f "$WORKDIR/robust/bin/MoneyServer.dll" ]] || die "$(msgf STARTSTOP_MONEY_DLL_MISSING "$WORKDIR/robust/bin/MoneyServer.dll")" - [[ -f "$WORKDIR/robust/bin/MoneyServer.ini" ]] || die "$(msgf STARTSTOP_MONEY_INI_MISSING "$WORKDIR/robust/bin/MoneyServer.ini")" - screen_start "moneyserver" "$WORKDIR/robust/bin" "MoneyServer.dll" || die "$(msg STARTSTOP_MONEY_START_FAILED)" - sleep "$MONEYSERVER_START_WAIT" - - while IFS= read -r sim_name; do - [[ -n "$sim_name" ]] || continue - require_ini "$WORKDIR/$sim_name/bin" "OpenSim.ini" "$sim_name" - screen_start "$sim_name" "$WORKDIR/$sim_name/bin" "OpenSim.dll" || die "$(msgf STARTSTOP_SIM_START_FAILED "$sim_name")" - sleep "$SIMULATOR_START_WAIT" - ((sim_count+=1)) - done < <(list_sim_names_asc) - - [[ "$sim_count" -gt 0 ]] || die "$(msgf STARTSTOP_NO_SIM_FOUND "$WORKDIR")" -} - -stop_grid() { - local sim_names=() - local idx - - log INFO "$(msg STARTSTOP_GRID_STOPPING)" - - mapfile -t sim_names < <(list_sim_names_asc) - for ((idx=${#sim_names[@]}-1; idx>=0; idx--)); do - stop_screen_session "${sim_names[$idx]}" "$SIMULATOR_STOP_WAIT" || true - done - - stop_screen_session "moneyserver" "$MONEYSERVER_STOP_WAIT" || true - stop_screen_session "robustserver" "$ROBUSTSERVER_STOP_WAIT" || true -} - -logclean_grid() { - log INFO "$(msg STARTSTOP_LOGCLEAN_BEGIN)" - - if [[ -d "$WORKDIR/robust/bin" ]]; then - rm -f "$WORKDIR/robust/bin/"*.log - log INFO "$(msgf STARTSTOP_LOGS_DELETED "$WORKDIR/robust/bin")" - fi - - local sim_dir sim_name - shopt -s nullglob - for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do - sim_name="$(basename "$(dirname "$sim_dir")")" - [[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue - rm -f "$sim_dir/"*.log - log INFO "$(msgf STARTSTOP_LOGS_DELETED "$sim_dir")" - done - shopt -u nullglob - - log INFO "$(msg STARTSTOP_LOGCLEAN_DONE)" -} - -restart_grid() { - stop_grid - sleep "$SIMULATOR_STOP_WAIT" - logclean_grid - sleep "$SIMULATOR_START_WAIT" - start_grid - log INFO "$(msg STARTSTOP_ACTIVE_SESSIONS)" - screen -ls 2>/dev/null || log INFO "$(msg STARTSTOP_NO_SESSIONS)" -} - -start_single() { - local target="$1" - case "$target" in - robust) - require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer" - screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll" - ;; - sim1) - require_ini "$WORKDIR/sim1/bin" "OpenSim.ini" "sim1" - screen_start "sim1" "$WORKDIR/sim1/bin" "OpenSim.dll" - ;; - standalone) - require_ini "$WORKDIR/standalone/bin" "OpenSim.ini" "standalone" - screen_start "standalone" "$WORKDIR/standalone/bin" "OpenSim.dll" - ;; - janus) - ensure_janus_ready - janus_service_action start - ;; - region) - [[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)" - require_ini "$WORKDIR/${NAME}/bin" "OpenSim.ini" "$NAME" - screen_start "$NAME" "$WORKDIR/${NAME}/bin" "OpenSim.dll" - ;; - *) - die "$(msgf STARTSTOP_UNSUPPORTED_START_TARGET "$target")" - ;; - esac -} - -stop_single() { - local target="$1" - case "$target" in - robust) - stop_screen_session "robustserver" - ;; - sim1) - stop_screen_session "sim1" - ;; - standalone) - stop_screen_session "standalone" - ;; - janus) janus_service_action stop ;; - region) - [[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)" - stop_screen_session "$NAME" - ;; - *) die "$(msgf STARTSTOP_UNSUPPORTED_STOP_TARGET "$target")" ;; - esac -} - -WORKDIR="$DEFAULT_WORKDIR" -TARGET="" -ACTION="" -NAME="" -PROFILE="grid-sim" -JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}" - -# Wartezeiten (Sekunden) – entsprechen den bewährten Werten aus osmtool.sh -SIMULATOR_STOP_WAIT="${SIMULATOR_STOP_WAIT:-15}" -MONEYSERVER_STOP_WAIT="${MONEYSERVER_STOP_WAIT:-30}" -ROBUSTSERVER_STOP_WAIT="${ROBUSTSERVER_STOP_WAIT:-30}" -SIMULATOR_START_WAIT="${SIMULATOR_START_WAIT:-15}" -MONEYSERVER_START_WAIT="${MONEYSERVER_START_WAIT:-30}" -ROBUSTSERVER_START_WAIT="${ROBUSTSERVER_START_WAIT:-30}" - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; - --target) TARGET="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --name) NAME="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "$(msgf ERR_UNKNOWN_OPTION "$1")" ;; - esac -done - -[[ -n "$TARGET" ]] || die "$(msg ERR_MISSING_TARGET)" -[[ -n "$ACTION" ]] || die "$(msg ERR_MISSING_ACTION)" -validate_profile "$PROFILE" -ensure_profile_action_allowed startstop "$PROFILE" "$ACTION" -ensure_profile_target_allowed "$PROFILE" "$TARGET" - -if [[ "$TARGET" == "janus" && "$ACTION" != "stop" ]]; then - ensure_janus_ready -fi - -log INFO "$(msgf INFO_USING_PROFILE "$PROFILE")" - -if [[ "$TARGET" == "grid" ]]; then - case "$ACTION" in - start) start_grid ;; - stop) stop_grid ;; - restart) restart_grid ;; - *) die "$(msgf ERR_UNSUPPORTED_GRID_ACTION "$ACTION")" ;; - esac -else - case "$ACTION" in - start) start_single "$TARGET" ;; - stop) stop_single "$TARGET" ;; - restart) - stop_single "$TARGET" - sleep 3 - start_single "$TARGET" - ;; - *) die "$(msgf ERR_UNSUPPORTED_ACTION "$ACTION")" ;; - esac -fi +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +msgf() { + local key="$1" + shift + # shellcheck disable=SC2059 + printf "$(msg "$key")" "$@" +} + +usage() { + cat <<'EOF' +Usage: + osmtool_startstop.sh [--workdir ] [--profile ] --target --action [--name ] + [--janus-prefix ] + +Examples: + osmtool_startstop.sh --profile grid-sim --target grid --action start --workdir /opt + osmtool_startstop.sh --profile robust --target robust --action restart --workdir /opt +EOF + print_usage_common +} + +run_screen_cmd() { + local screen_name="$1" + local command_text="$2" + screen -S "$screen_name" -p 0 -X stuff "${command_text}^M" +} + +screen_session_exists() { + local screen_name="$1" + screen -list 2>/dev/null | grep -qE "\\.${screen_name}[[:space:]]" +} + +stop_screen_session() { + local screen_name="$1" + local grace_seconds="${2:-$SIMULATOR_STOP_WAIT}" + + if ! screen_session_exists "$screen_name"; then + log INFO "$(msgf STARTSTOP_NOT_RUNNING "$screen_name")" + return 0 + fi + + run_screen_cmd "$screen_name" "shutdown" + log INFO "$(msgf STARTSTOP_SENT_SHUTDOWN "$screen_name")" + sleep "$grace_seconds" + + if screen_session_exists "$screen_name"; then + log INFO "$(msgf STARTSTOP_FORCE_QUIT "$screen_name")" + screen -S "$screen_name" -X quit || true + sleep 1 + fi + + if screen_session_exists "$screen_name"; then + log ERROR "$(msgf STARTSTOP_STOP_FAILED "$screen_name")" + return 1 + fi + + log INFO "$(msgf STARTSTOP_STOPPED "$screen_name")" + return 0 +} + +ensure_janus_ready() { + local marker="$JANUS_PREFIX/.osmtool_janus_ready" + local core_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg" + local core_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.cfg" + local http_cfg="$JANUS_PREFIX/etc/janus/janus.transport.http.jcfg" + local http_cfg_legacy="$JANUS_PREFIX/etc/janus/janus.transport.http.cfg" + + [[ -f "$JANUS_PREFIX/bin/janus" ]] || die "$(msgf STARTSTOP_JANUS_BIN_MISSING "$JANUS_PREFIX/bin/janus")" + + if [[ ! -f "$core_cfg" && ! -f "$core_cfg_legacy" ]]; then + die "$(msgf STARTSTOP_JANUS_CORE_CFG_MISSING "$JANUS_PREFIX/etc/janus")" + fi + + if [[ ! -f "$http_cfg" && ! -f "$http_cfg_legacy" ]]; then + die "$(msgf STARTSTOP_JANUS_HTTP_CFG_MISSING "$JANUS_PREFIX/etc/janus")" + fi + + [[ -f "$marker" ]] || log INFO "$(msgf STARTSTOP_JANUS_MARKER_MISSING "$marker")" +} + +janus_service_action() { + local action="$1" + local janus_bin janus_cfg + + janus_bin="$JANUS_PREFIX/bin/janus" + janus_cfg="$JANUS_PREFIX/etc/janus/janus.jcfg" + [[ -f "$janus_cfg" ]] || janus_cfg="$JANUS_PREFIX/etc/janus/janus.cfg" + + if command -v systemctl >/dev/null 2>&1; then + if systemctl list-unit-files 2>/dev/null | grep -q '^janus\.service'; then + sudo systemctl "$action" janus + return 0 + fi + fi + + if command -v service >/dev/null 2>&1; then + if service --status-all 2>/dev/null | grep -q janus; then + sudo service janus "$action" + return 0 + fi + fi + + if [[ -x "$WORKDIR/janus.sh" ]]; then + "$WORKDIR/janus.sh" "${action}_janus" || "$WORKDIR/janus.sh" "$action" + return 0 + fi + + if [[ -x "$WORKDIR/janus/janus.sh" ]]; then + "$WORKDIR/janus/janus.sh" "${action}_janus" || "$WORKDIR/janus/janus.sh" "$action" + return 0 + fi + + # Fallback: control Janus directly from installed binary. + if [[ -x "$janus_bin" ]]; then + case "$action" in + start) + if pgrep -f "$janus_bin" >/dev/null 2>&1; then + log INFO "$(msg STARTSTOP_JANUS_ALREADY_RUNNING)" + return 0 + fi + if command -v screen >/dev/null 2>&1; then + screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg" + else + nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 & + fi + return 0 + ;; + stop) + pkill -f "$janus_bin" >/dev/null 2>&1 || true + if command -v screen >/dev/null 2>&1; then + if screen -list | grep -q "janus_gateway"; then + screen -S janus_gateway -X quit || true + fi + fi + return 0 + ;; + restart) + pkill -f "$janus_bin" >/dev/null 2>&1 || true + sleep 1 + if command -v screen >/dev/null 2>&1; then + screen -fa -S janus_gateway -d -U -m "$janus_bin" -C "$janus_cfg" + else + nohup "$janus_bin" -C "$janus_cfg" >/tmp/janus.log 2>&1 & + fi + return 0 + ;; + esac + fi + + die "$(msg STARTSTOP_JANUS_CONTROL_NOT_CONFIGURED)" +} + +require_ini() { + local bin_dir="$1" + local ini_file="$2" + local label="$3" + + if [[ ! -f "$bin_dir/$ini_file" ]]; then + die "$(msgf STARTSTOP_REQUIRED_INI_MISSING "$label" "$bin_dir/$ini_file")" + fi +} + +screen_start() { + local screen_name="$1" + local bin_dir="$2" + local dll="$3" + local pat="\\.${screen_name}[[:space:]]" + + if screen -list 2>/dev/null | grep -qE "$pat"; then + log INFO "$(msgf STARTSTOP_ALREADY_RUNNING "$screen_name")" + return 0 + fi + + log INFO "$(msgf STARTSTOP_STARTING_FROM "$screen_name" "$bin_dir")" + (cd "$bin_dir" && screen -fa -S "$screen_name" -d -U -m dotnet "$dll") + sleep 0.5 + + if screen -list 2>/dev/null | grep -qE "$pat"; then + log INFO "$(msgf STARTSTOP_STARTED_OK "$screen_name")" + return 0 + else + log ERROR "$(msgf STARTSTOP_START_FAILED "$screen_name")" + return 1 + fi +} + +list_sim_names_asc() { + local sim_dir sim_name + local sim_names=() + + shopt -s nullglob + for sim_dir in "$WORKDIR"/sim[0-9]*; do + [[ -d "$sim_dir/bin" ]] || continue + sim_name="$(basename "$sim_dir")" + [[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue + sim_names+=("$sim_name") + done + shopt -u nullglob + + if [[ ${#sim_names[@]} -eq 0 ]]; then + return 0 + fi + + printf '%s\n' "${sim_names[@]}" | sort -V +} + +start_grid() { + local sim_name + local sim_count=0 + + log INFO "$(msgf STARTSTOP_GRID_STARTING "$WORKDIR")" + + [[ -d "$WORKDIR/robust/bin" ]] || die "$(msgf STARTSTOP_ROBUST_DIR_MISSING "$WORKDIR/robust/bin")" + require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer" + screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll" || die "$(msg STARTSTOP_ROBUST_START_FAILED)" + sleep "$ROBUSTSERVER_START_WAIT" + + [[ -f "$WORKDIR/robust/bin/MoneyServer.dll" ]] || die "$(msgf STARTSTOP_MONEY_DLL_MISSING "$WORKDIR/robust/bin/MoneyServer.dll")" + [[ -f "$WORKDIR/robust/bin/MoneyServer.ini" ]] || die "$(msgf STARTSTOP_MONEY_INI_MISSING "$WORKDIR/robust/bin/MoneyServer.ini")" + screen_start "moneyserver" "$WORKDIR/robust/bin" "MoneyServer.dll" || die "$(msg STARTSTOP_MONEY_START_FAILED)" + sleep "$MONEYSERVER_START_WAIT" + + while IFS= read -r sim_name; do + [[ -n "$sim_name" ]] || continue + require_ini "$WORKDIR/$sim_name/bin" "OpenSim.ini" "$sim_name" + screen_start "$sim_name" "$WORKDIR/$sim_name/bin" "OpenSim.dll" || die "$(msgf STARTSTOP_SIM_START_FAILED "$sim_name")" + sleep "$SIMULATOR_START_WAIT" + ((sim_count+=1)) + done < <(list_sim_names_asc) + + [[ "$sim_count" -gt 0 ]] || die "$(msgf STARTSTOP_NO_SIM_FOUND "$WORKDIR")" +} + +stop_grid() { + local sim_names=() + local idx + + log INFO "$(msg STARTSTOP_GRID_STOPPING)" + + mapfile -t sim_names < <(list_sim_names_asc) + for ((idx=${#sim_names[@]}-1; idx>=0; idx--)); do + stop_screen_session "${sim_names[$idx]}" "$SIMULATOR_STOP_WAIT" || true + done + + stop_screen_session "moneyserver" "$MONEYSERVER_STOP_WAIT" || true + stop_screen_session "robustserver" "$ROBUSTSERVER_STOP_WAIT" || true +} + +logclean_grid() { + log INFO "$(msg STARTSTOP_LOGCLEAN_BEGIN)" + + if [[ -d "$WORKDIR/robust/bin" ]]; then + rm -f "$WORKDIR/robust/bin/"*.log + log INFO "$(msgf STARTSTOP_LOGS_DELETED "$WORKDIR/robust/bin")" + fi + + local sim_dir sim_name + shopt -s nullglob + for sim_dir in "$WORKDIR"/sim[0-9]*/bin; do + sim_name="$(basename "$(dirname "$sim_dir")")" + [[ "$sim_name" =~ ^sim[0-9]+$ ]] || continue + rm -f "$sim_dir/"*.log + log INFO "$(msgf STARTSTOP_LOGS_DELETED "$sim_dir")" + done + shopt -u nullglob + + log INFO "$(msg STARTSTOP_LOGCLEAN_DONE)" +} + +restart_grid() { + stop_grid + sleep "$SIMULATOR_STOP_WAIT" + logclean_grid + sleep "$SIMULATOR_START_WAIT" + start_grid + log INFO "$(msg STARTSTOP_ACTIVE_SESSIONS)" + screen -ls 2>/dev/null || log INFO "$(msg STARTSTOP_NO_SESSIONS)" +} + +start_single() { + local target="$1" + case "$target" in + robust) + require_ini "$WORKDIR/robust/bin" "Robust.ini" "RobustServer" + screen_start "robustserver" "$WORKDIR/robust/bin" "Robust.dll" + ;; + sim1) + require_ini "$WORKDIR/sim1/bin" "OpenSim.ini" "sim1" + screen_start "sim1" "$WORKDIR/sim1/bin" "OpenSim.dll" + ;; + standalone) + require_ini "$WORKDIR/standalone/bin" "OpenSim.ini" "standalone" + screen_start "standalone" "$WORKDIR/standalone/bin" "OpenSim.dll" + ;; + janus) + ensure_janus_ready + janus_service_action start + ;; + region) + [[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)" + require_ini "$WORKDIR/${NAME}/bin" "OpenSim.ini" "$NAME" + screen_start "$NAME" "$WORKDIR/${NAME}/bin" "OpenSim.dll" + ;; + *) + die "$(msgf STARTSTOP_UNSUPPORTED_START_TARGET "$target")" + ;; + esac +} + +stop_single() { + local target="$1" + case "$target" in + robust) + stop_screen_session "robustserver" + ;; + sim1) + stop_screen_session "sim1" + ;; + standalone) + stop_screen_session "standalone" + ;; + janus) janus_service_action stop ;; + region) + [[ -n "$NAME" ]] || die "$(msg STARTSTOP_NAME_REQUIRED)" + stop_screen_session "$NAME" + ;; + *) die "$(msgf STARTSTOP_UNSUPPORTED_STOP_TARGET "$target")" ;; + esac +} + +WORKDIR="$DEFAULT_WORKDIR" +TARGET="" +ACTION="" +NAME="" +PROFILE="grid-sim" +JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}" + +# Wartezeiten (Sekunden) – entsprechen den bewährten Werten aus osmtool.sh +SIMULATOR_STOP_WAIT="${SIMULATOR_STOP_WAIT:-15}" +MONEYSERVER_STOP_WAIT="${MONEYSERVER_STOP_WAIT:-30}" +ROBUSTSERVER_STOP_WAIT="${ROBUSTSERVER_STOP_WAIT:-30}" +SIMULATOR_START_WAIT="${SIMULATOR_START_WAIT:-15}" +MONEYSERVER_START_WAIT="${MONEYSERVER_START_WAIT:-30}" +ROBUSTSERVER_START_WAIT="${ROBUSTSERVER_START_WAIT:-30}" + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; + --target) TARGET="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --name) NAME="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "$(msgf ERR_UNKNOWN_OPTION "$1")" ;; + esac +done + +[[ -n "$TARGET" ]] || die "$(msg ERR_MISSING_TARGET)" +[[ -n "$ACTION" ]] || die "$(msg ERR_MISSING_ACTION)" +validate_profile "$PROFILE" +ensure_profile_action_allowed startstop "$PROFILE" "$ACTION" +ensure_profile_target_allowed "$PROFILE" "$TARGET" + +if [[ "$TARGET" == "janus" && "$ACTION" != "stop" ]]; then + ensure_janus_ready +fi + +log INFO "$(msgf INFO_USING_PROFILE "$PROFILE")" + +if [[ "$TARGET" == "grid" ]]; then + case "$ACTION" in + start) start_grid ;; + stop) stop_grid ;; + restart) restart_grid ;; + *) die "$(msgf ERR_UNSUPPORTED_GRID_ACTION "$ACTION")" ;; + esac +else + case "$ACTION" in + start) start_single "$TARGET" ;; + stop) stop_single "$TARGET" ;; + restart) + stop_single "$TARGET" + sleep 3 + start_single "$TARGET" + ;; + *) die "$(msgf ERR_UNSUPPORTED_ACTION "$ACTION")" ;; + esac +fi diff --git a/modular/osmtool_update.sh b/modular/osmtool_update.sh index eff702b..190d89e 100644 --- a/modular/osmtool_update.sh +++ b/modular/osmtool_update.sh @@ -1,262 +1,262 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -# shellcheck source=/dev/null -source "$SCRIPT_DIR/osmtool_core.sh" - -usage() { - cat <<'EOF' -Usage: - osmtool_update.sh [--workdir ] --action - [--opensim-dir ] [--opensim-repo ] [--opensim-branch ] [--repo-mode ] - [--tsassets-dir ] [--currency-dir ] [--data-backup-dir ] - [--deploy-binaries ] [--legacy-patch-dir ] - [--janus-prefix ] [--janus-src ] [--public-host ] [--http-port ] - [--admin-port ] [--rtp-range ] [--enable-admin ] - [--api-secret ] [--admin-secret ] [--label ] [--dry-run ] - -Examples: - osmtool_update.sh --action create-rollback --workdir /opt --label pre_update - osmtool_update.sh --action update-opensim --workdir /opt --dry-run true -EOF - print_usage_common -} - -timestamp() { - date '+%Y%m%d_%H%M%S' -} - -rollback_dir() { - printf '%s' "$WORKDIR/rollback" -} - -ensure_rollback_dir() { - local dir - dir="$(rollback_dir)" - - if mkdir -p "$dir" 2>/dev/null; then - return 0 - fi - - sudo mkdir -p "$dir" - sudo chown "$(id -u):$(id -g)" "$dir" -} - -path_relative_to_root() { - local path="$1" - printf '%s' "${path#/}" -} - -append_snapshot_path() { - local path="$1" - - [[ -e "$path" ]] || return 0 - SNAPSHOT_PATHS+=("$(path_relative_to_root "$path")") -} - -build_opensim_snapshot_paths() { - local sim_dir - - SNAPSHOT_PATHS=() - append_snapshot_path "$OPENSIM_DIR" - append_snapshot_path "$WORKDIR/robust/bin" - append_snapshot_path "$WORKDIR/standalone/bin" - - shopt -s nullglob - for sim_dir in "$WORKDIR"/sim*; do - append_snapshot_path "$sim_dir/bin" - done - shopt -u nullglob -} - -build_janus_snapshot_paths() { - SNAPSHOT_PATHS=() - append_snapshot_path "$JANUS_PREFIX" - append_snapshot_path "$JANUS_SRC" -} - -create_snapshot_archive() { - local scope="$1" - shift - local archive_name archive_path manifest_path - local -a paths=("$@") - - ensure_rollback_dir - - if [[ ${#paths[@]} -eq 0 ]]; then - log WARN "No existing paths found for rollback scope: $scope" - return 0 - fi - - archive_name="${scope}_$(timestamp)" - if [[ -n "$LABEL" ]]; then - archive_name="${archive_name}_${LABEL}" - fi - - archive_path="$(rollback_dir)/${archive_name}.tar.gz" - manifest_path="$(rollback_dir)/${archive_name}.manifest" - - log INFO "Creating rollback archive: $archive_path" - printf '%s\n' "${paths[@]}" > "$manifest_path" - - if [[ "$DRY_RUN" == "true" ]]; then - log INFO "[DRY-RUN] Would archive paths listed in: $manifest_path" - return 0 - fi - - tar -czf "$archive_path" -C / "${paths[@]}" - log INFO "Rollback archive created: $archive_path" - log INFO "Rollback manifest created: $manifest_path" -} - -run_install_action() { - local install_action="$1" - local -a cmd - - cmd=("$SCRIPT_DIR/osmtool_install.sh" --profile "$PROFILE" --workdir "$WORKDIR" --action "$install_action") - - [[ -n "$OPENSIM_DIR" ]] && cmd+=(--opensim-dir "$OPENSIM_DIR") - [[ -n "$OPENSIM_REPO" ]] && cmd+=(--opensim-repo "$OPENSIM_REPO") - [[ -n "$OPENSIM_BRANCH" ]] && cmd+=(--opensim-branch "$OPENSIM_BRANCH") - [[ -n "$REPO_MODE" ]] && cmd+=(--repo-mode "$REPO_MODE") - [[ -n "$TSASSETS_DIR" ]] && cmd+=(--tsassets-dir "$TSASSETS_DIR") - [[ -n "$CURRENCY_DIR" ]] && cmd+=(--currency-dir "$CURRENCY_DIR") - [[ -n "$DATA_BACKUP_DIR" ]] && cmd+=(--data-backup-dir "$DATA_BACKUP_DIR") - [[ -n "$DEPLOY_BINARIES" ]] && cmd+=(--deploy-binaries "$DEPLOY_BINARIES") - [[ -n "$LEGACY_PATCH_DIR" ]] && cmd+=(--legacy-patch-dir "$LEGACY_PATCH_DIR") - [[ -n "$JANUS_PREFIX" ]] && cmd+=(--janus-prefix "$JANUS_PREFIX") - [[ -n "$JANUS_SRC" ]] && cmd+=(--janus-src "$JANUS_SRC") - [[ -n "$PUBLIC_HOST" ]] && cmd+=(--public-host "$PUBLIC_HOST") - [[ -n "$HTTP_PORT" ]] && cmd+=(--http-port "$HTTP_PORT") - [[ -n "$ADMIN_PORT" ]] && cmd+=(--admin-port "$ADMIN_PORT") - [[ -n "$RTP_RANGE" ]] && cmd+=(--rtp-range "$RTP_RANGE") - [[ -n "$ENABLE_ADMIN" ]] && cmd+=(--enable-admin "$ENABLE_ADMIN") - [[ -n "$API_SECRET" ]] && cmd+=(--api-secret "$API_SECRET") - [[ -n "$ADMIN_SECRET" ]] && cmd+=(--admin-secret "$ADMIN_SECRET") - - log INFO "Delegating update to install action: $install_action" - if [[ "$DRY_RUN" == "true" ]]; then - printf -v rendered '%q ' "${cmd[@]}" - log INFO "[DRY-RUN] $rendered" - return 0 - fi - - "${cmd[@]}" -} - -create_rollback() { - build_opensim_snapshot_paths - create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}" - build_janus_snapshot_paths - create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}" -} - -list_rollbacks() { - local dir - dir="$(rollback_dir)" - - if [[ ! -d "$dir" ]]; then - log INFO "No rollback directory found: $dir" - return 0 - fi - - find "$dir" -maxdepth 1 -type f \( -name '*.tar.gz' -o -name '*.manifest' \) -printf '%T@ %p\n' 2>/dev/null | \ - sort -rn | cut -d' ' -f2- -} - -update_opensim() { - build_opensim_snapshot_paths - create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}" - run_install_action install-opensim -} - -update_janus() { - build_janus_snapshot_paths - create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}" - run_install_action install-janus -} - -full_update() { - update_opensim - update_janus -} - -WORKDIR="$DEFAULT_WORKDIR" -ACTION="" -PROFILE="grid-sim" -OPENSIM_DIR="" -OPENSIM_REPO="" -OPENSIM_BRANCH="" -REPO_MODE="update" -TSASSETS_DIR="" -CURRENCY_DIR="" -DATA_BACKUP_DIR="" -DEPLOY_BINARIES="true" -LEGACY_PATCH_DIR="" -JANUS_PREFIX="" -JANUS_SRC="" -PUBLIC_HOST="" -HTTP_PORT="" -ADMIN_PORT="" -RTP_RANGE="" -ENABLE_ADMIN="" -API_SECRET="" -ADMIN_SECRET="" -LABEL="" -DRY_RUN="false" -SNAPSHOT_PATHS=() - -while [[ $# -gt 0 ]]; do - case "$1" in - --workdir) WORKDIR="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --action) ACTION="$2"; shift 2 ;; - --opensim-dir) OPENSIM_DIR="$2"; shift 2 ;; - --opensim-repo) OPENSIM_REPO="$2"; shift 2 ;; - --opensim-branch) OPENSIM_BRANCH="$2"; shift 2 ;; - --repo-mode) REPO_MODE="$2"; shift 2 ;; - --tsassets-dir) TSASSETS_DIR="$2"; shift 2 ;; - --currency-dir) CURRENCY_DIR="$2"; shift 2 ;; - --data-backup-dir) DATA_BACKUP_DIR="$2"; shift 2 ;; - --deploy-binaries) DEPLOY_BINARIES="$2"; shift 2 ;; - --legacy-patch-dir) LEGACY_PATCH_DIR="$2"; shift 2 ;; - --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; - --janus-src) JANUS_SRC="$2"; shift 2 ;; - --public-host) PUBLIC_HOST="$2"; shift 2 ;; - --http-port) HTTP_PORT="$2"; shift 2 ;; - --admin-port) ADMIN_PORT="$2"; shift 2 ;; - --rtp-range) RTP_RANGE="$2"; shift 2 ;; - --enable-admin) ENABLE_ADMIN="$2"; shift 2 ;; - --api-secret) API_SECRET="$2"; shift 2 ;; - --admin-secret) ADMIN_SECRET="$2"; shift 2 ;; - --label) LABEL="$2"; shift 2 ;; - --dry-run) DRY_RUN="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) die "Unknown option: $1" ;; - esac -done - -[[ -n "$ACTION" ]] || die "Missing --action" -validate_profile "$PROFILE" -ensure_profile_action_allowed update "$PROFILE" "$ACTION" - -case "$DRY_RUN" in - true|false) ;; - *) die "--dry-run must be true or false" ;; -esac - -OPENSIM_DIR="${OPENSIM_DIR:-$WORKDIR/opensim}" -JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}" -JANUS_SRC="${JANUS_SRC:-$WORKDIR/janus-gateway}" - -log INFO "Using profile: $PROFILE" - -case "$ACTION" in - create-rollback) create_rollback ;; - list-rollbacks) list_rollbacks ;; - update-opensim) update_opensim ;; - update-janus) update_janus ;; - full-update) full_update ;; - *) die "Unsupported action: $ACTION" ;; +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +# shellcheck source=/dev/null +source "$SCRIPT_DIR/osmtool_core.sh" + +usage() { + cat <<'EOF' +Usage: + osmtool_update.sh [--workdir ] --action + [--opensim-dir ] [--opensim-repo ] [--opensim-branch ] [--repo-mode ] + [--tsassets-dir ] [--currency-dir ] [--data-backup-dir ] + [--deploy-binaries ] [--legacy-patch-dir ] + [--janus-prefix ] [--janus-src ] [--public-host ] [--http-port ] + [--admin-port ] [--rtp-range ] [--enable-admin ] + [--api-secret ] [--admin-secret ] [--label ] [--dry-run ] + +Examples: + osmtool_update.sh --action create-rollback --workdir /opt --label pre_update + osmtool_update.sh --action update-opensim --workdir /opt --dry-run true +EOF + print_usage_common +} + +timestamp() { + date '+%Y%m%d_%H%M%S' +} + +rollback_dir() { + printf '%s' "$WORKDIR/rollback" +} + +ensure_rollback_dir() { + local dir + dir="$(rollback_dir)" + + if mkdir -p "$dir" 2>/dev/null; then + return 0 + fi + + sudo mkdir -p "$dir" + sudo chown "$(id -u):$(id -g)" "$dir" +} + +path_relative_to_root() { + local path="$1" + printf '%s' "${path#/}" +} + +append_snapshot_path() { + local path="$1" + + [[ -e "$path" ]] || return 0 + SNAPSHOT_PATHS+=("$(path_relative_to_root "$path")") +} + +build_opensim_snapshot_paths() { + local sim_dir + + SNAPSHOT_PATHS=() + append_snapshot_path "$OPENSIM_DIR" + append_snapshot_path "$WORKDIR/robust/bin" + append_snapshot_path "$WORKDIR/standalone/bin" + + shopt -s nullglob + for sim_dir in "$WORKDIR"/sim*; do + append_snapshot_path "$sim_dir/bin" + done + shopt -u nullglob +} + +build_janus_snapshot_paths() { + SNAPSHOT_PATHS=() + append_snapshot_path "$JANUS_PREFIX" + append_snapshot_path "$JANUS_SRC" +} + +create_snapshot_archive() { + local scope="$1" + shift + local archive_name archive_path manifest_path + local -a paths=("$@") + + ensure_rollback_dir + + if [[ ${#paths[@]} -eq 0 ]]; then + log WARN "No existing paths found for rollback scope: $scope" + return 0 + fi + + archive_name="${scope}_$(timestamp)" + if [[ -n "$LABEL" ]]; then + archive_name="${archive_name}_${LABEL}" + fi + + archive_path="$(rollback_dir)/${archive_name}.tar.gz" + manifest_path="$(rollback_dir)/${archive_name}.manifest" + + log INFO "Creating rollback archive: $archive_path" + printf '%s\n' "${paths[@]}" > "$manifest_path" + + if [[ "$DRY_RUN" == "true" ]]; then + log INFO "[DRY-RUN] Would archive paths listed in: $manifest_path" + return 0 + fi + + tar -czf "$archive_path" -C / "${paths[@]}" + log INFO "Rollback archive created: $archive_path" + log INFO "Rollback manifest created: $manifest_path" +} + +run_install_action() { + local install_action="$1" + local -a cmd + + cmd=("$SCRIPT_DIR/osmtool_install.sh" --profile "$PROFILE" --workdir "$WORKDIR" --action "$install_action") + + [[ -n "$OPENSIM_DIR" ]] && cmd+=(--opensim-dir "$OPENSIM_DIR") + [[ -n "$OPENSIM_REPO" ]] && cmd+=(--opensim-repo "$OPENSIM_REPO") + [[ -n "$OPENSIM_BRANCH" ]] && cmd+=(--opensim-branch "$OPENSIM_BRANCH") + [[ -n "$REPO_MODE" ]] && cmd+=(--repo-mode "$REPO_MODE") + [[ -n "$TSASSETS_DIR" ]] && cmd+=(--tsassets-dir "$TSASSETS_DIR") + [[ -n "$CURRENCY_DIR" ]] && cmd+=(--currency-dir "$CURRENCY_DIR") + [[ -n "$DATA_BACKUP_DIR" ]] && cmd+=(--data-backup-dir "$DATA_BACKUP_DIR") + [[ -n "$DEPLOY_BINARIES" ]] && cmd+=(--deploy-binaries "$DEPLOY_BINARIES") + [[ -n "$LEGACY_PATCH_DIR" ]] && cmd+=(--legacy-patch-dir "$LEGACY_PATCH_DIR") + [[ -n "$JANUS_PREFIX" ]] && cmd+=(--janus-prefix "$JANUS_PREFIX") + [[ -n "$JANUS_SRC" ]] && cmd+=(--janus-src "$JANUS_SRC") + [[ -n "$PUBLIC_HOST" ]] && cmd+=(--public-host "$PUBLIC_HOST") + [[ -n "$HTTP_PORT" ]] && cmd+=(--http-port "$HTTP_PORT") + [[ -n "$ADMIN_PORT" ]] && cmd+=(--admin-port "$ADMIN_PORT") + [[ -n "$RTP_RANGE" ]] && cmd+=(--rtp-range "$RTP_RANGE") + [[ -n "$ENABLE_ADMIN" ]] && cmd+=(--enable-admin "$ENABLE_ADMIN") + [[ -n "$API_SECRET" ]] && cmd+=(--api-secret "$API_SECRET") + [[ -n "$ADMIN_SECRET" ]] && cmd+=(--admin-secret "$ADMIN_SECRET") + + log INFO "Delegating update to install action: $install_action" + if [[ "$DRY_RUN" == "true" ]]; then + printf -v rendered '%q ' "${cmd[@]}" + log INFO "[DRY-RUN] $rendered" + return 0 + fi + + "${cmd[@]}" +} + +create_rollback() { + build_opensim_snapshot_paths + create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}" + build_janus_snapshot_paths + create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}" +} + +list_rollbacks() { + local dir + dir="$(rollback_dir)" + + if [[ ! -d "$dir" ]]; then + log INFO "No rollback directory found: $dir" + return 0 + fi + + find "$dir" -maxdepth 1 -type f \( -name '*.tar.gz' -o -name '*.manifest' \) -printf '%T@ %p\n' 2>/dev/null | \ + sort -rn | cut -d' ' -f2- +} + +update_opensim() { + build_opensim_snapshot_paths + create_snapshot_archive opensim "${SNAPSHOT_PATHS[@]}" + run_install_action install-opensim +} + +update_janus() { + build_janus_snapshot_paths + create_snapshot_archive janus "${SNAPSHOT_PATHS[@]}" + run_install_action install-janus +} + +full_update() { + update_opensim + update_janus +} + +WORKDIR="$DEFAULT_WORKDIR" +ACTION="" +PROFILE="grid-sim" +OPENSIM_DIR="" +OPENSIM_REPO="" +OPENSIM_BRANCH="" +REPO_MODE="update" +TSASSETS_DIR="" +CURRENCY_DIR="" +DATA_BACKUP_DIR="" +DEPLOY_BINARIES="true" +LEGACY_PATCH_DIR="" +JANUS_PREFIX="" +JANUS_SRC="" +PUBLIC_HOST="" +HTTP_PORT="" +ADMIN_PORT="" +RTP_RANGE="" +ENABLE_ADMIN="" +API_SECRET="" +ADMIN_SECRET="" +LABEL="" +DRY_RUN="false" +SNAPSHOT_PATHS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --workdir) WORKDIR="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --action) ACTION="$2"; shift 2 ;; + --opensim-dir) OPENSIM_DIR="$2"; shift 2 ;; + --opensim-repo) OPENSIM_REPO="$2"; shift 2 ;; + --opensim-branch) OPENSIM_BRANCH="$2"; shift 2 ;; + --repo-mode) REPO_MODE="$2"; shift 2 ;; + --tsassets-dir) TSASSETS_DIR="$2"; shift 2 ;; + --currency-dir) CURRENCY_DIR="$2"; shift 2 ;; + --data-backup-dir) DATA_BACKUP_DIR="$2"; shift 2 ;; + --deploy-binaries) DEPLOY_BINARIES="$2"; shift 2 ;; + --legacy-patch-dir) LEGACY_PATCH_DIR="$2"; shift 2 ;; + --janus-prefix) JANUS_PREFIX="$2"; shift 2 ;; + --janus-src) JANUS_SRC="$2"; shift 2 ;; + --public-host) PUBLIC_HOST="$2"; shift 2 ;; + --http-port) HTTP_PORT="$2"; shift 2 ;; + --admin-port) ADMIN_PORT="$2"; shift 2 ;; + --rtp-range) RTP_RANGE="$2"; shift 2 ;; + --enable-admin) ENABLE_ADMIN="$2"; shift 2 ;; + --api-secret) API_SECRET="$2"; shift 2 ;; + --admin-secret) ADMIN_SECRET="$2"; shift 2 ;; + --label) LABEL="$2"; shift 2 ;; + --dry-run) DRY_RUN="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) die "Unknown option: $1" ;; + esac +done + +[[ -n "$ACTION" ]] || die "Missing --action" +validate_profile "$PROFILE" +ensure_profile_action_allowed update "$PROFILE" "$ACTION" + +case "$DRY_RUN" in + true|false) ;; + *) die "--dry-run must be true or false" ;; +esac + +OPENSIM_DIR="${OPENSIM_DIR:-$WORKDIR/opensim}" +JANUS_PREFIX="${JANUS_PREFIX:-/opt/janus}" +JANUS_SRC="${JANUS_SRC:-$WORKDIR/janus-gateway}" + +log INFO "Using profile: $PROFILE" + +case "$ACTION" in + create-rollback) create_rollback ;; + list-rollbacks) list_rollbacks ;; + update-opensim) update_opensim ;; + update-janus) update_janus ;; + full-update) full_update ;; + *) die "Unsupported action: $ACTION" ;; esac \ No newline at end of file diff --git a/osmtool.sh b/osmtool.sh index c3d9509..182f436 100644 --- a/osmtool.sh +++ b/osmtool.sh @@ -1,6919 +1,6919 @@ -#!/bin/bash - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Debug in log Datei -#! ACHTUNG das loggen speichert alles auch vertrauliche Daten. -#?────────────────────────────────────────────────────────────────────────────────────────── - -#* ====================================================================== -#* DEBUG-LOG-SYSTEM (Überarbeitete Version) -#* -#* Merkmale: -#* - Vollständig abwärtskompatibel zu bestehenden Aufrufen -#* - Thread-sicherer Zugriff auf Log-Datei (mit flock) -#* - Automatische Log-Rotation bei Größenüberschreitung -#* - Unterstützt farbige Konsolenausgabe und bereinigte Log-Dateien -#* - Robustere Fehlerbehandlung -#* ====================================================================== - -#* 1. LOGGING-KONFIGURATION -#* ---------------------------------------------------------------------- - -# Logging global aktivieren/deaktivieren (true/false) -LOG_ENABLED=true # Default: true (Logging aktiv) -#LOG_ENABLED=false # Zum Deaktivieren - -# Soll die Log-Datei beim Start gelöscht werden? -OLD_LOG_DEL=true # Default: true (alte Logs löschen) -#OLD_LOG_DEL=false # Zum Deaktivieren - -# Log-Datei Name und Speicherort -DEBUG_LOG="osmtool_debug.log" # Default: im aktuellen Verzeichnis - -# Maximale Log-Größe in MB bevor Rotation erfolgt (0 = deaktiviert) -MAX_LOG_SIZE_MB=10 # 10MB empfohlen - -#* 1b. KONFIGURATION AUS JSON (osmtool_config.json) -#* ---------------------------------------------------------------------- - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -CONFIG_FILE_DEFAULT="$SCRIPT_DIR/osmtool_config.json" -CONFIG_FILE="${OSMTOOL_CONFIG_FILE:-$CONFIG_FILE_DEFAULT}" - -function json_get_raw_value() { - local key="$1" - local file="$2" - - [[ -f "$file" ]] || return 1 - - if command -v jq >/dev/null 2>&1; then - jq -r --arg k "$key" '.[$k] // empty' "$file" 2>/dev/null - return 0 - fi - - sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*\"([^\"]*)\"[[:space:]]*,?[[:space:]]*$/\1/p" "$file" | head -n1 -} - -function json_get_string() { - local key="$1" - local default_value="$2" - local value - - value="$(json_get_raw_value "$key" "$CONFIG_FILE")" - if [[ -n "$value" ]]; then - printf '%s' "$value" - else - printf '%s' "$default_value" - fi -} - -function json_get_bool() { - local key="$1" - local default_value="$2" - local value - - if command -v jq >/dev/null 2>&1; then - value="$(jq -r --arg k "$key" '.[$k] // empty' "$CONFIG_FILE" 2>/dev/null)" - else - value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*(true|false)[[:space:]]*,?[[:space:]]*$/\1/p" "$CONFIG_FILE" | head -n1)" - fi - - case "$value" in - true|false) printf '%s' "$value" ;; - *) printf '%s' "$default_value" ;; - esac -} - -function json_get_int() { - local key="$1" - local default_value="$2" - local value - - if command -v jq >/dev/null 2>&1; then - value="$(jq -r --arg k "$key" '.[$k] // empty' "$CONFIG_FILE" 2>/dev/null)" - else - value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*([0-9]+)[[:space:]]*,?[[:space:]]*$/\1/p" "$CONFIG_FILE" | head -n1)" - fi - - if [[ "$value" =~ ^[0-9]+$ ]]; then - printf '%s' "$value" - else - printf '%s' "$default_value" - fi -} - -function resolve_cfg_path() { - local path_value="$1" - if [[ -z "$path_value" ]]; then - printf '%s' "$SCRIPT_DIR" - return - fi - - if [[ "$path_value" = /* ]]; then - printf '%s' "$path_value" - else - printf '%s' "$SCRIPT_DIR/$path_value" - fi -} - -if [[ -f "$CONFIG_FILE" ]]; then - LOG_ENABLED="$(json_get_bool "log_enabled" "$LOG_ENABLED")" - OLD_LOG_DEL="$(json_get_bool "old_log_del" "$OLD_LOG_DEL")" - DEBUG_LOG="$(json_get_string "debug_log" "$DEBUG_LOG")" - MAX_LOG_SIZE_MB="$(json_get_int "max_log_size_mb" "$MAX_LOG_SIZE_MB")" -fi - -CFG_LANGUAGE="$(json_get_string "language" "de")" -CFG_LANG_DIR_REL="$(json_get_string "path_lang_dir" "lang")" -CFG_ROBUST_BIN_REL="$(json_get_string "path_robust_bin" "robust/bin")" -CFG_OPENSIM_BIN_REL="$(json_get_string "path_opensim_bin" "opensim/bin")" -CFG_WORKDIR_REL="$(json_get_string "path_workdir" ".")" - -LANG_DIR="$(resolve_cfg_path "$CFG_LANG_DIR_REL")" -PATH_ROBUST_BIN="$(resolve_cfg_path "$CFG_ROBUST_BIN_REL")" -PATH_OPENSIM_BIN="$(resolve_cfg_path "$CFG_OPENSIM_BIN_REL")" -WORK_DIR="$(resolve_cfg_path "$CFG_WORKDIR_REL")" - -export LANG_DIR PATH_ROBUST_BIN PATH_OPENSIM_BIN WORK_DIR - -if [[ ! -d "$WORK_DIR" ]]; then - WORK_DIR="$SCRIPT_DIR" -fi - -#* 2. LOG-SYSTEM INITIALISIERUNG -#* ---------------------------------------------------------------------- - -# Logdatei vorbereiten (wird nur aufgerufen wenn LOG_ENABLED=true) -function init_log_system() { - # Alte Log-Datei löschen falls gewünscht - if [[ "$OLD_LOG_DEL" == "true" ]]; then - : > "$DEBUG_LOG" 2>/dev/null || { - echo "FEHLER: Kann Logdatei nicht zurücksetzen: $DEBUG_LOG" >&2 - return 1 - } - else - touch "$DEBUG_LOG" 2>/dev/null || { - echo "FEHLER: Kann Logdatei nicht erstellen: $DEBUG_LOG" >&2 - return 1 - } - fi - - # Schreibrechte prüfen - if [ ! -w "$DEBUG_LOG" ]; then - echo "FEHLER: Keine Schreibrechte für Logdatei: $DEBUG_LOG" >&2 - return 1 - fi - - return 0 -} - -# System bei Start initialisieren -if [[ "$LOG_ENABLED" == "true" ]]; then - if ! init_log_system; then - echo "WARNUNG: Logging wird deaktiviert (Initialisierung fehlgeschlagen)" >&2 - LOG_ENABLED=false - fi -fi - -#* 3. HILFSFUNKTIONEN -#* ---------------------------------------------------------------------- - -# Entfernt ANSI-Farbcodes aus Text (für Log-Datei) -function clean_ansi() { - echo -e "$1" | sed -E 's/\x1B\[([0-9]{1,3}(;[0-9]{1,3})*)?[mGK]//g' -} - -# Führt Log-Rotation durch wenn MAX_LOG_SIZE_MB überschritten wird -function rotate_log_if_needed() { - [[ "$MAX_LOG_SIZE_MB" -eq 0 ]] && return # Rotation deaktiviert - - local log_size_mb - log_size_mb=$(du -m "$DEBUG_LOG" 2>/dev/null | cut -f1) || return - - if [[ "$log_size_mb" -ge "$MAX_LOG_SIZE_MB" ]]; then - mv "$DEBUG_LOG" "${DEBUG_LOG}.old" 2>/dev/null - : > "$DEBUG_LOG" 2>/dev/null - fi -} - -#* 4. HAUPT-LOG-FUNKTION (abwärtskompatibel!) -#* ---------------------------------------------------------------------- - -function log() { - local message="$1" - local level="${2:-INFO}" # Default-Level: INFO (abwärtskompatibel) - timestamp=$(date "+%Y-%m-%d %H:%M:%S") - - # 1. Immer zur Konsole ausgeben (mit Farben, genau wie bisher) - echo -e "$message" - - # 2. Nur in Log-Datei schreiben wenn Logging aktiviert - if [[ "$LOG_ENABLED" == "true" ]]; then - # Log-Rotation prüfen - rotate_log_if_needed - - # ANSI-Codes entfernen für Log-Datei - clean_message=$(clean_ansi "$message") - - # Thread-sicheres Schreiben (falls flock verfügbar) - if command -v flock >/dev/null; then - ( - flock -x 200 - echo "[${timestamp}] [${level}] ${clean_message}" >> "$DEBUG_LOG" - ) 200>>"$DEBUG_LOG" - else - echo "[${timestamp}] [${level}] ${clean_message}" >> "$DEBUG_LOG" - fi - fi -} - -#* 5. I18N-SYSTEM (de|en|fr|es) -#* ---------------------------------------------------------------------- - -APP_LANG="${OSM_LANG:-$CFG_LANGUAGE}" - -declare -A I18N_CURRENT=() -declare -A I18N_EN=() - -function normalize_lang() { - case "$1" in - de|en|fr|es) echo "$1" ;; - *) echo "de" ;; - esac -} - -function load_lang_file() { - local lang_file="$1" - local target_array_name="$2" - local line key value - - [[ -f "$lang_file" ]] || return 1 - - while IFS= read -r line || [[ -n "$line" ]]; do - [[ -z "$line" || "${line:0:1}" == "#" ]] && continue - [[ "$line" == *=* ]] || continue - key="${line%%=*}" - value="${line#*=}" - if [[ "$target_array_name" == "I18N_EN" ]]; then - I18N_EN["$key"]="$value" - else - I18N_CURRENT["$key"]="$value" - fi - done < "$lang_file" - - return 0 -} - -function init_i18n() { - APP_LANG="$(normalize_lang "$APP_LANG")" - I18N_CURRENT=() - I18N_EN=() - - load_lang_file "$LANG_DIR/en.lang" I18N_EN || true - load_lang_file "$LANG_DIR/${APP_LANG}.lang" I18N_CURRENT || true -} - -function msg() { - local key="$1" - if [[ -n "${I18N_CURRENT[$key]:-}" ]]; then - printf '%s' "${I18N_CURRENT[$key]}" - return - fi - if [[ -n "${I18N_EN[$key]:-}" ]]; then - printf '%s' "${I18N_EN[$key]}" - return - fi - printf '%s' "$key" -} - -function is_yes() { - case "${1,,}" in - j|ja|y|yes|o|oui|s|si) return 0 ;; - *) return 1 ;; - esac -} - -function is_no() { - case "${1,,}" in - n|no|nein|non) return 0 ;; - *) return 1 ;; - esac -} - -function parse_lang_arg() { - local -a filtered=() - local i=1 - while [[ $i -le $# ]]; do - local arg="${!i}" - if [[ "$arg" == "--lang" ]]; then - local next_index=$((i + 1)) - if [[ $next_index -le $# ]]; then - APP_LANG="$(normalize_lang "${!next_index}")" - i=$((i + 2)) - continue - fi - elif [[ "$arg" == --lang=* ]]; then - APP_LANG="$(normalize_lang "${arg#--lang=}")" - i=$((i + 1)) - continue - fi - filtered+=("$arg") - i=$((i + 1)) - done - - set -- "${filtered[@]}" - FILTERED_ARGS=("$@") -} - -parse_lang_arg "$@" -set -- "${FILTERED_ARGS[@]}" -export OSM_LANG="$APP_LANG" -init_i18n - -#* ====================================================================== -#* BEISPIELAUFRUFE: -#* -#* log "${COLOR_BAD}FEHLER: Robust.HG.ini nicht gefunden in $robust_dir${COLOR_RESET}" >&2 -#* log "Eine normale Info-Meldung" -#* ====================================================================== - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Informationen Kopfzeile -#?────────────────────────────────────────────────────────────────────────────────────────── - -# Quelle: -# https://github.com/ManfredAabye/opensimMULTITOOLS-II/blob/main/osmtool.sh - -tput reset # Bildschirmausgabe loeschen inklusive dem Scrollbereich. -SCRIPTNAME="opensimMULTITOOL II" - -#testmodus=1 # Testmodus: 1=aktiviert, 0=deaktiviert - -# Versionsnummer besteht aus: Jahr.Monat.Funktionsanzahl.Eigentliche_Versionsnummer -VERSION="V26.4.230.588" -log "\e[36m$SCRIPTNAME\e[0m $VERSION" -echo "$(msg INFO_TOOL_PURPOSE)" -echo "$(msg INFO_USE_OWN_RISK)" -log "\e[33m$(msg INFO_ABORT_HINT)\e[0m" -echo " " - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Variablen setzen -#?────────────────────────────────────────────────────────────────────────────────────────── - -#* FARBDEFINITIONEN -COLOR_OK='\e[32m' # Grün (Haken) -COLOR_BAD='\e[31m' # Rot (Kreuz) -COLOR_HEADING='\e[97m' # Weiß (Überschriften) -COLOR_START='\e[92m' # Hellgrün (Startaktionen) -COLOR_STOP='\e[91m' # Hellrot (Stopaktionen) -COLOR_SERVER='\e[36m' # Cyan (Server/Verzeichnisse/IPs) -COLOR_DIR='\e[90m' # Grau (Pfade) -COLOR_LABEL='\e[97m' # Weiß (Beschriftungen) -COLOR_WARNING='\e[33m' # Gelb (Warnungen) -COLOR_VALUE='\e[36m' # Cyan für Werte -COLOR_ACTION='\e[92m' # Hellgrün für Aktionen -COLOR_RESET='\e[0m' # Farbreset -COLOR_RESTART='\e[93m' # Gelb (RESTART) -COLOR_INFO='\e[31m' # Rot (INFO) -COLOR_SERVER='\e[34m' # Blau (SERVER) - -# Standardfarben -# COLOR_RED='\e[31m' # Rot -# COLOR_GREEN='\e[32m' # Grün -# COLOR_YELLOW='\e[33m' # Gelb -# COLOR_BLUE='\e[34m' # Blau (korrigiert für SERVER) -# COLOR_MAGENTA='\e[35m' # Magenta (dein aktueller "SERVER"-Wert) -# COLOR_CYAN='\e[36m' # Cyan -# COLOR_WHITE='\e[37m' # Weiß - -#* SYMBOLDEFINITIONEN -SYM_OK="${COLOR_OK}✓${COLOR_RESET}" -SYM_BAD="${COLOR_BAD}✗${COLOR_RESET}" -SYM_INFO="${COLOR_INFO}❓${COLOR_RESET}" -SYM_WAIT="${COLOR_VALUE}⏳${COLOR_RESET}" -SYM_LOG="${COLOR_VALUE}📋${COLOR_RESET}" -COLOR_SECTION='\e[0;35m' # Magenta für Sektionsnamen -COLOR_FILE='\e[0;33m' # Gelb für Dateipfade - -#* SYSTEM & SERVER -SYM_SERVER="${COLOR_SERVER}💻${COLOR_RESET}" # Server/Computer -#SYM_STORAGE="${COLOR_VALUE}💾${COLOR_RESET}" # Speicher (Diskette) -#SYM_NETWORK="${COLOR_VALUE}📡${COLOR_RESET}" # Netzwerk/Antenne -#SYM_SECURITY="${COLOR_VALUE}🔒${COLOR_RESET}" # Sicherheit - -#* DATEIEN & ORDNER -SYM_FOLDER="${COLOR_VALUE}📂${COLOR_RESET}" # Geöffneter Ordner -SYM_FILE="${COLOR_VALUE}📄${COLOR_RESET}" # Dokument -#SYM_ARCHIVE="${COLOR_VALUE}📦${COLOR_RESET}" # Archiv/Paket -#SYM_SEARCH="${COLOR_VALUE}🔍${COLOR_RESET}" # Suche - -#* TOOLS & AKTIONEN -SYM_TOOLS="${COLOR_VALUE}🧮${COLOR_RESET}" # Werkzeuge -SYM_CONFIG="${COLOR_VALUE}🔧${COLOR_RESET}" # Konfiguration -#SYM_MAINTENANCE="${COLOR_VALUE}🛠️${COLOR_RESET}" # Wartung -SYM_CLEAN="${COLOR_WARNING}🧹${COLOR_RESET}" # Bereinigung - -#* DOKUMENTATION -SYM_SCRIPT="${COLOR_VALUE}📜${COLOR_RESET}" # Skript -SYM_BOOK="${COLOR_VALUE}📖${COLOR_RESET}" # Dokumentation -#SYM_NOTES="${COLOR_VALUE}📝${COLOR_RESET}" # Notizen - -#* STATUS & KONTROLLE -SYM_OK="${COLOR_OK}✔${COLOR_RESET}" # Erfolg -SYM_BAD="${COLOR_BAD}✘${COLOR_RESET}" # Fehler -SYM_WARNING="${COLOR_WARNING}🔥${COLOR_RESET}" # Warnung -#SYM_RESTART="${COLOR_RESTART}🔄${COLOR_RESET}" # Neustart - -#* ERWEITERTE SYMBOLE (Für spezielle Funktionen) -#SYM_DATABASE="${COLOR_VALUE}💽${COLOR_RESET}" # Datenbank -#SYM_BACKUP="${COLOR_VALUE}💾${COLOR_RESET}" # Backup -#SYM_EMAIL="${COLOR_VALUE}📧${COLOR_RESET}" # E-Mail -#SYM_MONITORING="${COLOR_VALUE}📈${COLOR_RESET}" # Monitoring - -#* WARTEZEITEN muessen leider sein damit der Server nicht überfordert wird. -Simulator_Start_wait=15 # Sekunden -MoneyServer_Start_wait=30 # Sekunden -RobustServer_Start_wait=30 # Sekunden -Simulator_Stop_wait=15 # Sekunden -MoneyServer_Stop_wait=30 # Sekunden -RobustServer_Stop_wait=30 # Sekunden - -if [[ -f "$CONFIG_FILE" ]]; then - Simulator_Start_wait="$(json_get_int "simulator_start_wait" "$Simulator_Start_wait")" - MoneyServer_Start_wait="$(json_get_int "moneyserver_start_wait" "$MoneyServer_Start_wait")" - RobustServer_Start_wait="$(json_get_int "robustserver_start_wait" "$RobustServer_Start_wait")" - Simulator_Stop_wait="$(json_get_int "simulator_stop_wait" "$Simulator_Stop_wait")" - MoneyServer_Stop_wait="$(json_get_int "moneyserver_stop_wait" "$MoneyServer_Stop_wait")" - RobustServer_Stop_wait="$(json_get_int "robustserver_stop_wait" "$RobustServer_Stop_wait")" -fi - -# Sprachwert nach dem Bereinigen der Argumente fuer nachfolgende Logik sichern -KOMMANDO="${1:-}" - -#* Leere Zeile -function blankline() { - # Konfiguration: Zeichen für Linien (beliebig erweiterbar) - #local line_chars=("-" "_" "=" "#" "*" "~") - local line_chars=("_") - local line_length=80 # Standardlänge der Linie - - sleep 0.25 - - # Erzeuge jede Linie mit Verzögerung - for char in "${line_chars[@]}"; do - printf "%${line_length}s\n" | tr " " "$char" # Linie dynamisch generieren - echo " " # Leerzeile nach jeder Linie - done -} - -#* Hauptpfad des Skripts automatisch setzen -cd "$WORK_DIR" || exit 1 -system_ip=$(hostname -I | awk '{print $1}') -log "${COLOR_LABEL}$(msg INFO_WORKDIR)${COLOR_RESET} ${COLOR_VALUE}$WORK_DIR${COLOR_RESET}" -log "${COLOR_LABEL}$(msg INFO_SYSTEM_IP)${COLOR_RESET} ${COLOR_VALUE}$system_ip${COLOR_RESET}" -blankline - -#* Rootrechte erforderlich -function rootrights() { - # Root-Privilegien erforderlich - if [[ $EUID -ne 0 ]]; then - log "${COLOR_WARNING}$(msg ROOT_WARN_USER_MODE_1)${COLOR_RESET}" >&2 - log "$(msg ROOT_WARN_USER_MODE_2)${COLOR_RESET}" >&2 - log "[sudo bash osmtool.sh]" >&2 - - while true; do - log "$(msg ROOT_PROMPT_CONTINUE_NO_ROOT)" >&2 - read -r answer - - if is_yes "$answer"; then - log "$(msg ROOT_CONTINUE_NO_ROOT)" >&2 - return 0 - elif is_no "$answer"; then - log "${COLOR_STOP}$(msg COMMON_ABORTED)${COLOR_RESET}" >&2 - exit 1 - else - log "${COLOR_WARNING}$(msg INPUT_INVALID_YES_NO)${COLOR_RESET}" >&2 - fi - done - fi -} - - -#* Soll im Hypergrid Modus gearbeitet werden oder in einem Geschlossenen Grid? -function hypergrid() { - local modus="$1" - local robust_dir="$PATH_ROBUST_BIN" # Konfigurierbarer Pfad zu Robust-Dateien - - echo "$(msg MODE_CONFIG)" - - if [[ "$modus" == "hypergrid" ]]; then - echo "$(msg MODE_HYPERGRID_ENABLED)" - - # Prüfen ob Robust.HG.ini existiert - if [[ ! -f "$robust_dir/Robust.HG.ini" ]]; then - log "${COLOR_BAD}FEHLER: Robust.HG.ini nicht gefunden in $robust_dir${COLOR_RESET}" >&2 - return 1 - fi - - cp "$robust_dir/Robust.HG.ini" "$robust_dir/Robust.ini" || { - log "${COLOR_BAD}FEHLER: Konnte Robust.HG.ini nicht kopieren${COLOR_RESET}" >&2 - return 1 - } - - else - echo "$(msg MODE_CLOSEDGRID_ENABLED)" - - # Prüfen ob Robust.local.ini existiert - if [[ ! -f "$robust_dir/Robust.local.ini" ]]; then - log "${COLOR_BAD}FEHLER: Robust.local.ini nicht gefunden in $robust_dir${COLOR_RESET}" >&2 - return 1 - fi - - cp "$robust_dir/Robust.local.ini" "$robust_dir/Robust.ini" || { - log "${COLOR_BAD}FEHLER: Konnte Robust.local.ini nicht kopieren${COLOR_RESET}" >&2 - return 1 - } - fi - - log "${COLOR_OK}$(msg MODE_SET_OK): $modus${COLOR_RESET}" - return 0 -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Abhängigkeiten installieren -#?────────────────────────────────────────────────────────────────────────────────────────── - -# Nach git clone/pull prüfen -check_repo_integrity() { - local repo_dir=${1:-.} - - pushd "$repo_dir" > /dev/null || return 1 - - if ! git fsck --no-progress; then - log "${SYM_BAD} ${COLOR_ERROR}Repository-Prüfung fehlgeschlagen!${COLOR_RESET}" - popd > /dev/null - return 1 - fi - - if [ "$(git status --porcelain)" ]; then - log "${COLOR_WARNING}Uncommittete Änderungen vorhanden.${COLOR_RESET}" - fi - - popd > /dev/null - log "${SYM_OK} ${COLOR_ACTION}Repository-Integrität OK.${COLOR_RESET}" - return 0 -} - -function warn_if_desktop_environment() { - log "${COLOR_SECTION}=== Systemtyp-Erkennung (Server vs. Desktop) ===${COLOR_RESET}" - - # Prüfen auf Anzeichen einer Desktop-Umgebung - if [[ -n "$XDG_CURRENT_DESKTOP" || -n "$DESKTOP_SESSION" || $(pgrep -lE 'gnome|plasma|xfce|mate|lxde|cinnamon' 2>/dev/null) ]]; then - log "${SYM_WARNING} ${COLOR_WARNING}Desktop-Umgebung erkannt!${COLOR_RESET}" - log "${COLOR_WARNING}${SYM_WARNING} Du führst dieses Skript auf einem Desktop-System aus.${COLOR_RESET}" - log "${COLOR_ACTION}Dieses Setup installiert einen Server und benötigt Root-Rechte.${COLOR_RESET}" - log "${COLOR_WARNING}Bitte stelle sicher, dass du weißt, was du tust.${COLOR_RESET}" - echo -ne "${COLOR_ACTION}Trotzdem fortfahren? (j/n) [n] ${COLOR_RESET}" - read -r user_continue - user_continue=${user_continue:-n} - - if [[ "$user_continue" =~ ^[nN]$ ]]; then - log "${SYM_BAD} ${COLOR_BAD}Installation abgebrochen vom Benutzer.${COLOR_RESET}" - exit 1 - fi - fi -} - -# -------------------------- -# Neuer Servercheck mit installationen. -# -------------------------- - -# -------------------------- -# 🛠️ HAUPTFUNKTION: servercheck() -# -------------------------- -function newservercheck() { - log "${COLOR_HEADING}🔍 Server-Kompatibilitätscheck wird durchgeführt...${COLOR_RESET}" - - rootrights - warn_if_desktop_environment - - # 1. Distro erkennen - detect_distro - - # 2. .NET prüfen/installieren - install_dotnet - - # 3. MariaDB prüfen/installieren - install_mariadb - - # 4. Abhängigkeiten installieren - install_dependencies - - log "${SYM_OK} ${COLOR_HEADING}Server-Check abgeschlossen!${COLOR_RESET}" -} - -# -------------------------- -# 🖥️ NEBENFUNKTIONEN (modular & erweiterbar) -# -------------------------- - -function detect_distro() { - # OS-Details global speichern - #log "detect_distro:" - declare -g os_id os_version os_codename # Explizit deklarieren - os_id=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"') - os_version=$(grep '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"') - os_codename=$(grep '^VERSION_CODENAME=' /etc/os-release | cut -d= -f2 | tr -d '"') - - log "${COLOR_LABEL}Server läuft mit:${COLOR_RESET} ${COLOR_SERVER}$os_id $os_version ($os_codename)${COLOR_RESET}" -} - -function install_dotnet() { - # Paketnamen-Mapping (erweiterbar!) - #log "install_dotnet:" - declare -A dotnet_pkg=( - ["ubuntu"]="dotnet-sdk-8.0" - ["debian"]="dotnet-sdk-8.0" - ["linuxmint"]="dotnet-sdk-8.0" - ["pop_os"]="dotnet-sdk-8.0" - ["arch"]="dotnet-sdk" - ["manjaro"]="dotnet-sdk" - ["raspbian"]="dotnet-sdk-8.0" - ) - - # Distro-spezifische Logik - case "$os_id" in - ubuntu|linuxmint|pop_os) - if [[ "$os_version" == "18.04" ]]; then - required_dotnet="dotnet-sdk-6.0" - elif [[ "$os_version" == "24.04" ]]; then - required_dotnet=${dotnet_pkg[$os_id]} - log "${SYM_INFO} Ubuntu 24.04 verwendet das .NET Repository für 22.04 (jammy)" - elif dpkg --compare-versions "$os_version" ge "20.04"; then - required_dotnet=${dotnet_pkg[$os_id]} - else - log "${SYM_BAD} Nicht unterstützte Ubuntu-Version: $os_version!" - return 1 - fi - ;; - debian|raspbian) - [[ "$os_version" -ge "11" ]] || { log "${SYM_BAD} Debian $os_version wird nicht unterstützt!"; return 1; } - required_dotnet=${dotnet_pkg[$os_id]} - ;; - arch|manjaro) - required_dotnet=${dotnet_pkg[$os_id]} - ;; - *) - log "${SYM_BAD} Nicht unterstützte Distribution: $os_id!" - return 1 - ;; - esac - - # Installationslogik (pacman vs. apt) - if [[ "$os_id" =~ ^(arch|manjaro)$ ]]; then - pacman_install "$required_dotnet" - else - apt_install "$required_dotnet" - # Microsoft-Repo für Debian/Ubuntu - [[ "$os_id" =~ ^(ubuntu|debian|linuxmint|pop_os|raspbian)$ ]] && add_microsoft_repo - fi -} - -function install_mariadb() { - #log "install_mariadb:" - if ! command -v mariadb >/dev/null; then - apt_install "mariadb-server" || return 1 - fi - - # Version anzeigen & Service starten - log "${SYM_OK} MariaDB-Version: $(mariadb --version)" - systemctl start mariadb || { log "${SYM_BAD} MariaDB start fehlgeschlagen!"; return 1; } -} - -function install_dependencies() { - #log "install_dependencies:" - # Dependency-Mapping (erweiterbar!) - declare -A required_packages=( - ["ubuntu"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" - ["arch"]="git glibc gcc-libs krb5 icu lttng-ust openssl libunwind zlib gdiplus zip screen" - # ... weitere Distros hier ergänzen - ) - - # Fallback-Pakete - local pkg_list=("git" "libc6" "libgcc-s1" "libssl3" "zip" "screen") - [[ -n "${required_packages[$os_id]}" ]] && IFS=' ' read -r -a pkg_list <<< "${required_packages[$os_id]}" - - # Installieren - for pkg in "${pkg_list[@]}"; do - if [[ "$os_id" =~ ^(arch|manjaro)$ ]]; then - pacman_install "$pkg" - else - apt_install "$pkg" - fi - done -} - -# -------------------------- -# 🔧 HELFERFUNKTIONEN (DRY-Prinzip) -# -------------------------- -function apt_install() { - #log "apt_install: $1" - if ! dpkg-query -W "$1" >/dev/null 2>&1; then - log "${SYM_OK} Installiere $1..." - sudo apt-get install -y "$1" || { log "${SYM_BAD} Installation von $1 fehlgeschlagen!"; return 1; } - fi -} - -function pacman_install() { - #log "pacman_install:" - if ! pacman -Qi "$1" >/dev/null 2>&1; then - log "${SYM_OK} Installiere $1..." - sudo pacman -S --noconfirm "$1" || { log "${SYM_BAD} Installation von $1 fehlgeschlagen!"; return 1; } - fi -} - -function add_microsoft_repo() { - #log "add_microsoft_repo:" - # Prüfen, ob das Repo existiert UND funktioniert (via apt-key) - if ! apt-cache policy | grep -q "packages.microsoft.com" || \ - ! grep -q "packages.microsoft.com" /etc/apt/sources.list.d/* 2>/dev/null; then - log "${SYM_INFO} Füge Microsoft-Repository hinzu..." - - # Download & Install mit Fehlerabfrage - if ! wget -qO packages-microsoft-prod.deb "https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb"; then - log "${SYM_BAD} Download des Microsoft-Repos fehlgeschlagen!" - return 1 - fi - - if ! sudo dpkg -i packages-microsoft-prod.deb >/dev/null; then - log "${SYM_BAD} Installation des Microsoft-Repos fehlgeschlagen!" - rm -f packages-microsoft-prod.deb - return 1 - fi - - rm -f packages-microsoft-prod.deb - sudo apt-get update >/dev/null || { log "${SYM_BAD} apt-get update fehlgeschlagen!"; return 1; } - else - log "${SYM_INFO} Microsoft-Repository ist bereits konfiguriert." - fi -} - -# -------------------------- -# Neuer Servercheck mit installationen ENDE -# -------------------------- - -function servercheck() { - # Direkt kompatible Distributionen: - # Debian 11+ (Bullseye, Bookworm) – Offiziell unterstützt für .NET 8 - # Ubuntu 20.04, 22.04, 24.04 – Microsoft bietet direkt kompatible Pakete - # Linux Mint (basierend auf Ubuntu 20.04 oder 22.04) - # Pop!_OS (System76, basiert auf Ubuntu) - # MX Linux (Debian-basiert, integriert Ubuntu-Funktionen) - # Arch Linux – Offiziell unterstützte Pakete über pacman - # Manjaro – Bietet .NET-Pakete direkt über die Arch-Repositorys - - # Mögliche kompatible Distributionen (mit Anpassungen): - # Kali Linux (basierend auf Debian 12, Anpassungen nötig für .NET-Pakete) - # Zorin OS (Ubuntu-basiert, Unterstützung abhängig von Version) - # elementary OS (Ubuntu-basiert, kann .NET aus Ubuntu-Quellen beziehen) - # Raspberry Pi OS (Debian-basiert, erfordert manuelle Installation für .NET) - - log "${COLOR_HEADING}🔍 Server-Kompatibilitätscheck wird durchgeführt...${COLOR_RESET}" - - rootrights - warn_if_desktop_environment - - # Ermitteln der Distribution und Version - os_id=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"') - os_version=$(grep '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"') - os_codename=$(grep '^VERSION_CODENAME=' /etc/os-release | cut -d= -f2 | tr -d '"') - - log "${COLOR_LABEL}Server läuft mit:${COLOR_RESET} ${COLOR_SERVER}$os_id $os_version ($os_codename)${COLOR_RESET}" - - # Paketnamen für verschiedene Distributionen definieren - declare -A dotnet_pkg=( - ["ubuntu"]="dotnet-sdk-8.0" - ["debian"]="dotnet-sdk-8.0" - ["linuxmint"]="dotnet-sdk-8.0" - ["pop_os"]="dotnet-sdk-8.0" - ["arch"]="dotnet-sdk" - ["manjaro"]="dotnet-sdk" - ["raspbian"]="dotnet-sdk-8.0" - ) - - # Abhängigkeiten für verschiedene Distributionen - declare -A required_packages=( - ["ubuntu"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" - ["debian"]="git libc6 libgcc1 libgssapi-krb5-2 libicu67 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" - ["linuxmint"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" - ["pop_os"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" - ["arch"]="git glibc gcc-libs krb5 icu lttng-ust openssl libunwind zlib gdiplus zip screen" - ["manjaro"]="git glibc gcc-libs krb5 icu lttng-ust openssl libunwind zlib gdiplus zip screen" - ["raspbian"]="git libc6 libgcc1 libgssapi-krb5-2 libicu67 liblttng-ust0 libssl1.1 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" - ) - - # Prüfen, welche .NET-Version installiert werden muss - if [[ "$os_id" == "ubuntu" || "$os_id" == "linuxmint" || "$os_id" == "pop_os" ]]; then - if [[ "$os_version" == "18.04" ]]; then - required_dotnet="dotnet-sdk-6.0" - elif dpkg --compare-versions "$os_version" ge "20.04"; then - required_dotnet=${dotnet_pkg[$os_id]} - - # Spezialfall Ubuntu 24.04 (verwendet jammy Repository) - if [[ "$os_version" == "24.04" ]]; then - log "${SYM_INFO} Ubuntu 24.04 verwendet das .NET Repository für Ubuntu 22.04 (jammy)" - fi - else - log "${SYM_BAD} ${COLOR_WARNING}Nicht unterstützte Ubuntu-Version: $os_version!${COLOR_RESET}" - return 1 - fi - elif [[ "$os_id" == "debian" ]]; then - if [[ "$os_version" -ge "11" ]]; then - required_dotnet=${dotnet_pkg[$os_id]} - else - log "${SYM_BAD} ${COLOR_WARNING}Debian Version $os_version wird nicht unterstützt (mindestens Debian 11 erforderlich)!${COLOR_RESET}" - return 1 - fi - elif [[ "$os_id" == "arch" || "$os_id" == "manjaro" ]]; then - required_dotnet=${dotnet_pkg[$os_id]} - elif [[ "$os_id" == "raspbian" ]]; then - if [[ "$os_version" -ge "11" ]]; then - required_dotnet=${dotnet_pkg[$os_id]} - log "${SYM_INFO} Raspberry Pi OS erfordert möglicherweise manuelle Anpassungen für .NET 8.0" - else - log "${SYM_BAD} ${COLOR_WARNING}Raspberry Pi OS Version $os_version wird nicht unterstützt!${COLOR_RESET}" - return 1 - fi - else - log "${SYM_BAD} ${COLOR_WARNING}Keine unterstützte Distribution für .NET gefunden!${COLOR_RESET}" - return 1 - fi - - # .NET-Installationsstatus prüfen - log "${COLOR_HEADING}🔄 .NET Runtime-Überprüfung:${COLOR_RESET}" - - if [[ "$os_id" == "arch" || "$os_id" == "manjaro" ]]; then - if ! pacman -Qi "$required_dotnet" >/dev/null 2>&1; then - log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$required_dotnet${COLOR_RESET}..." - sudo pacman -S --noconfirm "$required_dotnet" - log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}wurde erfolgreich installiert.${COLOR_RESET}" - else - log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}ist bereits installiert.${COLOR_RESET}" - fi - else - #if ! dpkg -s "$required_dotnet" >/dev/null 2>&1; then - # dpkg-query -W hat eine bessere Fehlerabfrage - if ! dpkg-query -W "$required_dotnet" >/dev/null 2>&1; then - log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$required_dotnet${COLOR_RESET}..." - - # Microsoft Repository hinzufügen für Debian/Ubuntu-basierte Systeme - if [[ "$os_id" == "ubuntu" || "$os_id" == "debian" || "$os_id" == "linuxmint" || "$os_id" == "pop_os" || "$os_id" == "raspbian" ]]; then - log "${SYM_INFO} Füge Microsoft Repository hinzu..." - wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb - sudo dpkg -i packages-microsoft-prod.deb - rm packages-microsoft-prod.deb - sudo apt-get update - fi - - sudo apt-get install -y "$required_dotnet" - log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}wurde erfolgreich installiert.${COLOR_RESET}" - else - log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}ist bereits installiert.${COLOR_RESET}" - fi - fi - - # Prüfen, ob MariaDB installiert ist - if ! command -v mariadb >/dev/null 2>&1; then - log "${SYM_BAD} ${COLOR_BAD}MariaDB ist nicht installiert! Ich installiere mariadb über apt.${COLOR_RESET}" - # 20.05.2025 Hier wird vor der installation von MariaDB abgebrochen dabei sollte das spätestens jetzt installiert werden. - sudo apt install mariadb-server - #exit 1 - fi - - # MariaDB-Version anzeigen - mariadb_version=$(mariadb --version) - log "${SYM_OK} ${COLOR_OK}Gefundene MariaDB-Version: ${COLOR_VALUE}$mariadb_version${COLOR_RESET}" - - # Prüfen, ob Dienst läuft - if systemctl is-active --quiet mariadb; then - log "${SYM_OK} ${COLOR_OK}MariaDB-Dienst ist bereits aktiv.${COLOR_RESET}" - else - log "${SYM_STOP} ${COLOR_WARNING}MariaDB ist nicht aktiv. Versuche zu starten...${COLOR_RESET}" - sudo systemctl start mariadb - if systemctl is-active --quiet mariadb; then - log "${SYM_OK} ${COLOR_OK}MariaDB wurde erfolgreich gestartet.${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_BAD}Fehler: MariaDB konnte nicht gestartet werden!${COLOR_RESET}" - exit 1 - fi - fi - - # Prüfen, ob Datenbankverzeichnis initialisiert ist - if [ -d /var/lib/mysql/mysql ]; then - log "${SYM_INFO} ${COLOR_LABEL}MariaDB ist bereits initialisiert.${COLOR_RESET}" - else - log "${SYM_TOOLS} ${COLOR_ACTION}Initialisiere MariaDB-Datenbankverzeichnis...${COLOR_RESET}" - sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql - sudo systemctl restart mariadb - log "${SYM_OK} ${COLOR_OK}MariaDB wurde initialisiert und neu gestartet.${COLOR_RESET}" - fi - # MariaDB-Version checken ende - - # Fehlende Pakete prüfen und installieren - log "${COLOR_HEADING}${SYM_PACKAGE} Überprüfe fehlende Pakete...${COLOR_RESET}" - - # Paketliste basierend auf Distribution auswählen - if [[ -n "${required_packages[$os_id]}" ]]; then - IFS=' ' read -r -a pkg_list <<< "${required_packages[$os_id]}" - else - # Fallback für nicht aufgeführte Distributionen - pkg_list=("git" "libc6" "libgcc-s1" "libgssapi-krb5-2" "libicu70" "libssl3" "libstdc++6" "zlib1g" "zip" "screen") - fi - - for package in "${pkg_list[@]}"; do - if [[ "$os_id" == "arch" || "$os_id" == "manjaro" ]]; then - if ! pacman -Qi "$package" >/dev/null 2>&1; then - log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$package${COLOR_RESET}..." - sudo pacman -S --noconfirm "$package" - fi - else - #if ! dpkg -s "$package" >/dev/null 2>&1; then - # dpkg-query -W hat eine bessere Fehlerabfrage - if ! dpkg-query -W "$package" >/dev/null 2>&1; then - log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$package${COLOR_RESET}..." - sudo apt-get install -y "$package" - fi - fi - done - - log "${SYM_OK} ${COLOR_HEADING}Alle benötigten Pakete wurden installiert.${COLOR_RESET}" - blankline -} - -function setup_webserver() { - log "${COLOR_SECTION}=== Web Server Setup (Apache/PHP) ===${COLOR_RESET}" - - rootrights - - # 1. Paketlisten mit erweiterten PHP-Modulen - declare -A web_packages=( - ["ubuntu"]="apache2 php libapache2-mod-php php-mysql php-gd php-curl php-mbstring php-xml php-zip" - ["debian"]="apache2 php libapache2-mod-php php-mysql php-gd php-curl php-mbstring php-xml php-zip" - ["arch"]="apache php php-apache php-gd php-curl php-mysql mariadb-libs php-mbstring php-xml" - ["manjaro"]="apache php php-apache php-gd php-curl php-mysql mariadb-libs php-mbstring php-xml" - ["centos"]="httpd php php-mysqlnd php-gd php-curl php-mbstring php-xml" - ["fedora"]="httpd php php-mysqlnd php-gd php-curl php-mbstring php-xml" - ) - - # 2. Installation - case $current_distro in - ubuntu|debian|linuxmint|pop|raspbian) - log "${SYM_INFO} ${COLOR_ACTION}Installiere Apache/PHP (apt)...${COLOR_RESET}" - sudo apt-get update - sudo apt-get install -y "${web_packages[ubuntu]}" || { - log "${SYM_BAD} ${COLOR_ERROR}Installation fehlgeschlagen!${COLOR_RESET}"; - return 1; - } - sudo a2enmod rewrite - sudo systemctl restart apache2 - ;; - - arch|manjaro) - log "${SYM_INFO} ${COLOR_ACTION}Installiere Apache/PHP (pacman)...${COLOR_RESET}" - sudo pacman -Sy --noconfirm "${web_packages[arch]}" || { - log "${SYM_BAD} ${COLOR_ERROR}Installation fehlgeschlagen!${COLOR_RESET}"; - return 1; - } - - # Apache-Konfiguration für PHP - sudo sed -i 's/LoadModule mpm_event_module/#LoadModule mpm_event_module/' /etc/httpd/conf/httpd.conf - sudo sed -i 's/#LoadModule mpm_prefork_module/LoadModule mpm_prefork_module/' /etc/httpd/conf/httpd.conf - log "\n# PHP-Konfiguration\nLoadModule php_module modules/libphp.so\nAddHandler php-script .php\nInclude conf/extra/php_module.conf" | sudo tee -a /etc/httpd/conf/httpd.conf >/dev/null - - sudo systemctl restart httpd - ;; - - centos|fedora) - log "${SYM_INFO} ${COLOR_ACTION}Installiere Apache/PHP (yum/dnf)...${COLOR_RESET}" - [[ "$current_distro" == "centos" ]] && sudo yum install -y epel-release - sudo yum install -y "${web_packages[centos]}" || { - log "${SYM_BAD} ${COLOR_ERROR}Installation fehlgeschlagen!${COLOR_RESET}"; - return 1; - } - sudo systemctl restart httpd - sudo firewall-cmd --permanent --add-service=http - sudo firewall-cmd --reload - ;; - esac - - # 3. PHP-Check (OHNE Dateianlage) - log "${SYM_INFO} ${COLOR_ACTION}Prüfe PHP-Konfiguration...${COLOR_RESET}" - php_check() { - log "${COLOR_HEADING}=== PHP-Status ===${COLOR_RESET}" - log "Version: ${COLOR_VALUE}$(php -r 'echo PHP_VERSION;')${COLOR_RESET}" - - declare -A modules=( - ["mysqli"]="MySQL-Datenbank" - ["gd"]="GD-Grafikbibliothek" - ["curl"]="cURL" - ["xml"]="XML-Unterstützung" - ["mbstring"]="Multibyte-Strings" - ) - - for mod in "${!modules[@]}"; do - if php -m | grep -q "^$mod$"; then - log "${SYM_OK} ${COLOR_OK}${modules[$mod]} (${mod})${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_ERROR}Fehlend: ${modules[$mod]} (${mod})${COLOR_RESET}" - fi - done - } - - # Führe Check aus und protokolliere Ausgabe - php_check | while IFS= read -r line; do log "$line"; done - - # 4. osWebinterface Deployment - if [[ -d "oswebinterface" ]]; then - log "${SYM_INFO} ${COLOR_ACTION}Kopiere osWebinterface...${COLOR_RESET}" - sudo cp -r oswebinterface/* /var/www/html/ - sudo chown -R www-data:www-data /var/www/html 2>/dev/null || sudo chown -R apache:apache /var/www/html - - log "${SYM_OK} ${COLOR_OK}osWebinterface erfolgreich deployt${COLOR_RESET}" - fi - - log "${COLOR_SUCCESS}Webserver-Setup abgeschlossen!${COLOR_RESET}" - blankline -} - -# function setup_email_server() { -# # SMTP-Server Konfiguration (z.B. mail.gridname.de) -# local smtp_server="mail.gridname.de" -# local sender_email="noresponse@gridname.de" -# local sender_password="DEIN_PASSWORT" # Passwort für noresponse@ - -# echo -e "\n\033[32m=== Konfiguriere E-Mail-Server für PHP mail() ===\033[0m" - -# # Postfix installieren -# sudo apt update -# sudo DEBIAN_FRONTEND=noninteractive apt install -y postfix mailutils - -# # Postfix als SMTP-Relay einrichten -# sudo tee /etc/postfix/main.cf > /dev/null <&2 - return 2 # Spezieller Fehlercode für ungültige Eingabe - fi - screen -list | grep -q "$target_session" # Rückgabewert 0 = läuft, 1 = nicht läuft -} - -function standalonestart() { - if is_opensim_running; then - echo "OpenSim läuft bereits (Screen: $SCREEN_NAME)." - else - echo "Starte OpenSim in screen '$SCREEN_NAME'..." - cd "$OPENSIM_DIR" || exit 1 - screen -fa -S "$SCREEN_NAME" -d -U -m dotnet OpenSim.dll - echo "OpenSim starten abgeschlossen." - fi - blankline -} - -function standalonestop() { - if is_opensim_running; then - echo "Sende Shutdown-Befehl an OpenSim..." - screen -S "$SCREEN_NAME" -p 0 -X stuff "$SHUTDOWN_CMD^M" - sleep 5 # Warte auf saubere Beendigung - if ! is_opensim_running; then - echo "OpenSim wurde gestoppt." - else - echo "Warnung: OpenSim reagiert nicht auf 'shutdown'. Versuche hartes Stoppen..." - screen -S "$SCREEN_NAME" -X quit - fi - else - echo "OpenSim läuft nicht." - fi - blankline -} - -# Standalone-Service-Neustart (ohne Logbereinigung) -function standalonerestart() { - standalonestop - sleep $Simulator_Stop_wait # Wartezeit für sauberen Shutdown - standalonestart -} - -function standalonestatus() { - if is_opensim_running; then - echo "✅ OpenSim läuft (Screen: $SCREEN_NAME)." - else - echo "❌ OpenSim läuft nicht." - fi -} - -function validate_sim_name() { - local sim_name=$1 - # Überprüfe ob der Name dem Muster sim[1-99] entspricht (case-sensitive) - if [[ ! "$sim_name" =~ ^sim([1-9]|[1-9][0-9])$ ]]; then - log "${SYM_BAD} ${COLOR_WARNING}Ungültiger Sim-Name! Bitte verwende sim1 bis sim99.${COLOR_RESET}" - return 1 - fi - return 0 -} - -# Einzelne Instanzen starten und stoppen - -function simstart() { - local sim_name="$1" - local sim_dir="${sim_name}/bin" - local max_wait=${Simulator_Start_wait:-10} # Default 10 Sekunden Timeout - - # 1. Validierung - if ! validate_sim_name "$sim_name"; then - log "${SYM_BAD} ${COLOR_ERROR}Ungültiger Simulationsname!${COLOR_RESET}" - return 1 - fi - - # 2. Prüfen ob die Simulation bereits läuft - if is_opensim_running "$sim_name"; then - log "${SYM_INFO} ${COLOR_WARNING}Simulation '${sim_name}' läuft bereits!${COLOR_RESET}" - blankline - return 0 - fi - - # 3. Verzeichnisprüfung - if [[ ! -d "$sim_dir" ]]; then - log "${SYM_BAD} ${COLOR_ERROR}Verzeichnis nicht gefunden: ${sim_dir}${COLOR_RESET}" - return 1 - fi - - # 4. Startversuch - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}${sim_name}${COLOR_RESET}" - if ! (cd "$sim_dir" && screen -fa -S "$sim_name" -d -U -m dotnet OpenSim.dll); then - log "${SYM_BAD} ${COLOR_ERROR}Start fehlgeschlagen!${COLOR_RESET}" - return 1 - fi - - # 5. Startüberprüfung mit Timeout - local waited=0 - while ! is_opensim_running "$sim_name" && ((waited < max_wait)); do - sleep 1 - ((waited++)) - echo -n "." - done - echo "" - - # 6. Ergebnis auswerten - if is_opensim_running "$sim_name"; then - log "${SYM_OK} ${COLOR_START}Simulation erfolgreich gestartet (${waited}s).${COLOR_RESET}" - blankline - return 0 - else - log "${SYM_BAD} ${COLOR_ERROR}Timeout: Simulation startet nicht (${max_wait}s)${COLOR_RESET}" - return 1 - fi -} - -function simstop() { - local simstop="$1" - local max_wait=${Simulator_Stop_wait:-15} # Default 15 Sekunden Timeout - - # 1. Validierung - if ! validate_sim_name "$simstop"; then - log "${SYM_BAD} ${COLOR_ERROR}Ungültiger Simulationsname!${COLOR_RESET}" - return 1 - fi - - # 2. Prüfen ob die Simulation läuft - if ! is_opensim_running "$simstop"; then - log "${SYM_INFO} ${COLOR_WARNING}Simulation '$simstop' ist nicht aktiv.${COLOR_RESET}" - blankline - return 0 - fi - - # 3. Stop-Befehl senden - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}${simstop}${COLOR_RESET}" - if ! screen -S "$simstop" -p 0 -X stuff "shutdown^M"; then - log "${SYM_BAD} ${COLOR_ERROR}Konnte Stop-Befehl nicht senden!${COLOR_RESET}" - return 1 - fi - - # 4. Graceful Shutdown mit Timeout - local waited=0 - while is_opensim_running "$simstop" && ((waited < max_wait)); do - sleep 1 - ((waited++)) - echo -n "." - done - echo "" - - # 5. Ergebnis auswerten - if is_opensim_running "$simstop"; then - log "${SYM_BAD} ${COLOR_ERROR}Timeout: Simulation reagiert nicht auf shutdown (${max_wait}s)${COLOR_RESET}" - log "${SYM_INFO} ${COLOR_WARNING}Versuche hartes Stoppen...${COLOR_RESET}" - screen -S "$simstop" -X quit && return 0 || return 1 - else - log "${SYM_OK} ${COLOR_STOP}Simulation sauber gestoppt (${waited}s).${COLOR_RESET}" - blankline - return 0 - fi -} - -function simrestart() { - local simrestart=$1 - if ! validate_sim_name "$simrestart"; then - exit 1 - fi - - simstop "$simrestart" - simstart "$simrestart" - echo - echo "OpenSim Restart abgeschlossen." -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Start Stop Grid -#?────────────────────────────────────────────────────────────────────────────────────────── - -#* OpenSim starten (robust → money → sim1 bis sim999) -function opensimstart() { - log "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}" - - # RobustServer starten - if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" - cd robust/bin || exit 1 - # -inifile=Robust.HG.ini - - screen -fa -S robustserver -d -U -m dotnet Robust.dll - cd - >/dev/null 2>&1 || exit 1 - sleep $RobustServer_Start_wait - else - log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" - fi - - # MoneyServer starten - if [[ -f "robust/bin/MoneyServer.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" - cd robust/bin || exit 1 - screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll - cd - >/dev/null 2>&1 || exit 1 - sleep $MoneyServer_Start_wait - else - log "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}MoneyServer.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" - fi - - # Sim-Regionen starten - for ((i=1; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}" - cd "$sim_dir" || continue - screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll - cd - >/dev/null 2>&1 || continue - sleep $Simulator_Start_wait - fi - done - echo "OpenSim starten abgeschlossen." - blankline -} -# Test OpenSim starten Parallel -function opensimstartParallel() { - log "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}" - - # 1. RobustServer (muss zuerst laufen) - if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" - (cd robust/bin && screen -fa -S robustserver -d -U -m dotnet Robust.dll) - sleep "$RobustServer_Start_wait" - else - log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" - fi - - # 2. MoneyServer (optional) - if [[ -f "robust/bin/MoneyServer.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" - (cd robust/bin && screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll) - sleep "$MoneyServer_Start_wait" - fi - - # 3. SIM1 ZUERST (sequentiell) - if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_START}(primäre Region)...${COLOR_RESET}" - (cd sim1/bin && screen -fa -S sim1 -d -U -m dotnet OpenSim.dll) - sleep "$Simulator_Start_wait" - else - log "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET}" - fi - - # 4. SIM2-SIM99 PARALLEL - log "${SYM_INFO} ${COLOR_START}Starte sekundäre Simulatoren parallel...${COLOR_RESET}" - - # Maximal 10 parallele Jobs - MAX_JOBS=10 - for ((i=2; i<=99; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then - - # Warten falls zu viele Jobs laufen - while (( $(jobs -p | wc -l) >= MAX_JOBS )); do - sleep 1 - done - - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}" - (cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll) & - fi - done - - wait # Warte auf alle Hintergrundjobs - log "${SYM_OK} ${COLOR_START}Alle Simulatoren gestartet.${COLOR_RESET}" - blankline -} - -#* OpenSim stoppen (sim999 bis sim1 → money → robust) -function opensimstop() { - log "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}" - - # Sim-Regionen stoppen - for ((i=999; i>=1; i--)); do - sim_dir="sim$i" - if screen -list | grep -q "$sim_dir"; then - screen -S "sim$i" -p 0 -X stuff "shutdown^M" - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" - sleep $Simulator_Stop_wait - fi - done - - # MoneyServer stoppen - if screen -list | grep -q "moneyserver"; then - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" - screen -S moneyserver -p 0 -X stuff "shutdown^M" - sleep $MoneyServer_Stop_wait - else - log "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET} ${COLOR_STOP}Überspringe Stopp.${COLOR_RESET}" - fi - - # RobustServer stoppen - if screen -list | grep -q "robust"; then - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" - screen -S robustserver -p 0 -X stuff "shutdown^M" - sleep $RobustServer_Stop_wait - else - log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET} ${COLOR_STOP}Überspringe Stopp.${COLOR_RESET}" - fi - echo "OpenSim stoppen abgeschlossen." - blankline -} - -# Das parallele Stoppen in der Reihenfolge sim999 → sim2 parallel, dann sim1 → MoneyServer → RobustServer -function opensimstopParallel() { - log "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}" - local MAX_PARALLEL=10 # Maximale parallele Stopp-Vorgänge - - # 1. Paralleles Stoppen von sim999 bis sim2 - log "${SYM_INFO} ${COLOR_STOP}Stoppe sekundäre Simulatoren parallel...${COLOR_RESET}" - for ((i=999; i>=2; i--)); do - sim_name="sim$i" - - # Warten falls zu viele parallele Jobs laufen - #while [ $(jobs -p | wc -l) -ge $MAX_PARALLEL ]; do - while [ "$(jobs -p | wc -l)" -ge $MAX_PARALLEL ]; do - sleep 0.5 - done - - if screen -list | grep -q "$sim_name"; then - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}$sim_name${COLOR_RESET}" - ( - screen -S "$sim_name" -p 0 -X stuff "shutdown^M" - sleep $Simulator_Stop_wait - ) & - fi - done - wait # Warte auf alle parallelen Stopp-Vorgänge - - # 2. Sim1 sequentiell stoppen - if screen -list | grep -q "sim1"; then - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_STOP}(primäre Region)...${COLOR_RESET}" - screen -S "sim1" -p 0 -X stuff "shutdown^M" - sleep $Simulator_Stop_wait - fi - - # 3. MoneyServer stoppen - if screen -list | grep -q "moneyserver"; then - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" - screen -S moneyserver -p 0 -X stuff "shutdown^M" - sleep $MoneyServer_Stop_wait - else - log "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" - fi - - # 4. RobustServer stoppen (zuletzt) - if screen -list | grep -q "robustserver"; then - log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" - screen -S robustserver -p 0 -X stuff "shutdown^M" - sleep $RobustServer_Stop_wait - else - log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" - fi - - log "${SYM_OK} ${COLOR_STOP}Alle Dienste gestoppt.${COLOR_RESET}" - blankline -} - -# check_screens ist eine Grid Funktion und funktioniert nicht im Standalone. -function check_screens() { - # echo "Überprüfung der laufenden OpenSim-Prozesse..." - - restart_all=false - - # Überprüfen, ob RobustServer läuft - if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then - screenRO=$(screen -ls | grep -w "robustserver") - if [[ -z "$screenRO" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log - restart_all=true - else - echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft ✓" - fi - fi - - # Überprüfen, ob MoneyServer läuft - if [[ -d "robust/bin" && -f "robust/bin/MoneyServer.dll" ]];then - screenMoney=$(screen -ls | grep -w "moneyserver") - if [[ -z "$screenMoney" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log - restart_all=true - else - echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft ✓" - fi - fi - - # Überprüfen, ob sim1 läuft - if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then - screenSim1=$(screen -ls | grep -w "sim1") - if [[ -z "$screenSim1" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log - restart_all=true - else - echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft ✓" - fi - fi - - # Falls eines der kritischen Systeme ausgefallen ist, alles neu starten - if [[ "$restart_all" == true ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - Kritische Prozesse sind ausgefallen! OpenSim wird komplett neu gestartet." >> ProblemRestarts.log - # opensimstart - opensimrestart - return 0 - fi - - # Überprüfen, ob andere Regionen (sim2 bis sim999) einzeln neu gestartet werden müssen - for ((i=2; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then - screenSim=$(screen -ls | grep -w "sim$i") - if [[ -z "$screenSim" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft nicht und wird einzeln neu gestartet." >> ProblemRestarts.log - cd "$sim_dir" || continue - screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll - cd - >/dev/null 2>&1 || continue - sleep $Simulator_Start_wait - else - echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft ✓" - fi - fi - done - blankline -} - -# Falls ein Screen einmal nicht beenden will. -function simkill() { - local SIMKILL=$1 - local CONFIRM - - # Existenzprüfung - if ! screen -list | grep -q "$SIMKILL"; then - log "${SYM_BAD} ${COLOR_ERROR}Screen '${COLOR_SERVER}$SIMKILL${COLOR_ERROR}' nicht gefunden!${COLOR_RESET}" - return 1 - fi - - # Bestätigung - log "${SYM_WARNING} ${COLOR_WARNING}Warnung:${COLOR_RESET}" - read -rp "Soll Screen '${COLOR_SERVER}$SIMKILL${COLOR_RESET}' wirklich beendet werden? [y/N] " CONFIRM - [[ $CONFIRM =~ ^[Yy]$ ]] || { - log "${SYM_INFO} ${COLOR_ACTION}Abbruch durch Benutzer.${COLOR_RESET}" - return 1 - } - - # Erst ordnungsgemäß beenden versuchen - log "${SYM_WAIT} ${COLOR_ACTION}Versuche ordentliches Beenden...${COLOR_RESET}" - if screen -S "$SIMKILL" -X quit; then - log "${SYM_OK} ${COLOR_SUCCESS}Screen '${COLOR_SERVER}$SIMKILL${COLOR_SUCCESS}' erfolgreich beendet.${COLOR_RESET}" - return 0 - fi - - # Falls nötig, hart killen - log "${SYM_WARNING} ${COLOR_WARNING}Ordentliches Beenden fehlgeschlagen, erzwinge Kill...${COLOR_RESET}" - if screen -S "$SIMKILL" -X kill; then - log "${SYM_OK} ${COLOR_SUCCESS}Screen '${COLOR_SERVER}$SIMKILL${COLOR_SUCCESS}' wurde gekillt.${COLOR_RESET}" - return 0 - else - log "${SYM_BAD} ${COLOR_ERROR}Schwerer Fehler: Screen '${COLOR_SERVER}$SIMKILL${COLOR_ERROR}' konnte nicht beendet werden!${COLOR_RESET}" - return 1 - fi -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Erstellen eines OpenSimulators -#?────────────────────────────────────────────────────────────────────────────────────────── - -opensim_clone() { - # Stille Klon-Funktion mit automatischem Fallback - local max_retries=3 - local retry_delay=2 - - for ((i=1; i<=max_retries; i++)); do - # 1. Versuch: HTTPS (standard) - if git clone https://opensimulator.org/git/opensim opensim --quiet 2>/dev/null; then - return 0 - fi - - # 2. Versuch: Git-Protokoll (falls HTTPS blockiert) - if git clone git://opensimulator.org/git/opensim opensim --quiet 2>/dev/null; then - return 0 - fi - - # Bei Fehler temporäres Verzeichnis bereinigen - rm -rf opensim &>/dev/null - sleep $retry_delay - done - - return 1 -} - -function opensimgitcopy() { - log "${SYM_BOOK}${COLOR_HEADING} OpenSimulator GitHub-Verwaltung${COLOR_RESET}" - - # Zuerst versuchen, ein einfaches git pull durchzuführen, falls Repository existiert - if [[ -d "opensim/.git" ]]; then - log "${SYM_WAIT} ${COLOR_ACTION}Versuche einfaches Update via git pull...${COLOR_RESET}" - cd opensim || { - log "${SYM_BAD} ${COLOR_ERROR}Verzeichniswechsel fehlgeschlagen!${COLOR_RESET}" - return 1 - } - - old_head=$(git rev-parse HEAD) - if git pull origin master; then - if [ "$old_head" == "$(git rev-parse HEAD)" ]; then - log "${SYM_OK} ${COLOR_ACTION}Keine neuen Updates verfügbar.${COLOR_RESET}" - else - log "${SYM_OK} ${COLOR_SUCCESS}Update erfolgreich durchgeführt!${COLOR_RESET}" - fi - cd .. - - # Nach erfolgreichem Update Kompatibilität prüfen - check_dotnet_compatibility - # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() - versionrevision - log # Leerzeile für bessere Lesbarkeit - return 0 - else - log "${SYM_BAD} ${COLOR_WARNING}Einfaches Update fehlgeschlagen, fahre mit Standardverfahren fort...${COLOR_RESET}" - cd .. - fi - fi - - # Falls einfaches git pull nicht möglich ist, normale Abfrage durchführen - log "${COLOR_LABEL}Möchten Sie den OpenSimulator vom GitHub verwenden oder aktualisieren? (${COLOR_OK}[upgrade]${COLOR_LABEL}/new)${COLOR_RESET}" - read -r user_choice - user_choice=${user_choice:-upgrade} - - if [[ "$user_choice" == "new" ]]; then - if [[ -d "opensim" ]]; then - log "${COLOR_ACTION}Vorhandene OpenSimulator-Version wird gelöscht...${COLOR_RESET}" - rm -rf opensim - log "${SYM_OK} ${COLOR_ACTION}Alte OpenSimulator-Version wurde erfolgreich entfernt.${COLOR_RESET}" - fi - - log "${SYM_WAIT} ${COLOR_ACTION}OpenSimulator wird von GitHub geholt...${COLOR_RESET}" - if opensim_clone; then - log "${SYM_OK} ${COLOR_SUCCESS}Download erfolgreich!${COLOR_RESET}" - log "${SYM_WAIT} ${COLOR_ACTION}Überprüfe Repository-Integrität...${COLOR_RESET}" - - if check_repo_integrity "opensim"; then - log "${SYM_OK} ${COLOR_ACTION}Repository ist intakt.${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt!${COLOR_RESET}" - return 1 - fi - else - log "${SYM_BAD} ${COLOR_ERROR}Download fehlgeschlagen!${COLOR_RESET}" - log "${COLOR_WARNING}Bitte Netzwerkverbindung prüfen und später erneut versuchen.${COLOR_RESET}" - return 1 - fi - - elif [[ "$user_choice" == "upgrade" ]]; then - if [[ -d "opensim/.git" ]]; then - # Erneuter Versuch (falls vorheriger pull fehlgeschlagen) - cd opensim || return 1 - if git pull origin master; then - log "${SYM_OK} ${COLOR_SUCCESS}Update erfolgreich durchgeführt!${COLOR_RESET}" - cd .. - - # Nach erfolgreichem Update Kompatibilität prüfen - check_dotnet_compatibility - # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() - versionrevision - log # Leerzeile für bessere Lesbarkeit - return 0 - else - log "${SYM_BAD} ${COLOR_ERROR}Update fehlgeschlagen!${COLOR_RESET}" - cd .. - return 1 - fi - else - log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Kein Repository gefunden. Starte Neuinstallation...${COLOR_RESET}" - opensimgitcopy "new" - return $? - fi - else - log "${SYM_BAD} ${COLOR_ERROR}Ungültige Eingabe!${COLOR_RESET}" - return 1 - fi - - # .NET-Kompatibilität prüfen - check_dotnet_compatibility - # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() - versionrevision - - blankline -} - -check_dotnet_compatibility() { - cd opensim || return 1 - local dotnet_version - dotnet_version=$(dotnet --version 2>/dev/null | awk -F. '{print $1}') - - case $dotnet_version in - 6) - git checkout -q dotnet6 - log "${SYM_OK} ${COLOR_ACTION}Für .NET 6 konfiguriert.${COLOR_RESET}" - ;; - 7|8) - log "${SYM_OK} ${COLOR_ACTION}Kompatibel mit .NET $dotnet_version.${COLOR_RESET}" - ;; - *) - log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Keine .NET-Version erkannt. Verwende Standard.${COLOR_RESET}" - ;; - esac - cd .. -} - -function moneygitcopy() { - log "${COLOR_HEADING}💰 MoneyServer GitHub-Verwaltung${COLOR_RESET}" - - log "${COLOR_LABEL}Möchten Sie den MoneyServer vom GitHub verwenden oder aktualisieren? (${COLOR_OK}[upgrade]${COLOR_LABEL}/new)${COLOR_RESET}" - read -r user_choice - user_choice=${user_choice:-upgrade} - - if [[ "$user_choice" == "new" ]]; then - if [[ -d "opensimcurrencyserver" ]]; then - log "${COLOR_ACTION}Vorhandene MoneyServer-Version wird gelöscht...${COLOR_RESET}" - rm -rf opensimcurrencyserver - log "${SYM_OK} ${COLOR_ACTION}Alte MoneyServer-Version wurde erfolgreich entfernt.${COLOR_RESET}" - fi - - log "${COLOR_ACTION}MONEYSERVER: MoneyServer wird vom GIT geholt...${COLOR_RESET}" - if ! git clone https://github.com/ManfredAabye/opensimcurrencyserver-dotnet.git opensimcurrencyserver; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" - return 1 - fi - - if ! check_repo_integrity "opensimcurrencyserver"; then - log "${SYM_BAD} ${COLOR_ERROR}MoneyServer-Repository beschädigt!${COLOR_RESET}" - return 1 - fi - - log "${SYM_OK} ${COLOR_ACTION}MoneyServer wurde erfolgreich heruntergeladen.${COLOR_RESET}" - - elif [[ "$user_choice" == "upgrade" ]]; then - if [[ -d "opensimcurrencyserver/.git" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Repository gefunden. Aktualisiere mit 'git pull'...${COLOR_RESET}" - cd opensimcurrencyserver || { log "${SYM_BAD} ${COLOR_ERROR}Fehler: Kann nicht ins Verzeichnis wechseln!${COLOR_RESET}"; return 1; } - - # Branch-Erkennung mit Fehlerbehandlung - branch_name=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') - if [ -z "$branch_name" ]; then - branch_name="master" - log "${COLOR_WARNING}Standard-Branch 'master' wird verwendet.${COLOR_RESET}" - fi - - old_head=$(git rev-parse HEAD) - - if ! git pull origin "$branch_name"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Aktualisieren!${COLOR_RESET}" - cd .. - return 1 - fi - - if [ "$old_head" == "$(git rev-parse HEAD)" ]; then - log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}MoneyServer ist bereits aktuell.${COLOR_RESET}" - else - log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}MoneyServer erfolgreich aktualisiert!${COLOR_RESET}" - fi - - if ! check_repo_integrity; then - log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt nach Pull!${COLOR_RESET}" - cd .. - return 1 - fi - - cd .. - else - log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}MoneyServer-Verzeichnis nicht gefunden. Klone Repository neu...${COLOR_RESET}" - if ! git clone https://github.com/ManfredAabye/opensimcurrencyserver-dotnet.git opensimcurrencyserver; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" - return 1 - fi - log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}MoneyServer erfolgreich heruntergeladen!${COLOR_RESET}" - fi - else - log "${SYM_BAD} ${COLOR_ERROR}Abbruch: Keine Aktion durchgeführt.${COLOR_RESET}" - return 1 - fi - - # Verbesserte Dateikopierfunktion mit Prüfungen - copy_with_checks() { - local src=$1 - local dest=$2 - - if [ ! -d "$src" ]; then - log "${SYM_BAD} ${COLOR_ERROR}Quellverzeichnis $src nicht gefunden!${COLOR_RESET}" - return 1 - fi - - mkdir -p "$dest" - if ! cp -r "$src" "$dest"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Kopieren von $src!${COLOR_RESET}" - return 1 - fi - - log "${SYM_OK} ${COLOR_ACTION}Erfolgreich kopiert: $src → $dest${COLOR_RESET}" - return 0 - } - - # Kopiervorgänge mit Fehlerbehandlung - copy_with_checks "opensimcurrencyserver/addon-modules" "opensim/" || return 1 - copy_with_checks "opensimcurrencyserver/bin" "opensim/" || return 1 - - blankline - return 0 -} - -function osslscriptsgit() { - log "${COLOR_HEADING}📜 OSSL Beispiel-Skripte GitHub-Verwaltung${COLOR_RESET}" - - log "${COLOR_LABEL}Möchten Sie die OpenSim OSSL Beispiel-Skripte vom GitHub verwenden oder aktualisieren? (${COLOR_OK}[upgrade]${COLOR_LABEL}/new)${COLOR_RESET}" - read -r user_choice - user_choice=${user_choice:-upgrade} - - repo_name="opensim-ossl-example-scripts" - repo_url="https://github.com/ManfredAabye/opensim-ossl-example-scripts.git" - - if [[ "$user_choice" == "new" ]]; then - if [[ -d "$repo_name" ]]; then - log "${COLOR_ACTION}Vorhandene Version wird gelöscht...${COLOR_RESET}" - rm -rf "$repo_name" - log "${SYM_OK} ${COLOR_ACTION}Alte Version wurde erfolgreich entfernt.${COLOR_RESET}" - fi - - log "${COLOR_ACTION}Beispiel-Skripte werden vom GitHub heruntergeladen...${COLOR_RESET}" - if ! git clone "$repo_url" "$repo_name"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" - return 1 - fi - - if ! check_repo_integrity "$repo_name"; then - log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt!${COLOR_RESET}" - return 1 - fi - - log "${SYM_OK} ${COLOR_ACTION}Repository wurde erfolgreich heruntergeladen.${COLOR_RESET}" - - elif [[ "$user_choice" == "upgrade" ]]; then - if [[ -d "$repo_name/.git" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Repository gefunden. Aktualisiere mit 'git pull'...${COLOR_RESET}" - cd "$repo_name" || { log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Wechsel ins Verzeichnis!${COLOR_RESET}"; return 1; } - - branch_name=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') - [ -z "$branch_name" ] && branch_name="main" - - old_head=$(git rev-parse HEAD) - - if ! git pull origin "$branch_name"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Pull!${COLOR_RESET}" - cd .. - return 1 - fi - - if [ "$old_head" != "$(git rev-parse HEAD)" ]; then - log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Neue Updates wurden installiert.${COLOR_RESET}" - else - log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Repository ist bereits aktuell.${COLOR_RESET}" - fi - - if ! check_repo_integrity; then - log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt nach Pull!${COLOR_RESET}" - cd .. - return 1 - fi - - cd .. - else - log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Verzeichnis nicht gefunden oder kein Git-Repo. Klone Repository neu...${COLOR_RESET}" - if ! git clone "$repo_url" "$repo_name"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" - return 1 - fi - log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Repository wurde erfolgreich heruntergeladen.${COLOR_RESET}" - fi - else - log "${SYM_BAD} ${COLOR_ERROR}Abbruch: Keine Aktion durchgeführt.${COLOR_RESET}" - return 1 - fi - - # Verbesserte Kopierfunktion - safe_copy() { - local src=$1 - local dest=$2 - - if [ ! -e "$src" ]; then - log "${SYM_BAD} ${COLOR_ERROR}Quelle '$src' existiert nicht!${COLOR_RESET}" - return 1 - fi - - mkdir -p "$(dirname "$dest")" - if ! cp -r "$src" "$dest"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Kopieren von '$src'!${COLOR_RESET}" - return 1 - fi - - log "${SYM_OK} ${COLOR_ACTION}Erfolgreich kopiert: $src → $dest${COLOR_RESET}" - return 0 - } - - # Zielverzeichnisse erstellen mit Fehlerbehandlung - mkdir -p opensim/bin/assets/ || { log "${SYM_BAD} ${COLOR_ERROR}Konnte Verzeichnis nicht erstellen!${COLOR_RESET}"; return 1; } - mkdir -p opensim/bin/inventory/ || { log "${SYM_BAD} ${COLOR_ERROR}Konnte Verzeichnis nicht erstellen!${COLOR_RESET}"; return 1; } - - # Kopiervorgänge mit Fehlerbehandlung - safe_copy "$repo_name/ScriptsAssetSet" "opensim/bin/assets/" || return 1 - safe_copy "$repo_name/inventory/ScriptsLibrary" "opensim/bin/inventory/" || return 1 - - blankline - return 0 -} - -####################################### - -#* Das ist erst halb fertig. -function ruthrothgit() { - # Schritt 1 das bereitstellen der Pakete zur weiteren bearbeitung. - log "${COLOR_HEADING}👥 Ruth & Roth Avatar-Assets Vorbereitung${COLOR_RESET}" - - base_dir="ruthroth" - mkdir -p "$base_dir" - - declare -A repos=( - ["Ruth2"]="https://github.com/ManfredAabye/Ruth2.git" - ["Roth2"]="https://github.com/ManfredAabye/Roth2.git" - ) - - for avatar in "${!repos[@]}"; do - repo_url="${repos[$avatar]}" - target_dir="$avatar" - - if [[ ! -d "$target_dir" ]]; then - log " ${COLOR_ACTION}➜ Klone ${COLOR_SERVER}$avatar${COLOR_ACTION} von GitHub...${COLOR_RESET}" - git clone "$repo_url" "$target_dir" && log " ${COLOR_OK}${SYM_OKNN} ${COLOR_SERVER}$avatar${COLOR_RESET} ${COLOR_ACTION}wurde heruntergeladen.${COLOR_RESET}" - else - log " ${COLOR_OK}${SYM_OKNN} ${COLOR_SERVER}$avatar${COLOR_RESET} ${COLOR_ACTION}ist bereits vorhanden, überspringe Download.${COLOR_RESET}" - fi - - # Kopiere nur die relevanten IAR-Dateien direkt nach ruthroth - log " ${COLOR_ACTION}➜ Kopiere benötigte IAR-Dateien nach ${COLOR_DIR}$base_dir${COLOR_ACTION}...${COLOR_RESET}" - cp "$target_dir/Artifacts/IAR/"*.iar "$base_dir/" 2>/dev/null && log " ${SYM_OK} IAR-Dateien von ${COLOR_SERVER}$avatar${COLOR_RESET} kopiert.${COLOR_RESET}" - done - - # Kopiere das updatelibrary.py-Skript ins Hauptverzeichnis ruthroth - log " ${COLOR_ACTION}➜ Kopiere updatelibrary.py nach ${COLOR_DIR}$base_dir${COLOR_ACTION}...${COLOR_RESET}" - cp "updatelibrary.py" "$base_dir/" && log " ${SYM_OK} updatelibrary.py wurde kopiert.${COLOR_RESET}" - - echo "Verzeichniswechsel in $base_dir" - - # Wechsel ins ruthroth-Verzeichnis - cd "$base_dir" || { log "${SYM_BAD} Fehler beim Wechsel ins Verzeichnis ${COLOR_DIR}$base_dir${COLOR_RESET}"; return 1; } - - # Entpacke die IAR-Dateien direkt in ruthroth - log " ${COLOR_ACTION}➜ Entpacke IAR-Pakete in ${COLOR_DIR}$base_dir${COLOR_ACTION}...${COLOR_RESET}" - for iar_file in *.iar; do - if [[ -f "$iar_file" ]]; then - target_dir="${iar_file%.iar}" # Erstellt Verzeichnisname basierend auf Dateiname ohne .iar - mkdir -p "$target_dir" - tar -xzf "$iar_file" -C "$target_dir/" && log " ✓ ${iar_file} entpackt nach ${target_dir}" - else - log " ${SYM_WARNING} IAR-Datei ${iar_file} nicht gefunden. Überspringe..." - fi - done - - log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Grundlage für die OpenSimulator-Pakete wurde erfolgreich erstellt!${COLOR_RESET}" - - # Schritt 2 die verwendung von updatelibrary.py. - cd ruthroth - python3 updatelibrary.py -n "Roth2-v1" -s "Roth2-v1" -a Roth2-v1 -i Roth2-v1 - python3 updatelibrary.py -n "Roth2-v2" -s "Roth2-v2" -a Roth2-v2 -i Roth2-v2 - python3 updatelibrary.py -n "Ruth2-v3" -s "Ruth2-v3" -a Ruth2-v3 -i Ruth2-v3 - python3 updatelibrary.py -n "Ruth2-v4" -s "Ruth2-v4" -a Ruth2-v4 -i Ruth2-v4 - cd .. - # Schritt 3 das kopieren der Daten. Das einfügen der Daten in den Dateien ähnlich wie bei PBR. -} - -# Es werden die Konfiguartionen jetzt auch geändert. -function pbrtexturesgit() { - log "${COLOR_HEADING}🎨 PBR Texturen Installation${COLOR_RESET}" - - textures_zip_url="https://github.com/ManfredAabye/OpenSim_PBR_Textures/releases/download/PBR/OpenSim_PBR_Textures.zip" - zip_file="OpenSim_PBR_Textures.zip" - unpacked_dir="OpenSim_PBR_Textures" - target_dir="opensim" - - # ZIP herunterladen, wenn nicht vorhanden - if [[ ! -f "$zip_file" ]]; then - log "${COLOR_ACTION}Lade OpenSim PBR Texturen herunter...${COLOR_RESET}" - if ! wget -q --show-progress -O "$zip_file" "$textures_zip_url"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Herunterladen der Texturen!${COLOR_RESET}" - return 1 - fi - log "${SYM_OK} ${COLOR_ACTION}Download abgeschlossen: ${COLOR_DIR}$zip_file${COLOR_RESET}" - else - log "${SYM_OK} ${COLOR_ACTION}ZIP-Datei bereits vorhanden: ${COLOR_DIR}$zip_file${COLOR_RESET}" - fi - - # Entpacken, wenn Verzeichnis noch nicht existiert - if [[ ! -d "$unpacked_dir" ]]; then - log "${COLOR_ACTION}Entpacke Texturen nach ${COLOR_DIR}$unpacked_dir${COLOR_ACTION}...${COLOR_RESET}" - unzip -q "$zip_file" -d . - log "${SYM_OK} ${COLOR_ACTION}Entpackt.${COLOR_RESET}" - else - log "${SYM_OK} ${COLOR_ACTION}Verzeichnis ${COLOR_DIR}$unpacked_dir${COLOR_ACTION} existiert bereits – überspringe Entpacken.${COLOR_RESET}" - fi - - # Kopieren nach opensim/bin - if [[ -d "$unpacked_dir/bin" ]]; then - log "${COLOR_ACTION}Kopiere Texturen nach ${COLOR_DIR}$target_dir${COLOR_ACTION}...${COLOR_RESET}" - cp -r "$unpacked_dir/bin" "$target_dir" - log "${SYM_OK} ${COLOR_ACTION}Texturen erfolgreich installiert in ${COLOR_DIR}$target_dir${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_ERROR}Verzeichnis ${COLOR_DIR}$unpacked_dir/bin${COLOR_ERROR} nicht gefunden!${COLOR_RESET}" - return 1 - fi - - local asset_sets_file="opensim/bin/assets/AssetSets.xml" - local libraries_file="opensim/bin/inventory/Libraries.xml" - - # Funktion zur Überprüfung und Hinzufügung eines Eintrags - add_xml_section() { - local file="$1" - local section_name="$2" - local content="$3" - - # Überprüfen ob der Abschnitt bereits existiert - if ! grep -q "
" "$file"; then - # Abschnitt vor einfügen - sed -i "s||
\n$content\n
\n|" "$file" - echo "Added $section_name to $file" - else - echo "$section_name already exists in $file - no changes made" - fi - } - - # AssetSets.xml bearbeiten - add_xml_section "$asset_sets_file" "PBR Textures AssetSet" \ - " " - - # Libraries.xml bearbeiten - add_xml_section "$libraries_file" "PBRTextures Library" \ - " \n " - - blankline - return 0 -} - -function osWebinterfacegit() { - log "${COLOR_HEADING}🌐 Webinterface Installation${COLOR_RESET}" - - webverzeichnis="oswebinterface" - - # Abfrage zur Installation mit Default "Nein" - log "${COLOR_LABEL}Möchten Sie das OpenSim Webinterface installieren? ()j/N) ${COLOR_RESET} [n]" - read -r install_webinterface - if [[ ! "$install_webinterface" =~ ^[jJ][aA]?$ ]]; then - log "${COLOR_INFO}Installation abgebrochen (Default: Nein)${COLOR_RESET}" - blankline - return 0 - fi - - setup_webserver - - # 1. PHP-Check mit Distro-Erkennung - if ! command -v php &>/dev/null; then - log "${SYM_WARNING} ${COLOR_WARNING}PHP ist nicht installiert!${COLOR_RESET}" - - # Distro-Erkennung - # shellcheck source=/dev/null - source /etc/os-release - case $ID in - debian|ubuntu|linuxmint|pop|mx|zorin|elementary) - pkg_cmd="sudo apt-get install -y php php-mysql php-gd php-curl" - ;; - arch|manjaro) - pkg_cmd="sudo pacman -S --noconfirm php php-gd php-curl" - ;; - fedora|centos|rhel) - pkg_cmd="sudo dnf install -y php php-mysqlnd php-gd php-common" - ;; - opensuse|sles) - pkg_cmd="sudo zypper install -y php7 php7-mysql php7-gd php7-curl" - ;; - *) - log "${SYM_BAD} ${COLOR_ERROR}Unterstützte Distribution nicht erkannt!${COLOR_RESET}" - echo "Manuell installieren: php php-mysql php-gd php-curl" - return 1 - ;; - esac - - log "PHP auf ${PRETTY_NAME} installieren? (j/n) " - read -r install_php - if [[ "$install_php" =~ ^[jJ] ]]; then - log "${COLOR_ACTION}Installiere PHP... (${pkg_cmd})${COLOR_RESET}" - if ! eval "$pkg_cmd"; then - log "${SYM_BAD} ${COLOR_ERROR}PHP-Installation fehlgeschlagen!${COLOR_RESET}" - return 1 - fi - log "${COLOR_OK}${SYM_OKNN} PHP erfolgreich installiert!${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_ERROR}Abbruch: PHP ist erforderlich.${COLOR_RESET}" - return 1 - fi - else - log "${COLOR_OK}${SYM_OKNN} PHP ist installiert ($(php -v | head -n 1))${COLOR_RESET}" - fi - - # 2. Webverzeichnis-Check mit automatischer User/Group-Erkennung - local webroot="/var/www/html" - [[ -d "/var/www" && ! -d "$webroot" ]] && webroot="/var/www" # Fallback für einige Distros - - if [[ ! -d "$webroot" ]]; then - log "${SYM_BAD} ${COLOR_ERROR}Webroot nicht gefunden in:${COLOR_RESET}" - echo "/var/www/html oder /var/www" - echo "Tipp: Apache/Nginx zuerst installieren" - return 1 - fi - - # Bestimme den richtigen Benutzer und Gruppe basierend auf existierenden Dateien - local target_user target_group - # Suche nach einer existierenden Datei oder Verzeichnis im Webroot - sample_file=$(find "$webroot" -maxdepth 1 -type f -print -quit 2>/dev/null || true) - sample_dir=$(find "$webroot" -maxdepth 1 -type d ! -path "$webroot" -print -quit 2>/dev/null || true) - - if [ -n "$sample_file" ]; then - target_user=$(stat -c '%U' "$sample_file") - target_group=$(stat -c '%G' "$sample_file") - elif [ -n "$sample_dir" ]; then - target_user=$(stat -c '%U' "$sample_dir") - target_group=$(stat -c '%G' "$sample_dir") - else - # Fallback: Standard-Webserver-User je nach Distribution - # shellcheck source=/dev/null - source /etc/os-release - case $ID in - debian|ubuntu|linuxmint|pop|mx|zorin|elementary) - target_user="www-data" - target_group="www-data" - ;; - arch|manjaro) - target_user="http" - target_group="http" - ;; - fedora|centos|rhel) - target_user="apache" - target_group="apache" - ;; - opensuse|sles) - target_user="wwwrun" - target_group="www" - ;; - *) - target_user="www-data" - target_group="www-data" - ;; - esac - fi - - # 3. Git-Operationen - if [[ ! -d "oswebinterface" ]]; then - git clone https://github.com/ManfredAabye/oswebinterface.git oswebinterface || return 1 - else - cd oswebinterface || return 1 - git pull origin "$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')" || return 1 - cd .. - fi - - # 4. Deployment mit korrekten Berechtigungen - log "${COLOR_ACTION}Kopiere Webinterface nach ${webroot}/${webverzeichnis}...${COLOR_RESET}" - if ! sudo cp -r "oswebinterface" "$webroot/$webverzeichnis"; then - log "${SYM_BAD} ${COLOR_ERROR}Kopieren fehlgeschlagen!${COLOR_RESET}" - return 1 - fi - - log "${COLOR_ACTION}Setze Besitzer auf ${target_user}:${target_group}...${COLOR_RESET}" - if ! sudo chown -R "$target_user:$target_group" "$webroot/$webverzeichnis"; then - log "${SYM_BAD} ${COLOR_ERROR}Besitzer ändern fehlgeschlagen!${COLOR_RESET}" - return 1 - fi - - log "${COLOR_ACTION}Setze Dateiberechtigungen...${COLOR_RESET}" - if ! sudo find "$webroot/$webverzeichnis" -type d -exec chmod 755 {} \; || \ - ! sudo find "$webroot/$webverzeichnis" -type f -exec chmod 644 {} \; ; then - log "${SYM_BAD} ${COLOR_ERROR}Berechtigungen setzen fehlgeschlagen!${COLOR_RESET}" - return 1 - fi - - log "${COLOR_OK}${SYM_OKNN} Erfolgreich installiert nach: ${COLOR_DIR}$webroot/$webverzeichnis${COLOR_RESET}" - log " Benutzer/Gruppe: ${COLOR_INFO}$target_user:$target_group${COLOR_RESET}" - blankline - return 0 -} - -function versionrevision() { - file="opensim/OpenSim/Framework/VersionInfo.cs" - - #xflavour="Unknown" - #xflavour="Dev" - #xflavour="RC1" - #xflavour="RC2" - #xflavour="RC3" - #xflavour="Release" - #xflavour="Post_Fixes" - xflavour="Extended" - - if [[ ! -f "$file" ]]; then - log "${SYM_BAD} ${COLOR_ERROR}Datei nicht gefunden: ${COLOR_DIR}$file${COLOR_RESET}" - return 1 - fi - - log "${SYM_OK} ${COLOR_ACTION}Bearbeite Datei: ${COLOR_DIR}$file${COLOR_RESET}" - - # Ändere Flavour.Dev - sed -i 's/public const Flavour VERSION_FLAVOUR = Flavour\.[^;]*;/public const Flavour VERSION_FLAVOUR = Flavour.'"$xflavour"';/' "$file" - - # Entferne "Nessie" aus dem Versions-String - sed -i 's/OpenSim {versionNumber} Nessie {flavour}/OpenSim {versionNumber} {flavour}/' "$file" - - log "${SYM_OK} ${COLOR_ACTION}Änderungen zu $xflavour wurden erfolgreich vorgenommen.${COLOR_RESET}" - blankline - return 0 -} - -function generate_name() { - # Arrays mit Namensbestandteilen (alle einzigartig) - - local firstnames=( - # Vornamen - "Mystic" "Arcane" "Eldritch" "Enigmatic" "Esoteric" "Occult" "Cryptic" "Celestial" "Astral" "Ethereal" - "Luminous" "Radiant" "Prismatic" "Iridescent" "Phantasmal" "Spectral" "Otherworldly" "Transcendent" "Timeless" "Unearthly" - "Enchanted" "Charmed" "Bewitched" "Mythic" "Legendary" - "Verdant" "Sylvan" "Petrified" "Thundering" "Whispering" "Howling" "Roaring" "Rumbling" "Crystalline" "Obsidian" - "Amber" "Jade" "Sapphire" "Emerald" "Ruby" "Topaz" "Opaline" "Pearlescent" "Gilded" "Argent" - "Solar" "Lunar" "Stellar" "Nebular" "Galactic" - "Aether" "Runeweaver" "Dragonheart" "Moonshadow" "Spellbinder" "Witchbloom" "Grimoire" "Shadowalker" "Starborn" "Voidwhisper" - "Dreamwalker" "Fatesender" "Glyphborn" "Hollowveil" "Ivyroot" "Jadewhisper" "Kindlespark" "Lorekeeper" "Netherflame" "Oathbound" - "Pixieglen" "Quicksilver" "Ravenoak" "Silvershade" "Twilightthorn" - "Aerendyl" "Beltharion" "Celeborn" "Diorath" "Elrondar" "Faelivrin" "Galadhor" "Haldirion" "Ithilwen" "Jarathmel" - "Kelebrind" "Lothmiriel" "Melianthar" "Nimlothiel" "Oropherion" "Pelenor" "Quelamar" "Rivendell" "Silmarion" "Thranduvar" - "Ulmoen" "Vanyarion" "Windathar" "Xylanthir" "Yavanniel" - "Andromeda" "Beowulf" "Cybernova" "Deusex" "Eclipse" "Frostbyte" "Gigawatt" "Hyperion" "Io" "Jupiter" - "Krypton" "Lunarc" "Megatron" "Nebula" "Orion" "Pulsar" "Quantum" "Robodoc" "Starbuck" "Titan" - "Uranus" "Vortex" "Warpcore" "Xenon" "Zenith" - ) - - local lastnames=( - # Nachnamen - "Forest" "Grove" "Copse" "Thicket" "Wildwood" "Jungle" "Rainforest" "Mangrove" "Taiga" "Tundra" - "Mountain" "Peak" "Summit" "Cliff" "Crag" "Bluff" "Mesa" "Plateau" "Canyon" "Ravine" - "Valley" "Dale" "Glen" "Hollow" "Basin" - "River" "Stream" "Brook" "Creek" "Fjord" "Lagoon" "Estuary" "Delta" "Bayou" "Wetland" - "Oasis" "Geyser" "Spring" "Well" "Aquifer" - "Observatory" "Planetarium" "Orrery" "Reflectory" "Conservatory" "Atrium" "Rotunda" "Gazebo" "Pavilion" "Terrace" - "Ashenwood" "Bramblethorn" "Cliffhaven" "Dewspark" "Emberglade" "Frostvein" "Goldleaf" "Hailstone" "Ironbark" "Jasperridge" - "Kelpstrand" "Lavafall" "Mossgrip" "Nettlebrook" "Oakenshield" "Pinecrest" "Quartzpeak" "Rimefrost" "Stormbreak" "Tidepool" - "Umbravale" "Vinecreep" "Willowshade" "Xylem" "Yewroot" - "Aranel" "Beleriand" "Cirdan" "Doriath" "Eregion" "Fangorn" "Gondolin" "Hithlum" "Imladris" "Jarngard" - "Kementari" "Lorien" "Mirkwood" "Nargothrond" "Osgiliath" "Pelargir" "Quendi" "Rhosgobel" "Sindar" "Tirion" - "Undomiel" "Valinor" "Westfold" "Xandoria" "Yavanna" - "Axiom" "Borg" "Coruscant" "Dyson" "Expanse" "Federation" "Genesis" "Horizon" "Infinity" "Jovian" - "Kessel" "Lazarus" "Matrix" "Nostromo" "Outland" "Prometheus" "Quadrant" "Rapture" "Serenity" "Trifid" - "Umbra" "Voyager" "Weyland" "Xenomorph" "Zodiac" - ) - - gennamefirst="${firstnames[$RANDOM % ${#firstnames[@]}]}" # übergebe das an generate_all_name() - gennamesecond="${lastnames[$RANDOM % ${#lastnames[@]}]}" # übergebe das an generate_all_name() - -} -function generate_all_name() { - # Alle Namen und Bezeichnungen für die Installation erstellen das dient dazu das die Namen im gesamten Programm verwendet werden können. - # Benutzername Vorname Nachname - generate_name - genFirstname="${gennamefirst}" - generate_name - genLastname="${gennamesecond}" - echo "$gennamefirst" - echo "$gennamesecond" - - generate_name - # database_setup - genDatabaseUserName="${gennamefirst}${gennamesecond}$((RANDOM % 900 + 100))" - echo "$genDatabaseUserName" - - # generate_name - # # Neue Region - # genRegionName="${gennamefirst}${gennamesecond}$((RANDOM % 900 + 100))" - # echo "$genRegionName" - - generate_name - genGridName="${gennamesecond}Grid" - echo "$genGridName" - - # Test Ausgabe der Variablen - #echo "genFirstname='${genFirstname}'" - #echo "genLastname='${genLastname}'" - #echo "genDatabaseUserName='${genDatabaseUserName}'" - #echo "genRegionName='${genRegionName}'" - #echo "genGridName='${genGridName}'" - #echo "${names[$RANDOM % ${#names[@]}]}" -} - -function opensimbuild() { - log "${COLOR_HEADING}🏗️ OpenSimulator Build-Prozess${COLOR_RESET}" - - log "${COLOR_LABEL}Möchten Sie den OpenSimulator jetzt erstellen? (${COLOR_OK}[ja]${COLOR_LABEL}/nein)${COLOR_RESET}" - read -r user_choice - - user_choice=${user_choice:-ja} - - if [[ "$user_choice" == "ja" ]]; then - if [[ -d "opensim" ]]; then - cd opensim || { log "${SYM_BAD} ${COLOR_ERROR}Fehler: Verzeichnis 'opensim' nicht gefunden.${COLOR_RESET}"; return 1; } - log "${COLOR_ACTION}Starte Prebuild-Skript...${COLOR_RESET}" - bash runprebuild.sh - log "${COLOR_ACTION}Baue OpenSimulator...${COLOR_RESET}" - dotnet build --configuration Release OpenSim.sln - log "${SYM_OK} ${COLOR_ACTION}OpenSimulator wurde erfolgreich erstellt.${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_ERROR}OpenSim Build Fehler: Das Verzeichnis 'opensim' existiert nicht.${COLOR_RESET}" - return 1 - fi - else - log "${SYM_BAD} ${COLOR_ERROR}Abbruch: OpenSimulator wird nicht erstellt.${COLOR_RESET}" - fi - # Wer in ein Verzeichnis wechselt sollte auch wieder zur vorherigen Verzeichnis wechseln! - cd .. - blankline -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Erstellen eines OpenSimulators Grids -#?────────────────────────────────────────────────────────────────────────────────────────── - -function removeconfigfiles() { - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - # Erstelle Backup wenn Datei existiert - if [[ -f "$ini_file" ]]; then - #echo "$(date +'%d.%m.%Y')_$(date +'%H:%M:%S')" - backup_file="${ini_file}.$(date +'%d.%m.%Y')_$(date +'%H:%M:%S').bak" - sudo mv -f "$ini_file" "$backup_file" - fi -} - -function createdirectory() { - log "${COLOR_HEADING}📂 Verzeichniserstellung${COLOR_RESET}" - - log "${COLOR_LABEL}Möchten Sie einen Gridserver oder einen Regionsserver erstellen? (${COLOR_OK}[grid]${COLOR_LABEL}/region)${COLOR_RESET}" - read -r server_type - - # Standardmäßig Gridserver wählen, falls keine Eingabe erfolgt - server_type=${server_type:-grid} - - if [[ "$server_type" == "grid" ]]; then - log "${COLOR_ACTION}Erstelle robust Verzeichnis...${COLOR_RESET}" - mkdir -p robust/bin - log "${SYM_OK} ${COLOR_ACTION}Robust Verzeichnis wurde erstellt.${COLOR_RESET}" - - # Nach der Erstellung des Gridservers auch die Regionsserver erstellen lassen - log "${COLOR_LABEL}Wie viele Regionsserver benötigen Sie? ${COLOR_OK}[1]${COLOR_RESET}" - read -r num_regions - # Standardmäßig 1 Region wählen, falls keine Eingabe erfolgt - num_regions=${num_regions:-1} - log "${SYM_OK} ${COLOR_ACTION}Sie haben $num_regions Regionsserver gew‰hlt.${COLOR_RESET}" - - elif [[ "$server_type" == "region" ]]; then - log "${COLOR_LABEL}Wie viele Regionsserver benötigen Sie? ${COLOR_OK}[1]${COLOR_RESET}" - read -r num_regions - log "${SYM_OK} ${COLOR_ACTION}Sie haben $num_regions Regionsserver gew‰hlt.${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_ERROR}Ungültige Eingabe. Bitte geben Sie 'grid' oder 'region' ein.${COLOR_RESET}" - return 1 - fi - - # Überprüfen, ob die Anzahl der Regionsserver bis 999 geht - if [[ "$num_regions" =~ ^[0-9]+$ && "$num_regions" -le 999 ]]; then - for ((i=1; i<=num_regions; i++)); do - dir_name="sim$i" - if [[ ! -d "$dir_name" ]]; then - mkdir -p "$dir_name/bin" - log "${SYM_OK} ${COLOR_DIR}$dir_name${COLOR_RESET} ${COLOR_ACTION}wurde erstellt.${COLOR_RESET}" - sleep 1 - else - log "${SYM_OK} ${COLOR_DIR}$dir_name${COLOR_RESET} ${COLOR_WARNING}existiert bereits und wird übersprungen.${COLOR_RESET}" - fi - done - else - log "${SYM_BAD} ${COLOR_ERROR}Ungültige Anzahl an Regionsserver. Bitte geben Sie eine gültige Zahl zwischen 1 und 999 ein.${COLOR_RESET}" - fi - blankline -} - -function opensimcopy() { - log "${COLOR_HEADING}${SYM_PACKAGE} OpenSim Dateikopie${COLOR_RESET}" - - # Prüfen, ob das Verzeichnis "opensim" existiert - if [[ ! -d "opensim" ]]; then - log "${SYM_BAD} ${COLOR_ERROR}OpenSim Copy Fehler: Das Verzeichnis 'opensim' existiert nicht.${COLOR_RESET}" - return 1 - fi - - # Prüfen, ob das Unterverzeichnis "opensim/bin" existiert - if [[ ! -d "opensim/bin" ]]; then - log "${SYM_BAD} ${COLOR_ERROR}OpenSim Copy Fehler: Das Verzeichnis 'opensim/bin' existiert nicht.${COLOR_RESET}" - return 1 - fi - - # Prüfen, ob das Verzeichnis "robust" existiert und Dateien kopieren - if [[ -d "robust/bin" ]]; then - cp -r opensim/bin/* robust/bin - log "${SYM_OK} ${COLOR_ACTION}Dateien aus ${COLOR_DIR}opensim/bin${COLOR_RESET} ${COLOR_ACTION}wurden nach ${COLOR_DIR}robust/bin${COLOR_RESET} ${COLOR_ACTION}kopiert.${COLOR_RESET}" - else - log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Hinweis: 'robust' Verzeichnis nicht gefunden, keine Kopie durchgeführt.${COLOR_RESET}" - fi - - # Alle simX-Verzeichnisse suchen und Dateien kopieren - for sim_dir in sim*; do - if [[ -d "$sim_dir/bin" ]]; then - cp -r opensim/bin/* "$sim_dir/bin/" - log "${SYM_OK} ${COLOR_ACTION}Dateien aus ${COLOR_DIR}opensim/bin${COLOR_RESET} ${COLOR_ACTION}wurden nach ${COLOR_DIR}$sim_dir/bin${COLOR_RESET} ${COLOR_ACTION}kopiert.${COLOR_RESET}" - fi - done - - blankline -} - -function database_setup() { - # 06.05.2025 - log "${COLOR_SECTION}=== MariaDB/MySQL Datenbank-Setup ===${COLOR_RESET}" - - # 1. Distribution Detection - detect_distro() { - if [[ -f /etc/os-release ]]; then - awk -F= '/^ID=/ {print $2}' /etc/os-release | tr -d '"' - elif [[ -f /etc/debian_version ]]; then - echo "debian" - elif [[ -f /etc/centos-release ]]; then - echo "centos" - else - echo "unknown" - fi - } - - current_distro=$(detect_distro) - #supported_distros=("debian" "ubuntu" "linuxmint" "pop" "mx" "kali" "zorin" "elementary" "raspbian" "centos" "fedora") - supported_distros=("debian" "ubuntu" "linuxmint" "pop" "mx" "kali" "zorin" "elementary" "raspbian" "centos" "fedora" "arch" "manjaro") - - # 2. Support-Check - if ! printf '%s\n' "${supported_distros[@]}" | grep -q "^${current_distro}$"; then - log "${SYM_BAD} ${COLOR_BAD}Nicht unterstützte Distribution: '${current_distro}'${COLOR_RESET}" - log "${SYM_INFO} Unterstützt: ${supported_distros[*]}" - return 1 - fi - - # 3. Installation Check (angepasste Version) - if ! command -v mariadb &> /dev/null && ! command -v mysql &> /dev/null; then - log "${SYM_WAIT} ${COLOR_WARNING}MariaDB/MySQL ist nicht installiert${COLOR_RESET}" - echo -ne "${COLOR_ACTION}MariaDB installieren? (j/n) [j] ${COLOR_RESET}" - read -r install_choice - install_choice=${install_choice:-j} - - if [[ "$install_choice" =~ ^[jJ] ]]; then - case $current_distro in - debian|ubuntu|*mint|pop|zorin|elementary|kali|mx|raspbian) - log "${SYM_INFO} ${COLOR_ACTION}Installiere MariaDB (apt)...${COLOR_RESET}" - sudo apt-get update && sudo apt-get install -y mariadb-server - ;; - centos|fedora) - log "${SYM_INFO} ${COLOR_ACTION}Installiere MariaDB (yum)...${COLOR_RESET}" - sudo yum install -y mariadb-server - sudo systemctl start mariadb - sudo systemctl enable mariadb - ;; - arch|manjaro) - log "${SYM_INFO} ${COLOR_ACTION}Installiere MariaDB (pacman)...${COLOR_RESET}" - sudo pacman -Sy --noconfirm mariadb - sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql - sudo systemctl enable --now mariadb - ;; - *) - log "${SYM_BAD} ${COLOR_BAD}Automatische Installation nicht verfügbar${COLOR_RESET}" - return 1 - ;; - esac - - # Sicherheitskonfiguration für alle Distros - log "${SYM_INFO} ${COLOR_ACTION}Führe mysql_secure_installation aus...${COLOR_RESET}" - sudo mysql_secure_installation - else - log "${SYM_BAD} Installation abgebrochen" - return 0 - fi - else - log "${SYM_OK} ${COLOR_OK}MariaDB/MySQL ist bereits installiert${COLOR_RESET}" - fi - - # 4. Benutzeranmeldedaten - log "\n${COLOR_SECTION}=== Datenbank-Zugangsdaten ===${COLOR_RESET}" - echo -ne "${COLOR_ACTION}Zufallszugangsdaten verwenden? (j/n) [j] ${COLOR_RESET}" - read -r default_cred_choice - default_cred_choice=${default_cred_choice:-j} - - if [[ "$default_cred_choice" =~ ^[jJ] ]]; then - db_user="${genDatabaseUserName}" - db_pass=$(tr -dc 'A-Za-z0-9!@#$%^&*()' < /dev/urandom | head -c 16) - log "${SYM_INFO} ${COLOR_LABEL}Generiertes Passwort: ${COLOR_VALUE}${db_pass}${COLOR_RESET}" - else - echo -ne "${COLOR_ACTION}DB_Benutzername: ${COLOR_RESET}" - read -r db_user - echo -ne "${COLOR_ACTION}DB_Passwort: ${COLOR_RESET}" - read -rs db_pass - echo - fi - - # **Speicherung der Datenbank-Zugangsdaten in UserInfo.ini** - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_INFO}Erstelle UserInfo.ini${COLOR_RESET}" - sudo touch "$ini_file" - fi - - log "\n[DatabaseData]" | sudo tee -a "$ini_file" >/dev/null - echo "DB_Benutzername = ${db_user}" | sudo tee -a "$ini_file" >/dev/null - echo "DB_Passwort = ${db_pass}" | sudo tee -a "$ini_file" >/dev/null - - - log "${SYM_LOG} ${COLOR_LABEL}Datenbank-Zugangsdaten gespeichert in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" - - # 6. Datenbankeinrichtung - log "\n${COLOR_SECTION}=== Datenbank-Konfiguration ===${COLOR_RESET}" - - # RobustServer DB - if [[ -d "robust" ]]; then - if ! sudo mysql -e "USE robust" &> /dev/null; then - sudo mysql -e "CREATE DATABASE robust CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" - log "${SYM_OK} ${COLOR_VALUE}robust${COLOR_RESET} Datenbank angelegt" - else - log "${SYM_INFO} ${COLOR_WARNING}robust-Datenbank existiert bereits${COLOR_RESET}" - fi - fi - - # simX Server DBs - for ((i=1; i<=1000; i++)); do - if [[ -d "sim${i}" ]]; then - db_name="sim${i}" - if ! sudo mysql -e "USE ${db_name}" &> /dev/null; then - sudo mysql -e "CREATE DATABASE ${db_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" - log "${SYM_OK} ${COLOR_VALUE}${db_name}${COLOR_RESET} Datenbank angelegt" - else - log "${SYM_INFO} ${COLOR_WARNING}${db_name}-Datenbank existiert bereits${COLOR_RESET}" - fi - fi - done - - # Benutzerverwaltung - if ! sudo mysql -e "SELECT user FROM mysql.user WHERE user='${db_user}' AND host='localhost'" | grep -q "${db_user}"; then - sudo mysql -e "CREATE USER '${db_user}'@'localhost' IDENTIFIED BY '${db_pass}'" - log "${SYM_OK} ${COLOR_VALUE}${db_user}${COLOR_RESET} Benutzer angelegt" - else - log "${SYM_INFO} ${COLOR_WARNING}Benutzer ${db_user} existiert bereits${COLOR_RESET}" - fi - - # Rechte vergeben - [[ -d "robust" ]] && sudo mysql -e "GRANT ALL PRIVILEGES ON robust.* TO '${db_user}'@'localhost'" - for ((i=1; i<=1000; i++)); do - [[ -d "sim${i}" ]] && sudo mysql -e "GRANT ALL PRIVILEGES ON sim${i}.* TO '${db_user}'@'localhost'" - done - sudo mysql -e "FLUSH PRIVILEGES" - - log "${COLOR_OK} Datenbank Setup abgeschlossen!${COLOR_RESET}" -} - - -function createmasteruser() { - # 02.05.2025 Master Avatar MasterAvatar - - # RobustServer starten - echo "RobustServer starten, erster start..." - if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" - cd robust/bin || exit 1 - # -inifile=Robust.HG.ini - - screen -fa -S robustserver -d -U -m dotnet Robust.dll - cd - >/dev/null 2>&1 || exit 1 - sleep $RobustServer_Start_wait - else - log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" - fi - - genPasswort=$(tr -dc 'A-Za-z0-9!@#$%^&*()' < /dev/urandom | head -c 16) - genUserid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") - - VORNAME="${genFirstname}" - NACHNAME="${genLastname}" - local PASSWORT="${genPasswort}" - local EMAIL="${4:-${genFirstname}@${genLastname}.com}" - userid="${5:-$genUserid}" - - log "${COLOR_INFO}Master User Erstellung (Enter für generierte Werte)${COLOR_RESET}" - - echo -n "Vorname [${VORNAME}]: " - read -r input - VORNAME="${input:-$VORNAME}" - - echo -n "Nachname [${NACHNAME}]: " - read -r input - NACHNAME="${input:-$NACHNAME}" - - echo -n "Passwort [${PASSWORT}]: " - read -r input - PASSWORT="${input:-$PASSWORT}" - - echo -n "E-Mail [${EMAIL}]: " - read -r input - EMAIL="${input:-$EMAIL}" - - echo -n "UserID [${userid}]: " - read -r input - userid="${input:-$userid}" - - # Überprüfe ob Robust läuft - if ! screen -list | grep -q "robustserver"; then - log "${COLOR_BAD}CREATEUSER: Robust existiert nicht oder läuft nicht${COLOR_RESET}" - return 1 - fi - - # Benutzer in Robust erstellen - screen -S robustserver -p 0 -X eval "stuff 'create user'^M" - screen -S robustserver -p 0 -X eval "stuff '$VORNAME'^M" - screen -S robustserver -p 0 -X eval "stuff '$NACHNAME'^M" - screen -S robustserver -p 0 -X eval "stuff '$PASSWORT'^M" - screen -S robustserver -p 0 -X eval "stuff '$EMAIL'^M" - screen -S robustserver -p 0 -X eval "stuff '$userid'^M" - screen -S robustserver -p 0 -X eval "stuff 'Ruth'^M" - - log "${COLOR_OK}Masteruser $VORNAME $NACHNAME wurde erstellt${COLOR_RESET}" - log "${COLOR_INFO}UserID: $userid${COLOR_RESET}" - - # **Speicherung der Benutzerdaten in UserInfo.ini** NEU - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_INFO}Erstelle UserInfo.ini${COLOR_RESET}" - sudo touch "$ini_file" - fi - - log "\n[UserData]" | sudo tee -a "$ini_file" >/dev/null - echo "Vorname = ${VORNAME}" | sudo tee -a "$ini_file" >/dev/null - echo "Nachname = ${NACHNAME}" | sudo tee -a "$ini_file" >/dev/null - echo "Passwort = ${PASSWORT}" | sudo tee -a "$ini_file" >/dev/null - echo "E-Mail = ${EMAIL}" | sudo tee -a "$ini_file" >/dev/null - echo "UserID = ${userid}" | sudo tee -a "$ini_file" >/dev/null - - - log "${SYM_LOG} ${COLOR_LABEL}Benutzerdaten hinzugefügt in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" - - blankline -} - -function createmasterestate() { - # 02.05.2025 Master Estate - log "${COLOR_HEADING}🏡 Master Estate Erstellung${COLOR_RESET}" - - # sim1 starten - echo "Sim1 Welcome starten, erster start..." - if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1 ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}sim1/bin...${COLOR_RESET}" - cd sim1/bin || exit 1 - screen -fa -S sim1 -d -U -m dotnet OpenSim.dll - cd - >/dev/null 2>&1 || exit 1 - sleep 10 - else - log "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" - fi - - # 1. Überprüfe ob sim1 läuft - if ! screen -list | grep -q "sim1"; then - log "${SYM_BAD} ${COLOR_ERROR}CREATEESTATE: sim1 existiert nicht oder läuft nicht${COLOR_RESET}" - log "${COLOR_INFO}Tipp: Starten Sie die Simulator-Instanz zuerst${COLOR_RESET}" - return 1 - fi - - # 1. INI-Datei auslesen mit angepasstem Parsing - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" - return 1 - fi - - # Parsing-Funktion mit Trim und Leerzeichen im Pattern - ini_get() { - local section="$1" key="$2" - awk -F ' = ' ' - /^\[/ { current_section = substr($0, 2, length($0)-2) } - current_section == "'"$section"'" && $1 == "'"$key"'" { - sub(/^[ \t]+/, "", $2) # Trim leading whitespace - sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace - print $2 - exit - } - ' "$ini_file" - } - - # Werte auslesen - gridname=$(ini_get "ServerData" "GridName") - VORNAME=$(ini_get "UserData" "Vorname") - NACHNAME=$(ini_get "UserData" "Nachname") - - # Debug-Ausgabe - log "${COLOR_DEBUG}Gelesene Werte:" - log "GridName: '${gridname:-NICHT GEFUNDEN}'" - log "Vorname: '${VORNAME:-NICHT GEFUNDEN}'" - log "Nachname: '${NACHNAME:-NICHT GEFUNDEN}'${COLOR_RESET}" - - if [[ -z "$gridname" || -z "$VORNAME" || -z "$NACHNAME" ]]; then - log "${COLOR_BAD}Fehlende Daten in UserInfo.ini${COLOR_RESET}" - log "Bitte überprüfen Sie folgende Einträge:" - log "[ServerData]" - log "GridName = ..." - log "[UserData]" - log "Vorname = ..." - log "Nachname = ..." - return 1 - fi - - # 3. Logging vor der Ausführung - log "${COLOR_INFO}Erstelle Master Estate für:" - log "- Grid: ${COLOR_VALUE}$gridname" - log "- Avatar: ${COLOR_VALUE}$VORNAME $NACHNAME${COLOR_RESET}" - - # 4. Befehle an sim1 senden mit Fehlerprüfung - if ! screen -S sim1 -p 0 -X eval "stuff '$gridname Estate'^M"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden des Estate-Befehls${COLOR_RESET}" - return 1 - fi - sleep 1 # Kurze Pause zwischen den Befehlen - - if ! screen -S sim1 -p 0 -X eval "stuff '$VORNAME'^M"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden des Vornamens${COLOR_RESET}" - return 1 - fi - sleep 1 - - if ! screen -S sim1 -p 0 -X eval "stuff '$NACHNAME'^M"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden des Nachnamens${COLOR_RESET}" - return 1 - fi - - # 5. Erfolgsmeldung - log "${SYM_OK} ${COLOR_OK}Master Estate erfolgreich erstellt${COLOR_RESET}" - log "${COLOR_INFO}Starte nun die Estate-Akzeptierung für alle Regionen...${COLOR_RESET}" - blankline - - # 6. Alle anderen Starten und Estate akzeptieren - if ! createmasterestateall; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler bei createmasterestateall${COLOR_RESET}" - return 1 - fi - - return 0 -} - -function createmasterestateall() { - # 02.05.2025 Master Estate Bestätigung mit Simulator-Start - log "${COLOR_HEADING}🌍 Starte Simulatoren & bestätige Master Estate${COLOR_RESET}" - - # 1. INI-Datei auslesen mit angepasstem Parsing - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" - return 1 - fi - - # Parsing-Funktion mit Trim und Leerzeichen im Pattern - ini_get() { - local section="$1" key="$2" - awk -F ' = ' ' - /^\[/ { current_section = substr($0, 2, length($0)-2) } - current_section == "'"$section"'" && $1 == "'"$key"'" { - sub(/^[ \t]+/, "", $2) # Trim leading whitespace - sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace - print $2 - exit - } - ' "$ini_file" - } - - # Werte auslesen - gridname=$(ini_get "ServerData" "GridName") - VORNAME=$(ini_get "UserData" "Vorname") - NACHNAME=$(ini_get "UserData" "Nachname") - - # Debug-Ausgabe - log "${COLOR_DEBUG}Gelesene Werte:" - log "GridName: '${gridname:-NICHT GEFUNDEN}'" - log "Vorname: '${VORNAME:-NICHT GEFUNDEN}'" - log "Nachname: '${NACHNAME:-NICHT GEFUNDEN}'${COLOR_RESET}" - - if [[ -z "$gridname" || -z "$VORNAME" || -z "$NACHNAME" ]]; then - log "${COLOR_BAD}Fehlende Daten in UserInfo.ini${COLOR_RESET}" - log "Bitte überprüfen Sie folgende Einträge:" - log "[ServerData]" - log "GridName = ..." - log "[UserData]" - log "Vorname = ..." - log "Nachname = ..." - return 1 - fi - - # 2. Starte alle Simulatoren - log "${COLOR_ACTION}Starte Simulator-Instanzen...${COLOR_RESET}" - local started_sims=0 - - for ((i=2; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then - echo -n -e "${SYM_INFO} ${COLOR_DIR}sim$i: ${COLOR_RESET}" - - if cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll; then - log "${COLOR_OK}gestartet${COLOR_RESET}" - ((started_sims++)) - sleep "${Simulator_Start_wait:-5}" - else - log "${COLOR_ERROR}start fehlgeschlagen${COLOR_RESET}" - fi - cd - >/dev/null 2>&1 - fi - done - - # 3. Estate-Bestätigung für alle Regionen - if [[ $started_sims -gt 0 ]]; then - log "${COLOR_ACTION}Bestätige Estate für $started_sims Simulator(en)...${COLOR_RESET}" - - for ((i=2; i<=999; i++)); do - if screen -list | grep -q "sim$i"; then - regions_dir="${SCRIPT_DIR}/sim$i/bin/Regions" - if [[ -d "$regions_dir" ]]; then - # Zähle die Anzahl der Regionen-Konfigurationen - region_count=$(find "$regions_dir" -maxdepth 1 -name "*.ini" | wc -l) - log "${SYM_INFO} ${COLOR_DIR}sim$i: ${region_count} Region(en) gefunden${COLOR_RESET}" - - # Für jede Region die Bestätigung senden - for ((r=1; r<=region_count; r++)); do - echo -n -e " ${SYM_INFO} Region ${r}: ${COLOR_RESET}" - - if ! screen -S "sim$i" -p 0 -X eval "stuff 'yes'^M"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden von yes${COLOR_RESET}" - return 1 - fi - sleep 1 - - if ! screen -S "sim$i" -p 0 -X eval "stuff '$gridname Estate'^M"; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden von $gridname Estate${COLOR_RESET}" - return 1 - fi - log "${COLOR_OK}bestätigt${COLOR_RESET}" - sleep 1 - done - else - log "${SYM_WARNING} ${COLOR_WARNING}sim$i: Kein Regions-Verzeichnis gefunden${COLOR_RESET}" - sleep 1 - fi - fi - done - else - log "${SYM_WARNING} ${COLOR_WARNING}Keine Simulatoren gestartet!${COLOR_RESET}" - return 1 - fi - - log "${SYM_OK} ${COLOR_OK}$started_sims Simulatoren gestartet & Estate für alle Regionen bestätigt${COLOR_RESET}" - sleep 1 - blankline - return 0 -} - -function firststart() { - # 02.05.2025 - # Sind wir im Skriptverzeichnis oder noch in opensim? - cd "$SCRIPT_DIR" || exit 1 - - # Master Avatar Registrieren. - createmasteruser - - # Estate erstellen - createmasterestate - - # Erststart stoppen - #opensimstop - #killall screen - - # Regulären Start nach installation und setup. - #opensimrestart - - blankline - -} - -# bash osmtool.sh setcrontab -function setcrontab() { - # Strict Mode: Fehler sofort erkennen - set -euo pipefail - - log "${COLOR_HEADING}⏰ Cron-Job-Einrichtung (Interaktiv)${COLOR_RESET}" - - # Sicherheitsabfrage: Nur als root/sudo ausführen - if [ "$(id -u)" -ne 0 ]; then - log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Dieses Skript benötigt root-Rechte! (sudo verwenden)${COLOR_RESET}" >&2 - return 1 - fi - - # Prüfen, ob SCRIPT_DIR gesetzt und gültig ist - if [ -z "${SCRIPT_DIR:-}" ]; then - log "${SYM_BAD} ${COLOR_ERROR}FEHLER: 'SCRIPT_DIR' muss gesetzt sein!${COLOR_RESET}" >&2 - return 1 - fi - - if [ ! -d "$SCRIPT_DIR" ]; then - log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Verzeichnis '${COLOR_DIR}$SCRIPT_DIR${COLOR_ERROR}' existiert nicht!${COLOR_RESET}" >&2 - return 1 - fi - - # Temporäre Datei für neue Cron-Jobs - local temp_cron - temp_cron=$(mktemp) || { - log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Temp-Datei konnte nicht erstellt werden.${COLOR_RESET}" >&2 - return 1 - } - - ### Interaktive Abfragen ### - log "\n${COLOR_VALUE}=== Wartung am 1. des Monats ===${COLOR_RESET}" - log "Welche Aktionen sollen ausgeführt werden? (Mehrfachauswahl möglich)" - log " ${SYM_INFO} 1) Nichts (deaktivieren)" - log " ${SYM_INFO} 2) cacheclean (inkl. automatischem stop vorher)" - log " ${SYM_INFO} 3) mapclean (inkl. automatischem stop vorher)" - log " ${SYM_INFO} 4) logclean (inkl. automatischem stop vorher)" - log " ${SYM_INFO} 5) Vollständiger Neustart (stop → cacheclean → mapclean → logclean → reboot)" - log " ${SYM_INFO} 6) Nur Server neustarten (reboot)" - read -r -p "$(msg CRON_PROMPT_MONTHLY_SELECTION) " -a monthly_actions - - # Abfrage ob nach clean-Operationen ein reboot erfolgen soll - local needs_reboot=false - if [[ " ${monthly_actions[*]} " =~ [234] ]]; then - read -r -p "$(msg CRON_PROMPT_REBOOT_AFTER_CLEAN) " add_reboot - is_yes "$add_reboot" && needs_reboot=true - fi - - log "\n${COLOR_VALUE}=== Tägliche Wartung ===${COLOR_RESET}" - read -r -p "$(msg CRON_PROMPT_DAILY_RESTART) " daily_restart - if is_yes "$daily_restart"; then - read -r -p "$(msg CRON_PROMPT_DAILY_HOUR) " daily_hour - daily_hour=${daily_hour:-5} # Default: 5 Uhr - fi - - log "\n${COLOR_VALUE}=== Überwachung ===${COLOR_RESET}" - read -r -p "$(msg CRON_PROMPT_ENABLE_MONITORING) " enable_monitoring - if is_yes "$enable_monitoring"; then - read -r -p "$(msg CRON_PROMPT_MONITOR_INTERVAL) " monitor_interval - monitor_interval=${monitor_interval:-30} - fi - - ### Cron-Job-Generierung ### - { - echo "# === OpenSimGrid-Automatisierung ===" - echo "# Bedeutung: Minute Stunde Tag Monat Jahr Befehlskette" - echo "" - - # Monatliche Wartung (1. des Monats) - if [[ " ${monthly_actions[*]} " =~ "1" ]]; then - echo "# Deaktiviert: Monatliche Wartung" - else - echo "# Monatliche Wartung am 1. des Monats" - - # Berechnung der Minuten relativ zum täglichen Restart - local restart_hour=${daily_hour:-5} - local restart_minute=0 - - # Stop 30 Minuten vor täglichem Restart - if [[ " ${monthly_actions[*]} " =~ [2345] ]]; then - stop_time=$(calculate_relative_time "$restart_hour" $restart_minute -30) - echo "$stop_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' stop" - fi - - # Cacheclean 25 Minuten vor täglichem Restart (Option 2 oder 5) - if [[ " ${monthly_actions[*]} " =~ [25] ]]; then - cacheclean_time=$(calculate_relative_time "$restart_hour" $restart_minute -25) - echo "$cacheclean_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' cacheclean" - fi - - # Mapclean 20 Minuten vor täglichem Restart (Option 3 oder 5) - if [[ " ${monthly_actions[*]} " =~ [35] ]]; then - mapclean_time=$(calculate_relative_time "$restart_hour" $restart_minute -20) - echo "$mapclean_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' mapclean" - fi - - # Logclean 15 Minuten vor täglichem Restart (Option 4 oder 5) - if [[ " ${monthly_actions[*]} " =~ [45] ]]; then - logclean_time=$(calculate_relative_time "$restart_hour" $restart_minute -15) - echo "$logclean_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' logclean" - fi - - # Reboot 10 Minuten vor täglichem Restart (Option 5 oder 6 oder manuelle Bestätigung) - if [[ " ${monthly_actions[*]} " =~ [56] ]] || $needs_reboot; then - reboot_time=$(calculate_relative_time "$restart_hour" $restart_minute -10) - echo "$reboot_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' reboot" - fi - fi - - # Tägliche Wartung - if [[ "$daily_restart" =~ [jJ] ]]; then - log "\n# Täglicher Restart" - echo "0 ${daily_hour} * * * bash '$SCRIPT_DIR/osmtool.sh' restart" - else - log "\n# Deaktiviert: Täglicher Restart" - fi - - # Überwachung - if [[ "$enable_monitoring" =~ [jJ] ]]; then - log "\n# Überwachung" - echo "*/${monitor_interval} * * * * bash '$SCRIPT_DIR/osmtool.sh' check_screens" - else - log "\n# Deaktiviert: Überwachung" - fi - } > "$temp_cron" - - # Cron-Jobs installieren - if crontab "$temp_cron"; then - rm -f "$temp_cron" - log "\n${SYM_OK} ${COLOR_OK}Cron-Jobs wurden aktualisiert:${COLOR_RESET}" - crontab -l | grep -v '^#' | sed '/^$/d' | while read -r line; do - log "${COLOR_DIR}$line${COLOR_RESET}" - done - return 0 - else - log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Installation fehlgeschlagen. Prüfe $temp_cron manuell.${COLOR_RESET}" >&2 - return 1 - fi -} - -# Hilfsfunktion zur Berechnung relativer Zeiten -calculate_relative_time() { - local hour=$1 - local minute=$2 - local offset=$3 # in Minuten (kann negativ sein) - - # Gesamtminuten berechnen - local total_minutes=$((hour * 60 + minute + offset)) - - # Handle negative Zeiten (vor Mitternacht) - while (( total_minutes < 0 )); do - total_minutes=$((total_minutes + 1440)) # 24 Stunden in Minuten - done - - # Zurück in Stunden und Minuten umrechnen - local new_hour=$((total_minutes / 60 % 24)) - local new_minute=$((total_minutes % 60)) - - echo "$new_minute $new_hour" -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Backup und Upgrade des OpenSimulators Grids -#?────────────────────────────────────────────────────────────────────────────────────────── - -function opensimupgrade() { - log "\n${COLOR_WARNING}${SYM_WARNING} Der OpenSimulator muss zuerst im Verzeichnis 'opensim' vorliegen!${COLOR_RESET}" - log "${COLOR_LABEL}Möchten Sie den OpenSimulator aktualisieren? (${COLOR_BAD}[no]${COLOR_LABEL}/yes)${COLOR_RESET}" - read -r user_choice - user_choice=${user_choice:-no} - - # Prüfe, ob das Verzeichnis vorhanden ist - if [[ ! -d "opensim" ]]; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler: Das Verzeichnis '${COLOR_DIR}opensim${COLOR_ERROR}' existiert nicht${COLOR_RESET}" - return 1 - fi - - # Prüfe, ob im Verzeichnis 'opensim/bin' die Dateien OpenSim.dll und Robust.dll vorhanden sind - if [[ ! -f "opensim/bin/OpenSim.dll" || ! -f "opensim/bin/Robust.dll" ]]; then - log "${SYM_BAD} ${COLOR_ERROR}Fehler: Benötigte Dateien (OpenSim.dll und/oder Robust.dll) fehlen im Verzeichnis '${COLOR_DIR}opensim/bin${COLOR_ERROR}'${COLOR_RESET}" - log "\n${COLOR_WARNING}❓ Haben Sie vergessen den OpenSimulator zuerst zu Kompilieren?${COLOR_RESET}" - return 1 - fi - - if [[ "$user_choice" == "yes" ]]; then - log "${COLOR_ACTION}OpenSimulator wird gestoppt...${COLOR_RESET}" - opensimstop - sleep $Simulator_Stop_wait - - log "${COLOR_ACTION}OpenSimulator wird kopiert...${COLOR_RESET}" - opensimcopy - - log "${COLOR_ACTION}OpenSimulator wird gestartet...${COLOR_RESET}" - opensimstart - - log "${COLOR_OK}✔ ${COLOR_ACTION}Upgrade abgeschlossen.${COLOR_RESET}" - else - log "${COLOR_WARNING}Upgrade vom Benutzer abgebrochen.${COLOR_RESET}" - fi - blankline -} - -function regionbackup() { - DATUM=$(date +%Y-%m-%d_%H-%M) - BACKUPDIR="$SCRIPT_DIR/backup" - mkdir -p "$BACKUPDIR" - - log "${SYM_TOOLS} ${COLOR_HEADING}Starte automatisches Backup aller Regionen...${COLOR_RESET}" - - for ((i=1; i<=999; i++)); do - SIMNAME="sim$i" - SIMBIN="$SCRIPT_DIR/$SIMNAME/bin" - REGIONSDIR="$SIMBIN/Regions" - TARGETDIR="$BACKUPDIR/sim$i" - - if [[ -d "$REGIONSDIR" ]]; then - mkdir -p "$TARGETDIR" - log "${SYM_SERVER} ${COLOR_START}Backup für ${COLOR_SERVER}$SIMNAME${COLOR_RESET} wird vorbereitet (${COLOR_DIR}$SIMBIN${COLOR_RESET})..." - - # ➕ OpenSim.ini sichern - if [[ -f "$SIMBIN/OpenSim.ini" ]]; then - cp "$SIMBIN/OpenSim.ini" "$TARGETDIR/${DATUM}-OpenSim.ini" - log "${SYM_CONFIG} ${COLOR_LABEL}OpenSim.ini gesichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-OpenSim.ini${COLOR_RESET}" - fi - - # ➕ GridCommon.ini sichern - if [[ -f "$SIMBIN/config-include/GridCommon.ini" ]]; then - cp "$SIMBIN/config-include/GridCommon.ini" "$TARGETDIR/${DATUM}-GridCommon.ini" - log "${SYM_CONFIG} ${COLOR_LABEL}GridCommon.ini gesichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-GridCommon.ini${COLOR_RESET}" - fi - - for ini_file in "$REGIONSDIR"/*.ini; do - [[ -f "$ini_file" ]] || continue - - region_names=$(grep -oP '^\[\K[^\]]+' "$ini_file") - - for REGIONNAME in $region_names; do - blankline - log "${SYM_FOLDER} ${COLOR_LABEL}Sichere Region:${COLOR_RESET} ${COLOR_VALUE}$REGIONNAME${COLOR_RESET}" - - screen -S "$SIMNAME" -p 0 -X eval "stuff 'change region ${REGIONNAME//\"/}'^M" - sleep 1 - - screen -S "$SIMNAME" -p 0 -X eval "stuff 'save oar ${TARGETDIR}/${DATUM}-${REGIONNAME}.oar'^M" - log "${SYM_FILE} ${COLOR_LABEL}OAR gespeichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-${REGIONNAME}.oar${COLOR_RESET}" - - screen -S "$SIMNAME" -p 0 -X eval "stuff 'save xml2 ${TARGETDIR}/${DATUM}-${REGIONNAME}.xml2'^M" - log "${SYM_FILE} ${COLOR_LABEL}XML2 gespeichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-${REGIONNAME}.xml2${COLOR_RESET}" - - screen -S "$SIMNAME" -p 0 -X eval "stuff 'terrain save ${TARGETDIR}/${DATUM}-${REGIONNAME}.png'^M" - screen -S "$SIMNAME" -p 0 -X eval "stuff 'terrain save ${TARGETDIR}/${DATUM}-${REGIONNAME}.raw'^M" - log "${SYM_FILE} ${COLOR_LABEL}Terrain (PNG & RAW) gespeichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-${REGIONNAME}.{png,raw}${COLOR_RESET}" - - cp "$ini_file" "$TARGETDIR/${DATUM}-$(basename "$ini_file")" - log "${SYM_CONFIG} ${COLOR_LABEL}Konfig gesichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-$(basename "$ini_file")${COLOR_RESET}" - - sleep 1 - done - done - fi - done - - log "${SYM_OK} ${COLOR_ACTION}Automatisches Regionen-Backup abgeschlossen.${COLOR_RESET}" - blankline -} - -# todo: Testen, ob alles funktioniert. -# Erstellt ein strukturiertes Backup der Robust-Datenbank sowie wichtiger Konfigurationsdateien. -# Aufruf: -function robustbackup() { - # Variablen der Funktion. - local DB_NAME="robust" - local BACKUP_YEARS=30 - SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - local ini_file="$SCRIPT_DIR/UserInfo.ini" - local BACKUP_DIR="$SCRIPT_DIR/backup/robust" - local ROBUST_INI_DIR="$SCRIPT_DIR/robust/bin" - TIMESTAMP=$(date +%F_%H-%M) - TIMESTAMP_GRENZE=$(date -d "-$BACKUP_YEARS years" +%s) - ARCHIVIEREN="nein" - - # Root-Privilegien erforderlich - if [[ "$EUID" -ne 0 ]]; then - echo "Dieses Skript muss als Root ausgeführt werden (z.B. mit sudo)." >&2 - echo "Ohne Root-Privilegien müssen Sie das Passwort der Datenbank bei jedem Mal eingeben." >&2 - echo -n "Möchten Sie trotzdem ohne Root-Privilegien fortfahren? (ja/N): " >&2 - read -r answer - if [[ "$answer" != "ja" ]]; then - echo "Abbruch." >&2 - exit 1 - fi - fi - - # Zugangsdaten auslesen, falls vorhanden - local DB_USER DB_PASS - if [[ -f "$ini_file" ]]; then - DB_USER=$(grep -oP '^DB_Benutzername\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') - DB_PASS=$(grep -oP '^DB_Passwort\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') - fi - - # Falls nicht vorhanden: Benutzer fragen - if [[ -z "$DB_USER" ]]; then - echo "Bitte DB-Benutzername eingeben:" - read -r DB_USER - fi - - if [[ -z "$DB_PASS" ]]; then - echo "Bitte DB-Passwort eingeben:" - read -r DB_PASS - fi - - declare -A ASSET_NAMES=( - [-1]="NoneUnknown" [-2]="LLmaterialIAR" [0]="Texture" [1]="Sound" [2]="CallingCard" [3]="Landmark" - [4]="Unknown4" [5]="Clothing" [6]="Object" [7]="Notecard" [8]="Folder" [9]="Unknown9" - [10]="LSLText" [11]="LSLBytecode" [12]="TextureTGA" [13]="Bodypart" [14]="Unknown14" - [15]="Unknown15" [16]="Unknown16" [17]="SoundWAV" [18]="ImageTGA" [19]="ImageJPEG" - [20]="Animation" [21]="Gesture" [22]="Simstate" [23]="Unknown23" [24]="Link" - [25]="LinkFolder" [26]="MarketplaceFolder" [49]="Mesh" [56]="Settings" [57]="Material" - ) - - mkdir -p "$BACKUP_DIR/tables" "$BACKUP_DIR/assettypen" "$BACKUP_DIR/configs" - - log "${COLOR_HEADING}${SYM_PACKAGE} Starte Robust-Datenbank-Backup mit Zeitraumfilter ($BACKUP_YEARS Jahre)${COLOR_RESET}" - - #* Reparatur - mysqlcheck -u"$DB_USER" -p"$DB_PASS" --auto-repair "$DB_NAME" - - #* Tabellen sichern (außer assets) mit Zählung - local tabellen - local total_nonasset_rows=0 - tabellen=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SHOW TABLES IN $DB_NAME;" | grep -v '^assets$') - for table in $tabellen; do - row_count=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SELECT COUNT(*) FROM $table;" "$DB_NAME") - ((total_nonasset_rows += row_count)) - log "${SYM_LOG} Tabelleneinträge: $table (${row_count} Einträge)${COLOR_RESET}" - mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" "$table" | gzip > "$BACKUP_DIR/tables/${table}.sql.gz" - done - - log "${SYM_OK}${COLOR_INFO} Tabellen (außer assets): Insgesamt $total_nonasset_rows Einträge gesichert${COLOR_RESET}" - - #* Assettypen sichern mit Zählung - log "${SYM_PUZZLE} Starte assetType-Datensicherung mit Zeitraumfilter ab $(date -d "@$TIMESTAMP_GRENZE")" - - total_found=0 - total_saved=0 - - for assettype in "${!ASSET_NAMES[@]}"; do - local name="${ASSET_NAMES[$assettype]}" - log "${SYM_FOLDER} Exportiere assetType=$assettype ($name)${COLOR_RESET}" - - # Anzahl Datensätze in diesem Typ und Zeitraum - count=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e \ - "SELECT COUNT(*) FROM assets WHERE assetType = $assettype AND create_time >= $TIMESTAMP_GRENZE;" "$DB_NAME") - - if [[ "$count" -gt 0 ]]; then - ((total_found += count)) - ((total_saved += count)) - mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" assets \ - --where="assetType = $assettype AND create_time >= $TIMESTAMP_GRENZE" \ - | gzip > "$BACKUP_DIR/assettypen/assets_${name}.sql.gz" - log "${SYM_OK} Gespeichert: $count Einträge für $name" - else - log "${SYM_FORWARD} Keine Daten für assetType=$assettype ($name)" - fi - done - - log "${SYM_OK}${COLOR_INFO} Asset-Sicherung abgeschlossen: $total_found gefunden, $total_saved gespeichert, Differenz: $((total_found - total_saved))${COLOR_RESET}" - - #* Konfig-Dateien sichern - log "${SYM_LOG} Sicherung der Konfigurationsdateien im robust/bin Verzeichnis${COLOR_RESET}" - find "$ROBUST_INI_DIR" -maxdepth 1 -type f \( \ - -name "MoneyServer.ini" -o -name "MoneyServer.ini.*" \ - -o -name "Robust.ini" -o -name "Robust.HG.*" -o -name "Robust.local.*" \) \ - -exec cp {} "$BACKUP_DIR/configs/" \; - - #* Archiv erstellen (Was passiert hier wird das unützerweise alles in einer Datei gepackt?) - if [ "$ARCHIVIEREN" = "ja" ]; then - log "${COLOR_HEADING}${SYM_PACKAGE} Erstelle tgz-Archiv: robustbackup_${TIMESTAMP}.tgz${COLOR_RESET}" - tar czf "$BACKUP_DIR/robustbackup_${TIMESTAMP}.tgz" -C "$BACKUP_DIR" . - log "${SYM_OKNN} Backup abgeschlossen: $BACKUP_DIR/robustbackup_${TIMESTAMP}.tgz${COLOR_RESET}" - fi -} - -# todo: Testen, ob alles funktioniert. -# Wiederherstellt eine Robust-Datenbank aus einer Dump-Datei. -# Aufruf: -#* restoreRobustDump -function restoreRobustDump() { - local DB_USER=$1 - local DB_PASS=$2 - local DUMP_FILE=$3 - local TARGET_DB=$4 - - SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - local TMPDIR - TMPDIR=$(mktemp -d) - local total_tables=0 - - log "${COLOR_HEADING}${SYM_PACKAGE} Starte Wiederherstellung von Dump-Datei ${COLOR_FILE}${DUMP_FILE}${COLOR_RESET} in Datenbank ${COLOR_VALUE}${TARGET_DB}${COLOR_RESET}" - - if [[ ! -f "$DUMP_FILE" ]]; then - log "${SYM_BAD} ${COLOR_BAD}Fehler:${COLOR_RESET} Dump-Datei nicht gefunden: ${COLOR_FILE}$DUMP_FILE${COLOR_RESET}" - return 1 - fi - - #* Datenbank vorbereiten - log "${SYM_TOOLS} Entferne vorhandene Datenbank (falls vorhanden) und erstelle neu: ${COLOR_VALUE}$TARGET_DB${COLOR_RESET}" - mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP DATABASE IF EXISTS \`$TARGET_DB\`; CREATE DATABASE \`$TARGET_DB\`;" - - #* Dump-Datei aufteilen - log "${SYM_SCRIPT} Zerlege Dump-Datei in einzelne Tabellen im Temp-Verzeichnis: ${COLOR_FILE}$TMPDIR${COLOR_RESET}" - csplit -z -f "$TMPDIR/table_" -b "%03d.sql" "$DUMP_FILE" '/DROP TABLE IF EXISTS/' '{*}' > /dev/null - - #* Import der Tabellen - for sqlfile in "$TMPDIR"/table_*.sql; do - local tablename - tablename=$(grep -i "CREATE TABLE" "$sqlfile" | awk -F'\`' '{print $2}') - if [[ -n "$tablename" ]]; then - log "${SYM_FILE} Importiere Tabelle: ${COLOR_FILE}$tablename${COLOR_RESET}" - mysql -u"$DB_USER" -p"$DB_PASS" "$TARGET_DB" < "$sqlfile" - ((total_tables++)) - fi - done - - log "${SYM_OK}${COLOR_INFO} Import abgeschlossen: $total_tables Tabellen importiert${COLOR_RESET}" - - #* Asset-Typen prüfen und reparieren - log "${SYM_PUZZLE} Prüfe asset.assetType auf ungültige Werte..." - invalid_count=$(mysql -u"$DB_USER" -p"$DB_PASS" -sse "SELECT COUNT(*) FROM asset WHERE assetType NOT BETWEEN 0 AND 49;" "$TARGET_DB") - - if ((invalid_count > 0)); then - log "${SYM_WARNING} Ungültige assetType-Werte gefunden: $invalid_count — korrigiere auf 0" - mysql -u"$DB_USER" -p"$DB_PASS" -e "UPDATE asset SET assetType = 0 WHERE assetType NOT BETWEEN 0 AND 49;" "$TARGET_DB" - else - log "${SYM_OK} Alle assetType-Werte sind gültig" - fi - - #* Datenbank reparieren - log "${SYM_TOOLS} Führe mysqlcheck mit Reparatur durch..." - mysqlcheck -u"$DB_USER" -p"$DB_PASS" --auto-repair "$TARGET_DB" - - log "${SYM_OK} ${COLOR_OK}Wiederherstellung erfolgreich abgeschlossen für:${COLOR_RESET} ${COLOR_VALUE}$TARGET_DB${COLOR_RESET}" -} - - -# todo: Testen, ob alles funktioniert. -# robustrestore -# dbuser: SQL-Benutzername -# dbpass: Passwort des SQL-Benutzers -# all: Wiederherstellung aller Nicht-Asset-Tabellen und Konfig-Dateien -# tables: Wiederherstellung aller Nicht-Asset-Tabellen -# assets: Wiederherstellung der assetType-Tabellen und Konfig-Dateien -# assettype: Wiederherstellung der angegebenen assetType-Tabellen -function robustrestore() { - local DB_USER=$1 - local DB_PASS=$2 - local DB_NAME="robust" - local RESTORE_SCOPE=$3 # "all", "tables", "assets" oder Asset-Typ-Name - SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" - local BACKUP_DIR="$SCRIPT_DIR/backup/robust" - - log "${COLOR_HEADING}${SYM_PACKAGE} Starte Wiederherstellung für: ${COLOR_VALUE}${RESTORE_SCOPE}${COLOR_RESET}" - - case "$RESTORE_SCOPE" in - all) - log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung aller Nicht-Asset-Tabellen...${COLOR_RESET}" - for file in "$BACKUP_DIR/tables/"*.sql.gz; do - table_name=$(basename "$file" .sql.gz) - log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Tabelle: ${COLOR_LABEL}${table_name}${COLOR_RESET}" - gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" - done - - log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung aller Asset-Typen...${COLOR_RESET}" - for file in "$BACKUP_DIR/assettypen/"*.sql.gz; do - asset_name=$(basename "$file" .sql.gz) - log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Asset-Typ: ${COLOR_LABEL}${asset_name}${COLOR_RESET}" - gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" - done - ;; - tables) - log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung nur der Nicht-Asset-Tabellen...${COLOR_RESET}" - for file in "$BACKUP_DIR/tables/"*.sql.gz; do - table_name=$(basename "$file" .sql.gz) - log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Tabelle: ${COLOR_LABEL}${table_name}${COLOR_RESET}" - gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" - done - ;; - assets) - log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung aller Asset-Typen...${COLOR_RESET}" - for file in "$BACKUP_DIR/assettypen/"*.sql.gz; do - asset_name=$(basename "$file" .sql.gz) - log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Asset-Typ: ${COLOR_LABEL}${asset_name}${COLOR_RESET}" - gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" - done - ;; - *) - local file="$BACKUP_DIR/assettypen/assets_${RESTORE_SCOPE}.sql.gz" - if [[ -f "$file" ]]; then - log "${SYM_FOLDER} ${COLOR_LABEL}Wiederherstellung für Asset-Typ: ${COLOR_VALUE}${RESTORE_SCOPE}${COLOR_RESET}" - log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET}" - gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" - else - log "${SYM_BAD} ${COLOR_BAD}Fehler: Kein Backup für Asset-Typ '${RESTORE_SCOPE}' gefunden!${COLOR_RESET}" - return 1 - fi - ;; - esac - - log "${SYM_OK} ${COLOR_OK}Wiederherstellung erfolgreich abgeschlossen für Bereich: ${COLOR_VALUE}${RESTORE_SCOPE}${COLOR_RESET}" -} - -# todo: Testen, ob alles funktioniert. -# robustrepair -# dbuser: SQL-Benutzername -# dbpass: Passwort des SQL-Benutzers -# check: Prüft alle Tabellen auf Fehler -# repair: Repariert alle Tabellen automatisch -# truncate: Leert alle Inhalte, behält aber Tabellenstrukturen -# dropassets: Löscht alle Assets und Asset-Typen -# dropall: Löscht alle Tabelleninhalte -function robustrepair() { - local DB_USER=$1 - local DB_PASS=$2 - local DB_NAME="robust" - local ACTION=$3 # "check", "repair", "truncate", "dropassets", "dropall" - - log "${COLOR_HEADING}${SYM_TOOLS} Starte Datenbankwartung: ${COLOR_VALUE}${ACTION}${COLOR_RESET}" - - case "$ACTION" in - check) - log "${SYM_WAIT} ${COLOR_LABEL}Überprüfe Tabellen auf Fehler...${COLOR_RESET}" - mysqlcheck -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" - ;; - repair) - log "${SYM_BOOK} ${COLOR_LABEL}Repariere beschädigte Tabellen automatisch...${COLOR_RESET}" - mysqlcheck -u"$DB_USER" -p"$DB_PASS" --auto-repair "$DB_NAME" - ;; - truncate) - log "${SYM_WARNING} ${COLOR_WARNING}${SYM_WARNING} Achtung: Leert alle Inhalte, behält aber Tabellenstrukturen!${COLOR_RESET}" - echo -ne "${COLOR_BAD}$(msg LEGACY_PROMPT_CONTINUE_YESNO): ${COLOR_RESET}" - read -r confirm - if is_yes "$confirm"; then - local tables - tables=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SHOW TABLES IN $DB_NAME;") - for t in $tables; do - log "${SYM_CLEAN} Leere Tabelle: ${COLOR_LABEL}${t}${COLOR_RESET}" - mysql -u"$DB_USER" -p"$DB_PASS" -e "TRUNCATE TABLE $DB_NAME.$t;" - done - log "${SYM_OK} ${COLOR_OK}Alle Tabellen wurden geleert.${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_BAD}Abgebrochen.${COLOR_RESET}" - fi - ;; - dropassets) - log "${SYM_WARNING} ${COLOR_WARNING}${SYM_WARNING} Achtung: Löscht ALLE Einträge in der 'assets'-Tabelle!${COLOR_RESET}" - echo -ne "${COLOR_BAD}$(msg LEGACY_PROMPT_CONTINUE_YESNO): ${COLOR_RESET}" - read -r confirm - if is_yes "$confirm"; then - mysql -u"$DB_USER" -p"$DB_PASS" -e "DELETE FROM $DB_NAME.assets;" - log "${SYM_OK} ${COLOR_OK}Tabelle 'assets' wurde geleert.${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_BAD}Abgebrochen.${COLOR_RESET}" - fi - ;; - dropall) - log "${SYM_WARNING} ${COLOR_WARNING}${SYM_WARNING} Achtung: Alle Tabellen der Datenbank werden gelöscht!${COLOR_RESET}" - echo -ne "${COLOR_BAD}$(msg PROMPT_DROP_ALL_TABLES): ${COLOR_RESET}" - read -r confirm - if is_yes "$confirm"; then - local tables - tables=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SHOW TABLES IN $DB_NAME;") - for t in $tables; do - log "${SYM_CLEAN} Lösche Tabelle: ${COLOR_LABEL}${t}${COLOR_RESET}" - mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP TABLE $DB_NAME.$t;" - done - log "${SYM_OK} ${COLOR_OK}Alle Tabellen gelöscht.${COLOR_RESET}" - else - log "${SYM_BAD} ${COLOR_BAD}Abgebrochen.${COLOR_RESET}" - fi - ;; - *) - log "${SYM_BAD} ${COLOR_BAD}Unbekannte Aktion: ${ACTION}${COLOR_RESET}" - log "${SYM_INFO} Mögliche Optionen: check | repair | truncate | dropassets | dropall" - return 1 - ;; - esac -} - -# todo: Wenn die Parameter der Eingabe nicht stimmt, ausgeben was fehlt und der Aufruf der Funktion anzeigen: - -###* load und save oar und iar - -# - $1: Der Name des Besitzers. -# - $2: Das Verzeichnis, in das das IAR geladen werden soll -# - $3: Das Passwort fuer das IAR -# - $4: Der Dateiname des IAR -# bash osmtool.sh loadinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar" -function loadinventar() { - # Letzte Bearbeitung 30.09.2023 - LOADINVSCREEN="sim1" - NAME=$1 - VERZEICHNIS=$2 - local PASSWORD=$3 - DATEI=$4 - - if [ $# -ne 4 ]; then - echo "Falsche Anzahl an Parametern." - echo 'Verwendung: bash osmtool.sh loadinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar"' - return 1 - fi - - # Benutzer um Bestätigung fragen - echo "Soll die Datei '$DATEI' von '$VERZEICHNIS' für '$NAME' hochgeladen werden? (j/n)" - read -r ANTWORT - - if [[ "$ANTWORT" != "j" ]]; then - echo "Upload abgebrochen." - return 1 - fi - - # ueberpruefen, ob der 'screen'-Prozess existiert. - if screen -list | grep -q "$LOADINVSCREEN"; then - log "OSCOMMAND: load iar $NAME $VERZEICHNIS ***** $DATEI" - screen -S "$LOADINVSCREEN" -p 0 -X eval "stuff 'load iar $NAME $VERZEICHNIS $PASSWORD $DATEI'^M" - return 0 - else - log error "OSCOMMAND: Der Screen $LOADINVSCREEN existiert nicht" - return 1 - fi -} - -# $1 - Name des Inventars -# $2 - Verzeichnis, in dem das Inventar gespeichert werden soll -# $3 - Passwort (optional) -# $4 - Dateiname, unter dem das Inventar gespeichert wird -#? Verwendungsbeispiel: -# bash osmtool.sh saveinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar" -function saveinventar() { - # Letzte Bearbeitung 01.10.2023 - SAVEINVSCREEN="sim1" - NAME=$1 - VERZEICHNIS=$2 - local PASSWORD=$3 - DATEI=$4 - - if [ $# -ne 4 ]; then - echo "Falsche Anzahl an Parametern." - echo 'Verwendung: bash osmtool.sh saveinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar"' - return 1 - fi - - # Benutzer um Bestätigung fragen - echo "Soll die Datei '$DATEI' von '$VERZEICHNIS' für '$NAME' wirklich gespeichert werden? (j/n)" - read -r ANTWORT - - if [[ "$ANTWORT" != "j" ]]; then - echo "Speichern abgebrochen." - return 1 - fi - - # todo: fragen j/n ob tatsächlich gespeichert werden soll und die Parameter dabei anzeigen - if screen -list | grep -q "$SAVEINVSCREEN"; then - log "OSCOMMAND: save iar $NAME $VERZEICHNIS ***** $DATEI " - screen -S "$SAVEINVSCREEN" -p 0 -X eval "stuff 'save iar $NAME $VERZEICHNIS $PASSWORD $DATEI'^M" - return 0 - else - log "OSCOMMAND: Der Screen $SAVEINVSCREEN existiert nicht" - return 1 - fi -} - -#? Verwendungsbeispiel: -# bash osmtool.sh loadoar "sim1" "TestRegion" "backup.oar" -function loadoar() { - RESTOREVERZEICHNISSCREENNAME=$1 - REGIONSNAME=$2 - OARFILE=$3 - - if [ $# -ne 3 ]; then - echo "Falsche Anzahl an Parametern." - echo 'Verwendung: bash osmtool.sh loadoar "sim1" "TestRegion" "backup.oar"' - return 1 - fi - - # Benutzer um Bestätigung fragen - echo "Soll die Region '$REGIONSNAME' mit der Datei '$OARFILE.oar' wirklich wiederhergestellt werden? (j/n)" - read -r ANTWORT - - if [[ "$ANTWORT" != "j" ]]; then - echo "Wiederherstellung abgebrochen." - return 1 - fi - - log "OSRESTORE: Region $NSDATEINAME wiederherstellen" - cd /"$SCRIPT_DIR"/"$RESTOREVERZEICHNISSCREENNAME"/bin || return 1 - log "Ich kann nicht pruefen ob die Region im OpenSimulator vorhanden ist." - log "Sollte sie nicht vorhanden sein wird root also alle Regionen wiederhergestellt." - # todo: fragen j/n ob tatsächlich hochgeladen werden soll und die Parameter dabei anzeigen - screen -S "$RESTOREVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'change region ${REGIONSNAME//\"/}'^M" - screen -S "$RESTOREVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'load oar $OARFILE'^M" - - log "OSRESTORE: Region $REGIONSNAME wird wiederhergestellt" - return 0 -} - -# Aufruf: saveoar "sim1" "testregion" "/pfad/zum/backup.oar" -function saveoar() { - local SCREENNAME=$1 - local REGIONNAME=$2 - local OARFILE=$3 - - if [ $# -ne 3 ]; then - echo "Falsche Anzahl an Parametern." - echo 'Verwendung: bash osmtool.sh saveoar "sim1" "testregion" "/pfad/zum/backup.oar"' - return 1 - fi - - # Prüfen, ob alle Parameter gesetzt sind - if [[ -z "$SCREENNAME" || -z "$REGIONNAME" || -z "$OARFILE" ]]; then - echo "Fehler: Screen-Name, Regionsname und OAR-Datei müssen angegeben werden!" - return 1 - fi - - # Benutzer um Bestätigung fragen - echo "Soll die Region '$REGIONNAME' wirklich in '$OARFILE' gesichert werden? (j/n)" - read -r ANTWORT - - if [[ "$ANTWORT" != "j" ]]; then - echo "Speicherung abgebrochen." - return 1 - fi - - # Prüfen, ob der Screen existiert - if ! screen -list | grep -q "$SCREENNAME"; then - echo "$SCREENNAME" - echo "Fehler: Der Screen '$SCREENNAME' existiert nicht!" - return 1 - fi - - # Region auswählen und OAR-Datei speichern - echo "Sichere Region '$REGIONNAME' in '$OARFILE'..." - screen -S "$SCREENNAME" -p 0 -X eval "stuff 'change region $REGIONNAME'^M" - screen -S "$SCREENNAME" -p 0 -X eval "stuff 'save oar \"$OARFILE\"'^M" - - echo "Region erfolgreich gesichert!" - return 0 -} - -# bash osmtool.sh autoregionbackup -function autoregionbackup() { - # Konfiguration - local BACKUP_ROOT="$SCRIPT_DIR/backup" # Relativer Pfad - local BACKUP_WAIT=180 # 180, 300 , 500 Wartezeit zwischen Backups, zu kleine Werte uberfordern den Server. - DATUM=$(date +%Y%m%d_%H%M%S) - - # Backup-Verzeichnis erstellen - mkdir -p "$BACKUP_ROOT" || { - echo "FEHLER: Backup-Verzeichnis konnte nicht erstellt werden" - return 1 - } - - # Funktion zum Extrahieren des Regionsnamens aus der INI-Datei - get_region_name() { - local ini_file="$1" - # Extrahiere den Namen zwischen [ ] - grep -oP '^\[\K[^\]]+' "$ini_file" | head -1 - } - - # Durchsuche alle simX/bin/Regions-Verzeichnisse - for ((i=1; i<=999; i++)); do - local sim_name="sim$i" - local regions_dir="$sim_name/bin/Regions" - - if [[ -d "$sim_name/bin" && -d "$regions_dir" ]]; then - echo "Verarbeite Simulator: $sim_name" - - # Backup-Verzeichnis erstellen - mkdir -p "$BACKUP_ROOT/$sim_name" || { - echo "FEHLER: Backup-Verzeichnis konnte nicht erstellt werden" - return 1 - } - - # Verarbeite jede Regions-Konfiguration - for region_file in "$regions_dir"/*.ini; do - [[ -f "$region_file" ]] || continue - - # Extrahiere den echten Regionsnamen aus der INI-Datei (mit Leerzeichen) - display_name=$(get_region_name "$region_file") - safe_name=$(basename "$region_file" .ini) # Dateiname als Fallback - - # Verwende den echten Namen wenn vorhanden, sonst Dateinamen - local region_name=${display_name:-$safe_name} - safe_filename=$(echo "$region_name" | tr ' ' '_') # Für Dateinamen - - # Überspringe Offline-Regionen - if [[ -f "$region_file.offline" ]]; then - echo "Überspringe offline Region: $region_name" - continue - fi - - echo "Starte Backup von: $sim_name $region_name" - - # 1. Region auswählen (mit Originalname und Leerzeichen) - screen -S "$sim_name" -p 0 -X eval "stuff 'change region \"${region_name//\"/}\"'^M" - echo "change region \"$region_name\"" - sleep 1 - - # 2. OAR-Backup (mit safe_filename) - screen -S "$sim_name" -p 0 -X eval "stuff 'save oar \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.oar\"'^M" - echo "Backup: $DATUM-${safe_filename}.oar" - sleep 1 - - # 3. XML2-Backup - screen -S "$sim_name" -p 0 -X eval "stuff 'save xml2 \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.xml2\"'^M" - echo "Backup: $DATUM-${safe_filename}.xml2" - sleep 1 - - # 4. Terrain-Backups - screen -S "$sim_name" -p 0 -X eval "stuff 'terrain save \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.png\"'^M" - screen -S "$sim_name" -p 0 -X eval "stuff 'terrain save \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.raw\"'^M" - echo "Terrain: $DATUM-${safe_filename}.png/.raw" - sleep 1 - - # 5. Regions-Konfiguration kopieren - if [[ -f "$region_file" ]]; then - cp "$region_file" "$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.ini" - echo "Kopiere: $DATUM-${safe_filename}.ini" - sleep 1 - fi - - echo "Erstelle Backup: $BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.*" - sleep "$BACKUP_WAIT" - done - fi - done - - echo "Backup aller Regionen abgeschlossen" - return 0 -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Bereinigen des OpenSimulators Grids -#?────────────────────────────────────────────────────────────────────────────────────────── - -function dataclean() { - log "${COLOR_HEADING}🧹 Datenbereinigung wird durchgeführt...${COLOR_RESET}" - - # RobustServer bereinigen - if [[ -d "robust/bin" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Lösche Dateien im RobustServer...${COLOR_RESET}" - find "robust/bin" -maxdepth 1 -type f \( -name "*.log" -o -name "*.dll" -o -name "*.exe" -o -name "*.so" -o -name "*.xml" -o -name "*.dylib" -o -name "*.example" -o -name "*.sample" -o -name "*.txt" -o -name "*.config" -o -name "*.py" -o -name "*.old" -o -name "*.pdb" \) -delete - fi - - # Alle simX-Server bereinigen - for ((i=1; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Lösche Dateien in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" - find "$sim_dir" -maxdepth 1 -type f \( -name "*.log" -o -name "*.dll" -o -name "*.exe" -o -name "*.so" -o -name "*.xml" -o -name "*.dylib" -o -name "*.example" -o -name "*.sample" -o -name "*.txt" -o -name "*.config" -o -name "*.py" -o -name "*.old" -o -name "*.pdb" \) -delete - sleep 1 - fi - done - log "${COLOR_HEADING}${SYM_OKNN} Datenbereinigung abgeschlossen${COLOR_RESET}" - blankline -} - -function pathclean() { - directories=("assetcache" "maptiles" "MeshCache" "j2kDecodeCache" "ScriptEngines" "bakes" "addon-modules") - wildcard_dirs=("addin-db-*") # Separate Liste für Wildcard-Verzeichnisse - - log "${COLOR_HEADING}🗂️ Verzeichnisbereinigung wird durchgeführt...${COLOR_RESET}" - - # RobustServer bereinigen - if [[ -d "robust/bin" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Lösche komplette Verzeichnisse im RobustServer...${COLOR_RESET}" - - # Normale Verzeichnisse - for dir in "${directories[@]}"; do - target="robust/bin/$dir" - if [[ -d "$target" ]]; then - rm -rf "$target" - log " ${COLOR_ACTION}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" - fi - done - - # Wildcard-Verzeichnisse - for pattern in "${wildcard_dirs[@]}"; do - for target in robust/bin/$pattern; do - if [[ -d "$target" ]]; then - rm -rf "$target" - log " ${COLOR_WARNING}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" - fi - done - done - fi - - # Alle simX-Server bereinigen - for ((i=1; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Lösche komplette Verzeichnisse in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" - - # Normale Verzeichnisse - for dir in "${directories[@]}"; do - target="$sim_dir/$dir" - if [[ -d "$target" ]]; then - rm -rf "$target" - log " ${COLOR_ACTION}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" - sleep 1 - fi - done - - # Wildcard-Verzeichnisse - for pattern in "${wildcard_dirs[@]}"; do - for target in $sim_dir/$pattern; do - if [[ -d "$target" ]]; then - rm -rf "$target" - log " ${COLOR_WARNING}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" - fi - done - done - fi - done - log "${COLOR_HEADING}${SYM_OKNN} Verzeichnisbereinigung abgeschlossen${COLOR_RESET}" - blankline -} - -function cacheclean() { - #cache_dirs=("assetcache" "maptiles" "MeshCache" "j2kDecodeCache" "ScriptEngines") - cache_dirs=("assetcache" "MeshCache" "j2kDecodeCache" "ScriptEngines") - - log "${COLOR_HEADING}♻️ Cache-Bereinigung wird durchgeführt...${COLOR_RESET}" - - # RobustServer bereinigen - if [[ -d "robust/bin" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Leere Cache-Verzeichnisse im RobustServer...${COLOR_RESET}" - for dir in "${cache_dirs[@]}"; do - target="robust/bin/$dir" - if [[ -d "$target" ]]; then - find "$target" -mindepth 1 -delete - log " ${COLOR_ACTION}Inhalt geleert: ${COLOR_DIR}$target${COLOR_RESET}" - fi - done - fi - - # Alle simX-Server bereinigen - for ((i=1; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Leere Cache-Verzeichnisse in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" - for dir in "${cache_dirs[@]}"; do - target="$sim_dir/$dir" - if [[ -d "$target" ]]; then - find "$target" -mindepth 1 -delete - log " ${COLOR_ACTION}Inhalt geleert: ${COLOR_DIR}$target${COLOR_RESET}" - sleep 1 - fi - done - fi - done - log "${COLOR_HEADING}${SYM_OKNN} Cache-Bereinigung abgeschlossen${COLOR_RESET}" - blankline -} - -function logclean() { - log "${SYM_LOG}${COLOR_HEADING} Log-Bereinigung wird durchgeführt...${COLOR_RESET}" - - # RobustServer bereinigen - if [[ -d "robust/bin" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Lösche Log-Dateien in ${COLOR_DIR}robust/bin...${COLOR_RESET}" - rm -f robust/bin/*.log - fi - - # Alle simX-Server bereinigen (sim1 bis sim999) - for ((i=1; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" ]]; then - log "${SYM_OK} ${COLOR_ACTION}Lösche Log-Dateien in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" - rm -f "$sim_dir"/*.log - sleep 1 - fi - done - - log "${COLOR_HEADING}Log-Bereinigung abgeschlossen${COLOR_RESET}" - blankline -} - -function mapclean() { - log "${COLOR_HEADING}🗺️ Map-Tile-Bereinigung wird durchgeführt...${COLOR_RESET}" - - # Sicherheitscheck für robust/bin/maptiles - if [[ -d "robust/bin/maptiles" ]]; then - rm -rf -- "robust/bin/maptiles/"* - log "${SYM_OK} ${COLOR_ACTION}robust/bin/maptiles geleert${COLOR_RESET}" - fi - - # Sicherheitscheck für alle simX/bin/maptiles - for ((i=1; i<=999; i++)); do - local sim_dir="sim$i/bin/maptiles" - if [[ -d "$sim_dir" ]]; then - # shellcheck disable=SC2115 - rm -rf -- "${sim_dir}/"* - log "${SYM_OK} ${COLOR_ACTION}${COLOR_DIR}$sim_dir${COLOR_RESET} ${COLOR_ACTION}geleert${COLOR_RESET}" - sleep 1 - fi - done - - log "${COLOR_HEADING}${SYM_OKNN} Map-Tile-Bereinigung abgeschlossen${COLOR_RESET}" - blankline -} - -function autoallclean() { - local confirm - - # Warnung in Gelb (konsistenter mit \e anstelle von \033) - log "\e[33m" - cat >&2 <<'WARNUNG' -=== WARNUNG: Alle Daten-, Verzeichnis-, Cache-, Log- und Map-Daten werden bereinigt! === -=== DIESE OPERATION KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN! === -=== DER OPENSIMULATOR MUSS IM ANSCHLUSS NEU INSTALLIERT WERDEN! === -WARNUNG - log "\e[0m" - - # Bestätigung mit Timeout (10 Sekunden) für Sicherheit - read -t 30 -r -p "$(msg PROMPT_CONTINUE_TIMEOUT_YESNO) " confirm || { - log "\n\e[31mTimeout: Keine Bestätigung erhalten. Abbruch.\e[0m" >&2 - return 1 - } - - if is_yes "$confirm"; then - log "\e[32mBereinigung wird gestartet...\e[0m" >&2 - # Jede Clean-Funktion mit Fehlerprüfung - local clean_functions=(dataclean pathclean cacheclean logclean mapclean) - for func in "${clean_functions[@]}"; do - if ! command -v "$func" &>/dev/null; then - log "\e[31mFehler: '$func' ist keine gültige Funktion!\e[0m" >&2 - return 1 - fi - "$func" || { - log "\e[31mFehler bei $func!\e[0m" >&2 - return 1 - } - done - log "\e[32mBereinigung abgeschlossen.\e[0m" >&2 - else - log "\e[33mAbbruch: Bereinigung wurde nicht durchgeführt.\e[0m" >&2 - return 1 - fi - blankline -} - -function clean_linux_logs() { - local log_files=() - log "${COLOR_SECTION}${SYM_LOG} Suche nach alten Log-Dateien...${COLOR_RESET}" - - # Find and list files to be deleted - while IFS= read -r -d $'\0' file; do - log_files+=("$file") - log "${COLOR_FILE}${SYM_INFO} ${COLOR_LABEL}Gelöscht wird:${COLOR_RESET} ${COLOR_VALUE}$file${COLOR_RESET}" - done < <(find "/var/log" -name "*.log" -type f -mtime +7 -print0) - - if [ ${#log_files[@]} -eq 0 ]; then - log "${SYM_OK} ${COLOR_LABEL}Keine alten Log-Dateien gefunden.${COLOR_RESET}" - return 0 - fi - - log "${COLOR_WARNING}${#log_files[@]} Log-Dateien werden gelöscht. Fortfahren? (j/N) ${COLOR_RESET}" - read -r confirm - case "${confirm,,}" in - j|ja|y|yes) - find "/var/log" -name "*.log" -type f -mtime +7 -delete - log "${SYM_OK} ${COLOR_OK}${#log_files[@]} Log-Dateien wurden gelöscht.${COLOR_RESET}" - ;; - *) - log "${SYM_BAD} ${COLOR_BAD}Bereinigung abgebrochen.${COLOR_RESET}" - return 1 - ;; - esac -} - -function delete_opensim() { - log "${COLOR_HEADING}🗺️ Das komplette löschen vom OpenSimulator wird durchgeführt...${COLOR_RESET}" - - # Sicherheitsabfrage hinzufügen - read -rp "Sind Sie sicher, dass Sie ALLE OpenSimulator-Daten löschen möchten? (ja/N) " answer - [[ ${answer,,} != "ja" ]] && { echo "Abbruch."; return 1; } - - # Robust-Verzeichnis sicher löschen - if [[ -d "robust" ]]; then - rm -rf -- "robust" # Keine Wildcard mehr - log "${SYM_OK} ${COLOR_ACTION}robust komplett entfernt${COLOR_RESET}" - fi - - # Simulator-Verzeichnisse sicher löschen - for ((i=1; i<=999; i++)); do - local sim_dir="sim$i" - if [[ -d "$sim_dir" ]]; then - rm -rf -- "$sim_dir" # Keine Wildcard mehr - log "${SYM_OK} ${COLOR_ACTION}${COLOR_DIR}$sim_dir${COLOR_RESET} ${COLOR_ACTION}komplett entfernt${COLOR_RESET}" - sleep 1 - fi - done - - log "${COLOR_HEADING}${SYM_OKNN} Das komplette löschen vom OpenSimulator abgeschlossen${COLOR_RESET}" - blankline -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Konfigurationen -#?────────────────────────────────────────────────────────────────────────────────────────── - -# [Abschnitt] -# Schlüssel = Wert -# ; Kommentar -# [Section] -# Key = Value -# ; Comment - -# Überprüft, ob ein bestimmter Abschnitt (Section) in einer INI-Datei existiert, und gibt das Ergebnis als Exit-Code zurück. -# Aufruf: bash osmtool.sh verify_ini_section "test.ini" "Const" -# Letzte Prüfung am: 24.04.2025 -function verify_ini_section() { - local file="$1" - local section="$2" - - if [ ! -f "$file" ]; then - log "${SYM_BAD} Error: File ${file} does not exist" >&2 - return 2 - fi - - if grep -q "^\[${section}\]" "$file"; then - log "${SYM_OK} Section [${section}] exists in ${file}" - return 0 - else - log "${SYM_BAD} Section [${section}] not found in ${file}" - return 1 - fi -} - -# Überprüft, ob ein bestimmten Wert (key) im Abschnitt (Section) in einer INI-Datei existiert, und gibt das Ergebnis als Exit-Code zurück. -# Aufruf: bash osmtool.sh verify_ini_key "test.ini" "DatabaseService" "Include-Storage" -# Letzte Prüfung am: 24.04.2025 Repariert: 24.04.2025 -function verify_ini_key() { - local file="$1" - local section="$2" - local key="$3" - - if [ ! -f "$file" ]; then - log "${SYM_BAD} Error: File ${file} does not exist" >&2 - return 2 - fi - - # Einfacher grep-Befehl, der Leerzeichen & Kommentare ignoriert - if grep -Eq "^[[:space:]]*\[${section}\][[:space:]]*$" "$file" && \ - grep -Eq "^[[:space:]]*${key}[[:space:]]*=" "$file"; then - log "${SYM_OK} Key '${key}' exists in section [${section}]" - return 0 - else - log "${SYM_BAD} Key '${key}' NOT FOUND in section [${section}]" >&2 - return 1 - fi -} - -# Fügt einene Abschnitt hinzu, wenn es noch nicht vorhanden ist am ende der Datei. -# Aufruf: bash osmtool.sh add_ini_section "test.ini" "Const" -# Letzte Prüfung am: 24.04.2025 -function add_ini_section() { - local file="$1" - local section="$2" - - if verify_ini_section "$file" "$section" >/dev/null; then - return 0 - fi - - log "${SYM_INFO} Adding section [${section}] to ${file}" - - # Abschnitt am Ende der Datei hinzufügen - if printf "\n[%s]\n" "$section" >> "$file"; then - log "${SYM_OK} Successfully added section [${section}] to ${file}" - return 0 - else - log "${SYM_BAD} Failed to add section [${section}] to ${file}" >&2 - return 1 - fi -} - -# Fügt einene Abschnitt, wenn es noch nicht vorhanden ist vor dem Zielabschnitt hinzu. -# Also [Const] wird vor [DatabaseService] hinzugefügt. -# Aufruf: bash osmtool.sh add_ini_before_section "test.ini" "Const" "DatabaseService" -function add_ini_before_section() { - local file="$1" - local section="$2" - local target_section="$3" # Neuer Parameter für den Zielabschnitt - - if verify_ini_section "$file" "$section" >/dev/null; then - return 0 - fi - - #log "${SYM_INFO} Adding section [${section}] to ${file} before [${target_section}]" - - # Temporäre Datei erstellen - temp_file=$(mktemp) - - # Zielabschnitt suchen und neuen Abschnitt davor einfügen - local found=0 - while IFS= read -r line; do - if [[ "$line" =~ ^\[${target_section}\] ]]; then - printf "[%s]\n\n" "$section" >> "$temp_file" - found=1 - fi - echo "$line" >> "$temp_file" - done < "$file" - - # Falls Zielabschnitt nicht gefunden, am Ende einfügen (Fallback) - if [[ $found -eq 0 ]]; then - printf "\n[%s]\n" "$section" >> "$temp_file" - log "${SYM_WARNING} Target section [${target_section}] not found, appended [${section}] at end of file" - fi - - # Originaldatei ersetzen - if mv "$temp_file" "$file"; then - log "${SYM_OK} Successfully added section [${section}] to ${file}" - return 0 - else - log "${SYM_BAD} Failed to update ${file}" >&2 - return 1 - fi -} - -# Setzt den Wert des Keys in der gegebenen Sektion -# bash osmtool.sh set_ini_key "test.ini" "Const" "GridSize" "256" -# [Const] -# GridSize = 256 -# -# Wenn die Sektion oder der Key nicht vorhanden ist, wird er hinzugefügt. -# Falls der Key bereits vorhanden ist, wird der Wert aktualisiert. -function set_ini_key() { - local file="$1" section="$2" key="$3" value="$4" - local temp_file - temp_file=$(mktemp) || { - log "${COLOR_BAD}Fehler beim Erstellen der temporären Datei${COLOR_RESET}" >&2 - return 1 - } - - # Key für Regex absichern - local key_escaped - key_escaped=$(printf '%s\n' "$key" | sed 's/[]\/$*.^[]/\\&/g') - - # Verarbeitung mit awk - awk -v section="[$section]" -v key="$key" -v value="$value" -v key_re="$key_escaped" ' - BEGIN { in_section = 0; key_set = 0 } - - { - trimmed = $0 - sub(/^[[:space:]]+/, "", trimmed) - if (trimmed == section) { - print - in_section = 1 - next - } - - if (in_section && trimmed ~ /^\[.*\]/) { - if (!key_set) { - printf "%s = %s\n\n", key, value - key_set = 1 - } - in_section = 0 - } - - if (in_section && $0 ~ "^[[:blank:]]*" key_re "[[:blank:]]*=") { - printf "%s = %s\n", key, value - key_set = 1 - next - } - - print - } - - END { - if (in_section && !key_set) { - printf "%s = %s\n", key, value - } else if (!key_set) { - printf "\n[%s]\n%s = %s\n", section, key, value - } - }' "$file" > "$temp_file" || { - log "${COLOR_BAD}AWK-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 - rm -f "$temp_file" - return 1 - } - - if ! mv "$temp_file" "$file"; then - log "${COLOR_BAD}Konnte Datei ${COLOR_FILE}${file}${COLOR_RESET} nicht aktualisieren" >&2 - rm -f "$temp_file" - return 1 - fi - - log "${COLOR_OK}Gesetzt: ${COLOR_KEY}${key} = ${COLOR_VALUE}${value}${COLOR_OK} in [${section}]${COLOR_RESET}" - return 0 -} - -# Setze einen Key in einer INI-Datei -# Die INI-Datei wird nach dem Schlüssel durchsucht und der Key wird -# am passenden Ort eingefügt. -function add_ini_key() { - local file="$1" section="$2" key="$3" value="$4" - local temp_file - temp_file=$(mktemp) || { - log "${COLOR_BAD}Failed to create temp file${COLOR_RESET}" >&2 - return 1 - } - - # Verarbeitung mit awk - if ! awk -v section="[${section}]" -v key="$key" -v value="$value" ' - BEGIN { in_section = 0; modified = 0 } - $0 == section { in_section = 1; print; next } - in_section && /^\[/ { - # Neue Sektion beginnt, Key einfügen (mit Leerzeichen um das =) - printf "%s = %s\n\n", key, value - modified = 1 - in_section = 0 - } - in_section && $0 ~ "^[[:blank:]]*" key "[[:blank:]]*=" { - # Existierenden Key ersetzen (mit Leerzeichen um das =) - printf "%s = %s\n", key, value - modified = 1 - in_section = 0 - next - } - { print } - END { - if (!modified && in_section) { - # Am Ende der Sektion einfügen (mit Leerzeichen um das =) - printf "%s = %s\n", key, value - } else if (!modified) { - # Neue Sektion am Dateiende (mit Leerzeichen um das =) - printf "\n[%s]\n%s = %s\n", section, key, value - } - } - ' "$file" > "$temp_file"; then - log "${COLOR_BAD}AWK processing failed${COLOR_RESET}" >&2 - rm -f "$temp_file" - return 1 - fi - - if ! mv "$temp_file" "$file"; then - log "${COLOR_BAD}Failed to update ${COLOR_FILE}${file}${COLOR_RESET}" >&2 - return 1 - fi - - log "${COLOR_OK}Set ${COLOR_KEY}${key} = ${COLOR_VALUE}${value}${COLOR_OK} in [${section}]${COLOR_RESET}" - return 0 -} - -function del_ini_section() { - local file="$1" - local section="$2" - - # Verifizieren ob der Abschnitt existiert (still, ohne Ausgabe) - if ! verify_ini_section "$file" "$section" >/dev/null; then - log "${SYM_INFO} Section [${section}] not found in ${COLOR_FILE}${file}${COLOR_RESET}" - return 0 - fi - - log "${SYM_INFO} Removing section [${COLOR_SECTION}${section}${COLOR_RESET}] from ${COLOR_FILE}${file}${COLOR_RESET}" - - # Temporäre Datei mit Fehlerbehandlung - local temp_file - temp_file=$(mktemp) || { - log "${SYM_BAD} Failed to create temporary file" >&2 - return 1 - } - - # Abschnitt entfernen - if awk -v section="[${section}]" ' - $0 == section { skip=1; next } - skip && /^\[/ { skip=0 } - !skip { print } - ' "$file" > "$temp_file"; then - - if mv "$temp_file" "$file"; then - log "${SYM_OK} Successfully removed section [${COLOR_SECTION}${section}${COLOR_RESET}]" - return 0 - else - log "${SYM_BAD} Failed to update ${COLOR_FILE}${file}${COLOR_RESET}" >&2 - rm -f "$temp_file" - return 1 - fi - - else - log "${SYM_BAD} AWK processing failed" >&2 - rm -f "$temp_file" - return 1 - fi -} - -function uncomment_ini_line() { - local file="$1" - local search_key="$2" - - # Sicherheitsprüfungen - [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } - [ -z "$search_key" ] && { log "${COLOR_BAD}Suchschlüssel darf nicht leer sein${COLOR_RESET}" >&2; return 1; } - - # Temporäre Datei erstellen - local temp_file - temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } - - # Entkommentieren der Zeile - sed -E "/^[[:space:]]*;[[:space:]]*${search_key}[[:space:]]*=/s/^[[:space:]]*;//" "$file" > "$temp_file" || { - rm -f "$temp_file" - log "${COLOR_BAD}Sed-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 - return 1 - } - - # Originaldatei ersetzen - if mv "$temp_file" "$file"; then - log "${COLOR_OK}Zeile '${search_key}' erfolgreich entkommentiert${COLOR_RESET}" - return 0 - else - log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 - return 1 - fi -} - -function uncomment_ini_section_line() { - local file="$1" - local section="$2" - local search_key="$3" - - # Sicherheitsprüfungen - [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } - [ -z "$section" ] && { log "${COLOR_BAD}Sektion darf nicht leer sein${COLOR_RESET}" >&2; return 1; } - [ -z "$search_key" ] && { log "${COLOR_BAD}Suchschlüssel darf nicht leer sein${COLOR_RESET}" >&2; return 1; } - - # Temporäre Datei erstellen - local temp_file - temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } - - # Entkommentieren der Zeile in der richtigen Sektion - awk -v section="[$section]" -v key="$search_key" ' - BEGIN { in_section = 0 } - $0 ~ "^\\[" section "\\]" { in_section = 1; print; next } - in_section && /^\[/ { in_section = 0 } # Sektion beendet - in_section && /^[[:space:]]*;[[:space:]]*"key"[[:space:]]*=[[:space:]]*/ { - sub(/^[[:space:]]*;/, "", $0) - } - { print } - ' "$file" > "$temp_file" || { - rm -f "$temp_file" - log "${COLOR_BAD}AWK-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 - return 1 - } - - # Originaldatei ersetzen - if mv "$temp_file" "$file"; then - log "${COLOR_OK}Zeile '${search_key}' in Sektion '${section}' erfolgreich entkommentiert${COLOR_RESET}" - return 0 - else - log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 - return 1 - fi -} -function comment_ini_line() { - local file="$1" - local section="$2" - local search_key="$3" - - # Sicherheitsprüfungen - [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } - [ -z "$section" ] && { log "${COLOR_BAD}Sektion darf nicht leer sein${COLOR_RESET}" >&2; return 1; } - [ -z "$search_key" ] && { log "${COLOR_BAD}Suchschlüssel darf nicht leer sein${COLOR_RESET}" >&2; return 1; } - - # Temporäre Datei erstellen - local temp_file - temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } - - # Zeile in der richtigen Sektion kommentieren - awk -v section="[$section]" -v key="$search_key" ' - BEGIN { in_section = 0 } - $0 ~ "^\\[" section "\\]" { in_section = 1; print; next } - in_section && /^\[/ { in_section = 0 } - in_section && $0 ~ key && !/^[[:space:]]*;/ { - # Nur nicht bereits kommentierte Zeilen kommentieren - sub(/^[[:space:]]*/, "&;", $0) - print $0 - next - } - { print } - ' "$file" > "$temp_file" || { - rm -f "$temp_file" - log "${COLOR_BAD}AWK-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 - return 1 - } - - # Originaldatei ersetzen - if mv "$temp_file" "$file"; then - log "${COLOR_OK}Zeile '${search_key}' in Sektion '${section}' erfolgreich kommentiert${COLOR_RESET}" - return 0 - else - log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 - return 1 - fi -} - -function clear_ini_section() { - local file="$1" - local section="$2" - - # Sicherheitsprüfungen - [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } - [ -z "$section" ] && { log "${COLOR_BAD}Sektion darf nicht leer sein${COLOR_RESET}" >&2; return 1; } - - # Temporäre Datei erstellen - local temp_file - temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } - - # AWK zum Leeren der Sektion (behält Header) - awk -v section="$section" ' - BEGIN { in_section = 0 } - - # Sektionsanfang erkennen - $0 ~ "^\\[" section "\\]" { - in_section = 1 - print $0 # Header ausgeben - next - } - - # Sektionsende erkennen - in_section && /^\[/ { - in_section = 0 - } - - # Innerhalb der Sektion: nichts ausgeben (löschen) - in_section { next } - - # Außerhalb der Sektion: normale Ausgabe - { print } - ' "$file" > "$temp_file" - - # Originaldatei ersetzen - if mv "$temp_file" "$file"; then - log "${COLOR_OK}Sektion '[${section}]' erfolgreich geleert${COLOR_RESET}" - return 0 - else - log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 - return 1 - fi -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Konfigurationen der einzelnen Dienste -#?────────────────────────────────────────────────────────────────────────────────────────── - -# [Abschnitt] -# Schlüssel = Wert -# ; Kommentar -# [Section] -# Key = Value -# ; Comment - - -function database_set_iniconfig() { - # 30.04.2025 - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - local section="DatabaseService" - - # Zugangsdaten auslesen - local db_user db_pass - # Zeilenumbrüche entfernen - db_user=$(grep -oP '^DB_Benutzername\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') - db_pass=$(grep -oP '^DB_Passwort\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') - - - if [[ -z "$db_user" || -z "$db_pass" ]]; then - log "${COLOR_BAD}DB_Benutzername oder DB_Passwort fehlt in UserInfo.ini${COLOR_RESET}" - return 1 - fi - - # === Robust-Datenbanken === - local db_database="robust" - local robust_conn="Data Source=localhost;Database=${db_database};User ID=${db_user};Password=${db_pass};Old Guids=true;SslMode=None;" - - # Robust.HG.ini - local robust_hg_ini="robust/bin/Robust.HG.ini" - if [[ -f "$robust_hg_ini" ]]; then - add_ini_key "$robust_hg_ini" "$section" "ConnectionString" "\"$robust_conn\"" - else - log "${COLOR_WARNING}Datei nicht gefunden: $robust_hg_ini${COLOR_RESET}" - fi - - # Robust.local.ini - local robust_ini="robust/bin/Robust.local.ini" - if [[ -f "$robust_ini" ]]; then - add_ini_key "$robust_ini" "$section" "ConnectionString" "\"$robust_conn\"" - else - log "${COLOR_WARNING}Datei nicht gefunden: $robust_ini${COLOR_RESET}" - fi - - # === simX-Datenbanken === - for ((i=1; i<=1000; i++)); do - local sim_ini="${SCRIPT_DIR}/sim${i}/bin/config-include/GridCommon.ini" - if [[ -f "$sim_ini" ]]; then - local sim_conn="Data Source=localhost;Database=sim${i};User ID=${db_user};Password=${db_pass};Old Guids=true;SslMode=None;" - add_ini_key "$sim_ini" "$section" "ConnectionString" "\"$sim_conn\"" - fi - done - - log "${COLOR_OK}Datenbanken erfolgreich konfiguriert${COLOR_RESET}" - blankline -} - - - -# Welcome-Region konfigurieren wenn sie noch nicht existiert. -function welcomeiniconfig() { - # 25.04.2025 - local ip="$1" - gridname="$2" - - # Gridname bereinigen - gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') - - local welcome_ini="${SCRIPT_DIR}/sim1/bin/Regions/$gridname.ini" - - # Überprüfen ob die Welcome-Region bereits existiert - if [[ -f "$welcome_ini" ]]; then - log "${COLOR_INFO}Überspringe Erstellung der Welcome-Region: '$gridname.ini' existiert bereits${COLOR_RESET}" - # Vorsichtshalber Region in Robust-Konfigurationen eintragen. - set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.HG.ini" "GridService" "Region_$gridname" "\"DefaultRegion, DefaultHGRegion, FallbackRegion\"" - set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.local.ini" "GridService" "Region_$gridname" "\"DefaultRegion, FallbackRegion\"" - return - fi - - # region_uuid=$(uuidgen) - #region_uuid=$(command -v uuidgen >/dev/null && uuidgen || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") - region_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") - - # Datei erstellen - #touch "$welcome_ini" - #touch "$welcome_ini" || echo "" > "$welcome_ini" - touch "$welcome_ini" 2>/dev/null || echo "" > "$welcome_ini" - - # 2. Sektion hinzufügen - add_ini_section "$welcome_ini" "$gridname" - - # 3. Alle Key-Value Paare setzen - set_ini_key "$welcome_ini" "$gridname" "RegionUUID" "$region_uuid" - set_ini_key "$welcome_ini" "$gridname" "Location" "3000,3000" - set_ini_key "$welcome_ini" "$gridname" "SizeX" "256" - set_ini_key "$welcome_ini" "$gridname" "SizeY" "256" - set_ini_key "$welcome_ini" "$gridname" "SizeZ" "256" - set_ini_key "$welcome_ini" "$gridname" "InternalPort" "9015" - set_ini_key "$welcome_ini" "$gridname" "ExternalHostName" "$system_ip" - set_ini_key "$welcome_ini" "$gridname" "MaxPrims" "15000" - set_ini_key "$welcome_ini" "$gridname" "MaxAgents" "40" - set_ini_key "$welcome_ini" "$gridname" "MaptileStaticUUID" "$region_uuid" - set_ini_key "$welcome_ini" "$gridname" "InternalAddress" "0.0.0.0" - set_ini_key "$welcome_ini" "$gridname" "AllowAlternatePorts" "False" - - set_ini_key "$welcome_ini" "$gridname" ";NonPhysicalPrimMax" "512" - set_ini_key "$welcome_ini" "$gridname" ";PhysicalPrimMax" "128" - set_ini_key "$welcome_ini" "$gridname" ";ClampPrimSize" "false" - set_ini_key "$welcome_ini" "$gridname" ";MaxPrimsPerUser" "-1" - set_ini_key "$welcome_ini" "$gridname" ";ScopeID" "$region_uuid" - set_ini_key "$welcome_ini" "$gridname" ";RegionType" "Mainland" - set_ini_key "$welcome_ini" "$gridname" ";RenderMinHeight" "-1" - set_ini_key "$welcome_ini" "$gridname" ";RenderMaxHeight" "100" - set_ini_key "$welcome_ini" "$gridname" ";MapImageModule" "Warp3DImageModule" - set_ini_key "$welcome_ini" "$gridname" ";TextureOnMapTile" "true" - set_ini_key "$welcome_ini" "$gridname" ";DrawPrimOnMapTile" "true" - set_ini_key "$welcome_ini" "$gridname" ";GenerateMaptiles" "true" - set_ini_key "$welcome_ini" "$gridname" ";MaptileRefresh" "0" - set_ini_key "$welcome_ini" "$gridname" ";MaptileStaticFile" "path/to/SomeFile.png" - set_ini_key "$welcome_ini" "$gridname" ";MasterAvatarFirstName" "John" - set_ini_key "$welcome_ini" "$gridname" ";MasterAvatarLastName" "Doe" - set_ini_key "$welcome_ini" "$gridname" ";MasterAvatarSandboxPassword" "passwd" - - # 4. Region in Robust-Konfigurationen eintragen - # DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate - set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.HG.ini" "GridService" "Region_$gridname" "\"DefaultRegion, DefaultHGRegion, FallbackRegion\"" - set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.local.ini" "GridService" "Region_$gridname" "\"DefaultRegion, FallbackRegion\"" - - log "${COLOR_OK}Welcome_Area.ini Konfiguration abgeschlossen für $gridname${COLOR_RESET}" - blankline -} - -function moneyserveriniconfig() { - # 30.04.2025 - local ip="$1" - gridname="$2" - - # Gridname bereinigen - gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') - - # Zugangsdaten aus UserInfo.ini laden - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - local db_user db_pass - db_user=$(grep -oP '^DB_Benutzername\s*=\s*\K\S+' "$ini_file") - db_pass=$(grep -oP '^DB_Passwort\s*=\s*\K\S+' "$ini_file") - - # Falls keine Benutzer- und Passwortwerte gelesen wurden, abbrechen - if [[ -z "$db_user" || -z "$db_pass" ]]; then - log "${COLOR_BAD}Fehler: DB_Benutzername oder DB_Passwort fehlen in UserInfo.ini${COLOR_RESET}" - return 1 - fi - - local dir="$SCRIPT_DIR/robust/bin" - local file="$dir/MoneyServer.ini" - - # Sicherstellen, dass die Vorlage existiert - if [[ ! -f "$file.example" ]]; then - log "${COLOR_BAD}FEHLER: Konfigurationsvorlage '$file.example' fehlt!${COLOR_RESET}" >&2 - exit 1 - fi - - # Kopieren der Vorlage - cp "$file.example" "$file" || { - log "${COLOR_BAD}FEHLER: Konnte '$file' nicht erstellen${COLOR_RESET}" >&2 - exit 1 - } - - # [Startup] - set_ini_key "$file" "Startup" "PIDFile" "\"/tmp/MoneyServer.exe.pid\"" - - # [MySql] → Daten aus UserInfo.ini verwenden - set_ini_key "$file" "MySql" "hostname" "\"localhost\"" - set_ini_key "$file" "MySql" "database" "\"robust\"" - set_ini_key "$file" "MySql" "username" "\"$db_user\"" - set_ini_key "$file" "MySql" "password" "\"$db_pass\"" - set_ini_key "$file" "MySql" "pooling" "\"true\"" - set_ini_key "$file" "MySql" "port" "\"3306\"" - set_ini_key "$file" "MySql" "MaxConnection" "\"25\"" - - # [MoneyServer] - set_ini_key "$file" "MoneyServer" "ServerPort" "\"8008\"" - set_ini_key "$file" "MoneyServer" "CurrencyOnOff" "\"on\"" - set_ini_key "$file" "MoneyServer" "CurrencyMaximum" "\"20000\"" - set_ini_key "$file" "MoneyServer" "MoneyServerIPaddress" "\"http://$ip:8008\"" - set_ini_key "$file" "MoneyServer" "DefaultBalance" "\"1000\"" - - # [Certificate] - set_ini_key "$file" "Certificate" "CheckClientCert" "\"false\"" - set_ini_key "$file" "Certificate" "CheckServerCert" "\"false\"" - - log "${COLOR_OK}MoneyServer.ini Konfiguration abgeschlossen${COLOR_RESET}" - blankline -} - - -# Konfiguriert OpenSim.ini für alle sim1 bis sim99-Verzeichnisse -function opensiminiconfig() { - # 24.04.2025 - local ip="$1" - local gridname="$2" - local base_port=9010 - local sim_counter=1 - - # Gridname bereinigen - gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') - - # Iteration über alle sim1 bis sim99 Verzeichnisse - for i in $(seq 1 99); do - sim_dir="$SCRIPT_DIR/sim$i" - if [[ -d "$sim_dir/bin" ]]; then - local dir="$sim_dir/bin" - local file="$dir/OpenSim.ini" - - if [[ ! -f "$file.example" ]]; then - echo "FEHLER: Konfigurationsvorlage '$file.example' fehlt!" >&2 - echo "Das Programm benötigt diese Datei zum Starten." >&2 - exit 1 # Programm mit Fehlercode beenden - fi - - # Nur wenn Vorlage existiert: Kopieren - cp "$file.example" "$file" || { - echo "FEHLER: Konnte '$file' nicht erstellen" >&2 - exit 1 - } - - sleep 1 - - log "${COLOR_INFO}Konfiguriere OpenSim.ini in $dir${COLOR_RESET}" - - # Portberechnung pro Instanz - local public_port=$((base_port + (sim_counter - 1) * 100)) - - # Werte setzen - # [Const] - set_ini_key "$file" "Const" "BaseHostname" "$ip" - set_ini_key "$file" "Const" "PublicPort" "8002" - - # [Startup] - #uncomment_ini_section_line "$file" "Startup" "PIDFile" - set_ini_key "$file" "Startup" "PIDFile" "\"/tmp/OpenSim.$i.exe.pid\"" - - # [Estates] - #set_ini_key "$file" "Estates" "DefaultEstateName" "$gridname Estate" - #set_ini_key "$file" "Estates" "DefaultEstateOwnerName" "$VORNAME $NACHNAME" - - # [Network] - # http_listener_port = 9010 - uncomment_ini_section_line "$file" "Network" "http_listener_port" - set_ini_key "$file" "Network" "http_listener_port" "$public_port" - - # [SimulatorFeatures] - uncomment_ini_line "$file" "SearchServerURI" - - # [ClientStack.LindenUDP] Begrenzt die Viewer damit sie die Server leistung nicht kippen können. - set_ini_key "$file" "ClientStack.LindenUDP" "DisableFacelights" "true" - # 10.000.000 bps = 10 Mbit/s pro Client gute Einstellung ist "350.000" bis "500.000" - set_ini_key "$file" "ClientStack.LindenUDP" "client_throttle_max_bps" "350000" - # 10.000.000 bps = 10 Mbit/s pro Region "70.000.000" gute Einstellung ist "70.000.000" bis "1.000.000.000" - set_ini_key "$file" "ClientStack.LindenUDP" "scene_throttle_max_bps" "70000000" - - # [SimulatorFeatures] - set_ini_key "$file" "SimulatorFeatures" "SearchServerURI" "\${Const|BaseURL}:\${Const|PublicPort}" - set_ini_key "$file" "SimulatorFeatures" "DestinationGuideURI" "\${Const|BaseURL}:\${Const|PublicPort}" - - # [Messaging] - set_ini_key "$file" "Messaging" "OfflineMessageModule" "Offline Message Module V2" - set_ini_key "$file" "Messaging" "OfflineMessageURL" "\${Const|PrivURL}:\${Const|PrivatePort}" - set_ini_key "$file" "Messaging" "StorageProvider" "OpenSim.Data.MySQL.dll" - set_ini_key "$file" "Messaging" "MuteListModule" "MuteListModule" - set_ini_key "$file" "Messaging" "ForwardOfflineGroupMessages" "true" - - # [Materials] - set_ini_key "$file" "Materials" "MaxMaterialsPerTransaction" "250" - - # [DataSnapshot] - set_ini_key "$file" "DataSnapshot" "gridname" "$gridname" - - # [Economy] - set_ini_key "$file" "Economy" "SellEnabled" "true" - set_ini_key "$file" "Economy" "EconomyModule" "DTLNSLMoneyModule" - set_ini_key "$file" "Economy" "CurrencyServer" "\${Const|BaseURL}:8008/" - set_ini_key "$file" "Economy" "UserServer" "\${Const|BaseURL}:8002/" - set_ini_key "$file" "Economy" "CheckServerCert" "false" - set_ini_key "$file" "Economy" "PriceUpload" "0" - set_ini_key "$file" "Economy" "MeshModelUploadCostFactor" "1.0" - set_ini_key "$file" "Economy" "MeshModelUploadTextureCostFactor" "1.0" - set_ini_key "$file" "Economy" "MeshModelMinCostFactor" "1.0" - set_ini_key "$file" "Economy" "CheckServerCert" "false" - set_ini_key "$file" "Economy" "PriceUpload" "0" - set_ini_key "$file" "Economy" "MeshModelUploadCostFactor" "1.0" - set_ini_key "$file" "Economy" "MeshModelUploadTextureCostFactor" "1.0" - set_ini_key "$file" "Economy" "MeshModelMinCostFactor" "1.0" - set_ini_key "$file" "Economy" "PriceGroupCreate" "0" - set_ini_key "$file" "Economy" "ObjectCount" "0" - set_ini_key "$file" "Economy" "PriceEnergyUnit" "0" - set_ini_key "$file" "Economy" "PriceObjectClaim" "0" - set_ini_key "$file" "Economy" "PricePublicObjectDecay" "0" - set_ini_key "$file" "Economy" "PricePublicObjectDelete" "0" - set_ini_key "$file" "Economy" "PriceParcelClaim" "0" - set_ini_key "$file" "Economy" "PriceParcelClaimFactor" "1" - set_ini_key "$file" "Economy" "PriceRentLight" "0" - set_ini_key "$file" "Economy" "TeleportMinPrice" "0" - set_ini_key "$file" "Economy" "TeleportPriceExponent" "2" - set_ini_key "$file" "Economy" "EnergyEfficiency" "1" - set_ini_key "$file" "Economy" "PriceObjectRent" "0" - set_ini_key "$file" "Economy" "PriceObjectScaleFactor" "10" - set_ini_key "$file" "Economy" "PriceParcelRent" "0" - - # [Groups] - set_ini_key "$file" "Groups" "Enabled" "true" - set_ini_key "$file" "Groups" "LevelGroupCreate" "0" - set_ini_key "$file" "Groups" "Module" "\"Groups Module V2\"" - set_ini_key "$file" "Groups" "StorageProvider" "OpenSim.Data.MySQL.dll" - set_ini_key "$file" "Groups" "ServicesConnectorModule" "\"Groups HG Service Connector\"" - set_ini_key "$file" "Groups" "LocalService" "remote" - set_ini_key "$file" "Groups" "GroupsServerURI" "\${Const|BaseURL}:\${Const|PrivatePort}" - set_ini_key "$file" "Groups" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - set_ini_key "$file" "Groups" "MessagingEnabled" "true" - set_ini_key "$file" "Groups" "MessagingModule" "\"Groups Messaging Module V2\"" - set_ini_key "$file" "Groups" "NoticesEnabled" "true" - set_ini_key "$file" "Groups" "MessageOnlineUsersOnly" "true" - set_ini_key "$file" "Groups" "XmlRpcServiceReadKey" "1234" - set_ini_key "$file" "Groups" "XmlRpcServiceWriteKey" "1234" - - # [InterestManagement] - set_ini_key "$file" "InterestManagement" "UpdatePrioritizationScheme" "BestAvatarResponsiveness" - set_ini_key "$file" "InterestManagement" "ObjectsCullingByDistance" "true" - - # [MediaOnAPrim] - set_ini_key "$file" "MediaOnAPrim" "Enabled" "true" - - # [NPC] - set_ini_key "$file" "NPC" "Enabled" "true" - set_ini_key "$file" "NPC" "MaxNumberNPCsPerScene" "40" - set_ini_key "$file" "NPC" "AllowNotOwned" "true" - set_ini_key "$file" "NPC" "AllowSenseAsAvatar" "true" - set_ini_key "$file" "NPC" "AllowCloneOtherAvatars" "true" - set_ini_key "$file" "NPC" "NoNPCGroup" "true" - - # [Terrain] - set_ini_key "$file" "Terrain" "InitialTerrain" "\"flat\"" - - # [LandManagement] - set_ini_key "$file" "LandManagement" "ShowParcelBansLines" "true" - - # [UserProfiles] - set_ini_key "$file" "UserProfiles" "ProfileServiceURL" "\${Const|BaseURL}:\${Const|PublicPort}" - set_ini_key "$file" "UserProfiles" "AllowUserProfileWebURLs" "true" - - # [XBakes] - set_ini_key "$file" "XBakes" "URL" "\${Const|PrivURL}:\${Const|PrivatePort}" - - # [Architecture] - set_ini_key "$file" "Architecture" "Include-Architecture" "\"config-include/GridHypergrid.ini\"" - - ((sim_counter++)) - sleep 1 - fi - done - - log "${COLOR_OK}${sim_counter} Simulationen konfiguriert.${COLOR_RESET}" - blankline -} - -# Konfiguration von Robust.HG.ini im robust/bin Verzeichnis -function robusthginiconfig() { - # 23.04.2025 - local ip="$1" - local gridname="$2" - local dir="$SCRIPT_DIR/robust/bin" - local file="$dir/Robust.HG.ini" - webverzeichnis="oswebinterface" - - # Gridname bereinigen - gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') - - if [[ ! -f "$file.example" ]]; then - echo "FEHLER: Konfigurationsvorlage '$file.example' fehlt!" >&2 - echo "Das Programm benötigt diese Datei zum Starten." >&2 - exit 1 # Programm mit Fehlercode beenden - fi - - # Nur wenn Vorlage existiert: Kopieren - cp "$file.example" "$file" || { - echo "FEHLER: Konnte '$file' nicht erstellen" >&2 - exit 1 - } - - # [Const] - set_ini_key "$file" "Const" "BaseHostname" "$ip" - - # [Startup] - # PID-Dateien gehören grundsätzlich in /tmp warum: tmp Wird beim Neustart automatisch geleert. Keine Berechtigungsprobleme (normalerweise schreibbar für alle). - # Standard-PID-Datei: /tmp/Robust.exe.pid - uncomment_ini_line "$file" "PIDFile" - - # [ServiceList] - uncomment_ini_line "$file" "OfflineIMServiceConnector" - uncomment_ini_line "$file" "GroupsServiceConnector" - uncomment_ini_line "$file" "BakedTextureService" - uncomment_ini_line "$file" "UserProfilesServiceConnector" - uncomment_ini_line "$file" "HGGroupsServiceConnector" - - # [Network] - - # [Hypergrid] - uncomment_ini_line "$file" "HomeURI" - uncomment_ini_line "$file" "GatekeeperURI" - - # [DatabaseService] wird in database_set_iniconfig eingetragen. - - # [GridService] für osWebinterface - uncomment_ini_line "$file" "MapTileDirectory" - - # [LoginService] für osWebinterface etc. "\${Const|BaseURL}:\${Const|PublicPort}" - uncomment_ini_line "$file" "SearchURL" - uncomment_ini_line "$file" "DestinationGuide" - uncomment_ini_line "$file" "AvatarPicker" - uncomment_ini_line "$file" "MinLoginLevel" - uncomment_ini_line "$file" "Currency" - uncomment_ini_line "$file" "ClassifiedFee" - - set_ini_key "$file" "LoginService" "WelcomeMessage" "\"Willkommen im $gridname!\"" - set_ini_key "$file" "LoginService" "MapTileURL" "\"\${Const|BaseURL}:\${Const|PublicPort}/\"" - set_ini_key "$file" "LoginService" "SearchURL" "\"\${Const|BaseURL}:\${Const|PublicPort}/$webverzeichnis/searchservice.php\"" - set_ini_key "$file" "LoginService" "DestinationGuide" "\"\${Const|BaseURL}/$webverzeichnis/guide.php\"" - set_ini_key "$file" "LoginService" "AvatarPicker" "\"\${Const|BaseURL}/$webverzeichnis/avatarpicker.php\"" - set_ini_key "$file" "LoginService" "Currency" "\"OS$\"" - set_ini_key "$file" "LoginService" "DSTZone" "\"local\"" - - # [GatekeeperService] - uncomment_ini_line "$file" "ExternalName" - - # [GridInfoService] - set_ini_key "$file" "GridInfoService" "gridname" "\"$gridname\"" - set_ini_key "$file" "GridInfoService" "gridnick" "\"$gridname\"" - set_ini_key "$file" "GridInfoService" "welcome" "\"\${Const|BaseURL}/$webverzeichnis/welcomesplashpage.php\"" - set_ini_key "$file" "GridInfoService" "economy" "\"\${Const|BaseURL}:8008/\"" - set_ini_key "$file" "GridInfoService" "about" "\"\${Const|BaseURL}/$webverzeichnis/aboutinformation.php\"" - set_ini_key "$file" "GridInfoService" "register" "\"\${Const|BaseURL}/$webverzeichnis/createavatar.php\"" - set_ini_key "$file" "GridInfoService" "help" "\"\${Const|BaseURL}/$webverzeichnis/help.php\"" - set_ini_key "$file" "GridInfoService" "password" "\"\${Const|BaseURL}/$webverzeichnis/passwordreset.php\"" - set_ini_key "$file" "GridInfoService" "GridStatusRSS" "\"\${Const|BaseURL}/$webverzeichnis/gridstatusrss.php\"" - - # [UserAgentService] - uncomment_ini_line "$file" "LevelOutsideContacts" - uncomment_ini_line "$file" "ShowUserDetailsInHGProfile" - - # [Messaging] - set_ini_key "$file" "Messaging" "MaxOfflineIMs" "250" - - # [Groups] - set_ini_key "$file" "Groups" "MaxAgentGroups" "100" - - log "${COLOR_OK}Robust.HG.ini konfiguriert.${COLOR_RESET}" - blankline -} - -# Funktion zur Generierung eines 16-stelligen Passworts -function genPass() { - tr -dc 'A-Za-z0-9' "$php_config_file" < -EOF - - # config.example.php in config.php umbenennen, falls es existiert - if [[ -f "$config_example_file" ]]; then - #mv "$config_example_file" "$config_file" - cp "$config_example_file" "$config_file" - log "${SYM_OK} ${COLOR_ACTION}Konfigurationsdatei umbenannt: ${COLOR_DIR}$config_file${COLOR_RESET}" - - # Konfiguration in config.php einfügen - if [[ -f "$config_file" ]]; then - # BASE_URL ersetzen oder hinzufügen - if grep -q "define('BASE_URL'" "$config_file"; then - sed -i "s|define('BASE_URL'.*|define('BASE_URL', 'http://${server_ip}');|" "$config_file" - else - sed -i "/&2 - log "${COLOR_BAD}Das Programm benötigt diese Datei zum Starten.${COLOR_RESET}" >&2 - exit 1 - fi - - # Vorlage nach Robust.local.ini kopieren - cp "$source_file" "$target_file" || { - log "${COLOR_BAD}FEHLER: Konnte '$target_file' nicht erstellen${COLOR_RESET}" >&2 - exit 1 - } - - # [Const] - set_ini_key "$target_file" "Const" "BaseHostname" "$ip" - - # [ServiceList] - uncomment_ini_line "$target_file" "OfflineIMServiceConnector" - uncomment_ini_line "$target_file" "GroupsServiceConnector" - uncomment_ini_line "$target_file" "BakedTextureService" - uncomment_ini_line "$target_file" "UserProfilesServiceConnector" - - # [LoginService] Konfiguration - set_ini_key "$target_file" "LoginService" "Currency" "\"OS$\"" - set_ini_key "$target_file" "LoginService" "WelcomeMessage" "\"Willkommen im $gridname!\"" - set_ini_key "$target_file" "LoginService" "MapTileURL" "\"\${Const|BaseURL}:\${Const|PublicPort}/\"" - set_ini_key "$target_file" "LoginService" "SearchURL" "\"\${Const|BaseURL}/searchservice.php\"" - set_ini_key "$target_file" "LoginService" "DestinationGuide" "\"\${Const|BaseURL}/guide.php\"" - set_ini_key "$target_file" "LoginService" "AvatarPicker" "\"\${Const|BaseURL}/avatarpicker.php\"" - - # [GridInfoService] - set_ini_key "$target_file" "GridInfoService" "gridname" "\"$gridname\"" - set_ini_key "$target_file" "GridInfoService" "gridnick" "\"$gridname\"" - set_ini_key "$target_file" "GridInfoService" "welcome" "\"\${Const|BaseURL}/welcome\"" - set_ini_key "$target_file" "GridInfoService" "economy" "\"\${Const|BaseURL}:8008/\"" - set_ini_key "$target_file" "GridInfoService" "about" "\"\${Const|BaseURL}/about\"" - set_ini_key "$target_file" "GridInfoService" "register" "\"\${Const|BaseURL}/register\"" - set_ini_key "$target_file" "GridInfoService" "help" "\"\${Const|BaseURL}/help\"" - set_ini_key "$target_file" "GridInfoService" "password" "\"\${Const|BaseURL}/password\"" - set_ini_key "$target_file" "GridInfoService" "GridStatusRSS" "\"\${Const|BaseURL}:\${Const|PublicPort}/GridStatusRSS\"" - - log "${COLOR_OK}Robust.local.ini erfolgreich konfiguriert.${COLOR_RESET}" - blankline -} - -# Konfiguriert die FlotsamCache.ini Dateien -# - Erstellt die Dateien in den bin/config-include Ordner der Simulatoren -# - Setzt Optimierte Parameter den FlotsamCache.ini Dateien -function flotsaminiconfig() { - # 25.04.2025 - for i in $(seq 1 99); do - local config_dir="$SCRIPT_DIR/sim$i/bin/config-include" - local file="$config_dir/FlotsamCache.ini" - - if [[ -d "$config_dir" ]]; then - log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" - mkdir -p "$config_dir" - - # Datei erstellen - #touch "$welcome_ini" - #touch "$welcome_ini" || echo "" > "$welcome_ini" - touch "$file" 2>/dev/null || echo "" > "$file" - - # 2. Sektion hinzufügen - add_ini_section "$file" "AssetCache" - - sleep 1 - - # 3. Alle Key-Value Paare setzen - set_ini_key "$file" "AssetCache" "CacheDirectory" "./assetcache" - set_ini_key "$file" "AssetCache" "LogLevel" "0" - set_ini_key "$file" "AssetCache" "HitRateDisplay" "100" - set_ini_key "$file" "AssetCache" "MemoryCacheEnabled" "false" - set_ini_key "$file" "AssetCache" "UpdateFileTimeOnCacheHit" "false" - set_ini_key "$file" "AssetCache" "NegativeCacheEnabled" "true" - set_ini_key "$file" "AssetCache" "NegativeCacheTimeout" "120" - set_ini_key "$file" "AssetCache" "NegativeCacheSliding" "false" - set_ini_key "$file" "AssetCache" "FileCacheEnabled" "true" - set_ini_key "$file" "AssetCache" "MemoryCacheTimeout" ".016" - set_ini_key "$file" "AssetCache" "FileCacheTimeout" "48" - set_ini_key "$file" "AssetCache" "FileCleanupTimer" "1.0" - - log "${COLOR_OK}→ FlotsamCache.ini neu geschrieben für sim$i${COLOR_RESET}" - fi - done - - log "${COLOR_OK}FlotsamCache.ini konfiguriert.${COLOR_RESET}" - blankline -} - -function gridcommoniniconfig() { - local ip="$1" - local gridname="$2" - - # Gridname bereinigen - gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') - - for i in $(seq 1 99); do - local config_dir="$SCRIPT_DIR/sim$i/bin/config-include" - local file="$config_dir/GridCommon.ini" - local example_file="$config_dir/GridCommon.ini.example" - - # Strikte Prüfung - Abbruch wenn etwas fehlt - if [[ ! -d "$config_dir" ]] || [[ ! -f "$example_file" ]]; then - return 1 - fi - - # Vorlage kopieren - cp "$example_file" "$file" || return 1 - - sleep 1 - - # [Const] - add_ini_before_section "$file" "Const" "DatabaseService" - set_ini_key "$file" "Const" "BaseHostname" "\"$ip\"" - set_ini_key "$file" "Const" "BaseURL" "\"http://\${Const|BaseHostname}\"" - set_ini_key "$file" "Const" "PublicPort" "\"8002\"" - set_ini_key "$file" "Const" "PrivatePort" "\"8003\"" - - # [DatabaseService] wird in database_set_iniconfig eingetragen. - clear_ini_section "$file" "DatabaseService" - set_ini_key "$file" "DatabaseService" "StorageProvider" "\"OpenSim.Data.MySQL.dll\"" - - # [Hypergrid] - set_ini_key "$file" "Hypergrid" "GatekeeperURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - set_ini_key "$file" "Hypergrid" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - - # [Modules] - set_ini_key "$file" "Modules" "AssetCaching" "\"FlotsamAssetCache\"" - set_ini_key "$file" "Modules" "Include-FlotsamCache" "\"config-include/FlotsamCache.ini\"" - set_ini_key "$file" "Modules" "AuthorizationServices" "\"RemoteAuthorizationServicesConnector\"" - - # [AssetService] - set_ini_key "$file" "AssetService" "DefaultAssetLoader" "\"OpenSim.Framework.AssetLoader.Filesystem.dll\"" - set_ini_key "$file" "AssetService" "AssetLoaderArgs" "\"assets/AssetSets.xml\"" - set_ini_key "$file" "AssetService" "AssetServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [InventoryService] - set_ini_key "$file" "InventoryService" "InventoryServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [GridInfo] - set_ini_key "$file" "GridInfo" "GridInfoURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - - # [GridService] - set_ini_key "$file" "GridService" "GridServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - set_ini_key "$file" "GridService" "MapTileDirectory" "\"./maptiles\"" - set_ini_key "$file" "GridService" "Gatekeeper" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - - # [EstateDataStore] - set_ini_key "$file" "EstateService" "EstateServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [Messaging] - set_ini_key "$file" "Messaging" "Gatekeeper" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - - # [AvatarService] - set_ini_key "$file" "AvatarService" "AvatarServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [AgentPreferencesService] - set_ini_key "$file" "AgentPreferencesService" "AgentPreferencesServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [PresenceService] - set_ini_key "$file" "PresenceService" "PresenceServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [UserAccountService] - set_ini_key "$file" "UserAccountService" "UserAccountServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [GridUserService] - set_ini_key "$file" "GridUserService" "GridUserServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [AuthenticationService] - set_ini_key "$file" "AuthenticationService" "AuthenticationServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [FriendsService] - set_ini_key "$file" "FriendsService" "FriendsServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [HGInventoryAccessModule] - set_ini_key "$file" "HGInventoryAccessModule" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - set_ini_key "$file" "HGInventoryAccessModule" "Gatekeeper" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - - # [HGAssetService] - set_ini_key "$file" "HGAssetService" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" - - # [HGFriendsModule] - set_ini_key "$file" "HGFriendsModule" "LevelHGFriends" "0" - - # [MapImageService] - set_ini_key "$file" "MapImageService" "MapImageServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - # [AuthorizationService] - set_ini_key "$file" "AuthorizationService" "AuthorizationServerURI" "\"\${Const|PrivURL}/hgauth.php\"" - - # [MuteListService] - set_ini_key "$file" "MuteListService" "MuteListServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" - - log "${COLOR_OK}✓ sim$i: GridCommon.ini erfolgreich${COLOR_RESET}" - - sleep 1 - done - - log "${COLOR_OK}GridCommon.ini konfiguriert.${COLOR_RESET}" - blankline -} - -function osslenableiniconfig() { - # 25.04.2025 - for i in $(seq 1 99); do - local config_dir="$SCRIPT_DIR/sim$i/bin/config-include" - local file="$config_dir/osslEnable.ini" - - if [[ -d "$config_dir" ]]; then - log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" - mkdir -p "$config_dir" - - touch "$file" 2>/dev/null || echo "" > "$file" - - # Sektion hinzufügen - add_ini_section "$file" "OSSL" - - sleep 1 - - # Basis-Key-Value Paare - set_ini_key "$file" "OSSL" "AllowOSFunctions" "true" - set_ini_key "$file" "OSSL" "AllowMODFunctions" "true" - set_ini_key "$file" "OSSL" "AllowLightShareFunctions" "true" - set_ini_key "$file" "OSSL" "PermissionErrorToOwner" "false" - set_ini_key "$file" "OSSL" "OSFunctionThreatLevel" "VeryHigh" - set_ini_key "$file" "OSSL" "osslParcelO" "\"PARCEL_OWNER,\"" - set_ini_key "$file" "OSSL" "osslParcelOG" "\"PARCEL_GROUP_MEMBER,PARCEL_OWNER,\"" - set_ini_key "$file" "OSSL" "osslNPC" "\${OSSL|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER" - - # Alle Allow_* Einträge - set_ini_key "$file" "OSSL" "Allow_osGetAgents" "true" - set_ini_key "$file" "OSSL" "Allow_osGetAvatarList" "true" - set_ini_key "$file" "OSSL" "Allow_osGetNPCList" "true" - set_ini_key "$file" "OSSL" "Allow_osNpcGetOwner" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osSetSunParam" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osTeleportOwner" "true" - set_ini_key "$file" "OSSL" "Allow_osSetEstateSunSettings" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetRegionSunSettings" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osEjectFromGroup" "true" - set_ini_key "$file" "OSSL" "Allow_osForceBreakAllLinks" "true" - set_ini_key "$file" "OSSL" "Allow_osForceBreakLink" "true" - set_ini_key "$file" "OSSL" "Allow_osGetWindParam" "true" - set_ini_key "$file" "OSSL" "Allow_osInviteToGroup" "true" - set_ini_key "$file" "OSSL" "Allow_osReplaceString" "true" - set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureData" "true" - set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureDataFace" "true" - set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureDataBlend" "true" - set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureDataBlendFace" "true" - set_ini_key "$file" "OSSL" "Allow_osSetParcelMediaURL" "true" - set_ini_key "$file" "OSSL" "Allow_osSetParcelMusicURL" "true" - set_ini_key "$file" "OSSL" "Allow_osSetParcelSIPAddress" "true" - set_ini_key "$file" "OSSL" "Allow_osSetPrimFloatOnWater" "true" - set_ini_key "$file" "OSSL" "Allow_osSetWindParam" "true" - set_ini_key "$file" "OSSL" "Allow_osTerrainFlush" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osAvatarName2Key" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osFormatString" "true" - set_ini_key "$file" "OSSL" "Allow_osKey2Name" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osListenRegex" "true" - set_ini_key "$file" "OSSL" "Allow_osLoadedCreationDate" "true" - set_ini_key "$file" "OSSL" "Allow_osLoadedCreationID" "true" - set_ini_key "$file" "OSSL" "Allow_osLoadedCreationTime" "true" - set_ini_key "$file" "OSSL" "Allow_osMessageObject" "true" - set_ini_key "$file" "OSSL" "Allow_osRegexIsMatch" "true" - set_ini_key "$file" "OSSL" "Allow_osGetAvatarHomeURI" "true" - set_ini_key "$file" "OSSL" "Allow_osNpcSetProfileAbout" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcSetProfileImage" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osDie" "true" - set_ini_key "$file" "OSSL" "Allow_osDetectedCountry" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osDropAttachment" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osDropAttachmentAt" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetAgentCountry" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetGridCustom" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetGridGatekeeperURI" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetGridHomeURI" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetGridLoginURI" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetGridName" "true" - set_ini_key "$file" "OSSL" "Allow_osGetGridNick" "true" - set_ini_key "$file" "OSSL" "Allow_osGetNumberOfAttachments" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetRegionStats" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetSimulatorMemory" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetSimulatorMemoryKB" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osMessageAttachments" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osReplaceAgentEnvironment" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetSpeed" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetOwnerSpeed" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osRequestURL" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osRequestSecureURL" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osCauseDamage" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osCauseHealing" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetHealth" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetHealRate" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osForceAttachToAvatar" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osForceAttachToAvatarFromInventory" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osForceCreateLink" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osForceDropAttachment" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osForceDropAttachmentAt" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetLinkPrimitiveParams" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetPhysicsEngineType" "true" - set_ini_key "$file" "OSSL" "Allow_osGetRegionMapTexture" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetScriptEngineName" "true" - set_ini_key "$file" "OSSL" "Allow_osGetSimulatorVersion" "true" - set_ini_key "$file" "OSSL" "Allow_osMakeNotecard" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osMatchString" "true" - set_ini_key "$file" "OSSL" "Allow_osNpcCreate" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcGetPos" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcGetRot" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcLoadAppearance" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcMoveTo" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcMoveToTarget" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcPlayAnimation" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcRemove" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcSaveAppearance" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcSay" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcSayTo" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcSetRot" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcShout" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcSit" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcStand" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcStopAnimation" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcStopMoveToTarget" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcTouch" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osNpcWhisper" "\${OSSL|osslNPC}" - set_ini_key "$file" "OSSL" "Allow_osOwnerSaveAppearance" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osParcelJoin" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osParcelSubdivide" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osRegionRestart" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osRegionNotice" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetProjectionParams" "true" - set_ini_key "$file" "OSSL" "Allow_osSetRegionWaterHeight" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetTerrainHeight" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetTerrainTexture" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetTerrainTextureHeight" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osAgentSaveAppearance" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osAvatarPlayAnimation" "true" - set_ini_key "$file" "OSSL" "Allow_osAvatarStopAnimation" "true" - set_ini_key "$file" "OSSL" "Allow_osForceAttachToOtherAvatarFromInventory" "true" - set_ini_key "$file" "OSSL" "Allow_osForceDetachFromAvatar" "true" - set_ini_key "$file" "OSSL" "Allow_osForceOtherSit" "true" - set_ini_key "$file" "OSSL" "Allow_osGetNotecard" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetNotecardLine" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osGetNumberOfNotecardLines" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureURL" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureURLBlend" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureURLBlendFace" "ESTATE_MANAGER,ESTATE_OWNER" - set_ini_key "$file" "OSSL" "Allow_osSetRot" "true" - set_ini_key "$file" "OSSL" "Allow_osSetParcelDetails" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" - - log "${COLOR_OK}→ osslEnable.ini neu geschrieben für sim$i${COLOR_RESET}" - - sleep 1 - fi - done - - log "${COLOR_OK}osslEnable.ini konfiguriert.${COLOR_RESET}" - blankline -} - -# Erstellt eine StandaloneCommon.ini -function standalonecommoniniconfig() { - local ip="$1" - local gridname="$2" - - # Gridname bereinigen - gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') - - local config_dir="$SCRIPT_DIR/opensim/bin/config-include" - local file="$config_dir/StandaloneCommon.ini" - local example_file="$config_dir/StandaloneCommon.ini.example" - - log "${COLOR_FILE}Erstelle StandaloneCommon.ini in opensim/bin${COLOR_RESET}" - mkdir -p "$config_dir" - - # Datei erstellen - #touch "$welcome_ini" - #touch "$welcome_ini" || echo "" > "$welcome_ini" - touch "$file" 2>/dev/null || echo "" > "$file" - - # 2. Const-Sektion hinzufügen - add_ini_section "$file" "Const" - - # 3. Werte für Const-Sektion setzen - set_ini_key "$file" "Const" "BaseHostname" "\"$ip\"" - set_ini_key "$file" "Const" "BaseURL" "http://\${Const|BaseHostname}" - set_ini_key "$file" "Const" "PublicPort" "\"9000\"" - set_ini_key "$file" "Const" "PrivatePort" "\"9003\"" - set_ini_key "$file" "Const" "PrivURL" "http://\${Const|BaseHostname}:\${Const|PrivatePort}" - - # 4. Hypergrid- und GridInfo-Werte setzen - set_ini_key "$file" "Hypergrid" "GatekeeperURI" "\"http://$ip:8002\"" - set_ini_key "$file" "Hypergrid" "HomeURI" "\"http://$ip:8002\"" - set_ini_key "$file" "GridInfoService" "GridName" "\"$gridname\"" - set_ini_key "$file" "GridInfoService" "GridLoginURI" "\"http://$ip:8002\"" - - log "${COLOR_OK}→ StandaloneCommon.ini erfolgreich erstellt${COLOR_RESET}" - blankline -} - -# Random Position (mit Simulator-Offset) -function random_position() { - local center_x=$1 - local center_y=$2 - local n=$3 # Region-Nummer - local sim_offset=$4 # Simulator-Offset - - # Zufallsposition mit Simulator-basiertem Seed - RANDOM=$(( n + sim_offset * 1000 )) # Reproduzierbarer Zufall - local offset_x=$(( (RANDOM % 200) - 100 )) # Kleinerer Bereich (±100 Einheiten) - local offset_y=$(( (RANDOM % 200) - 100 )) - - echo "$((center_x + offset_x + sim_offset * 10)),$((center_y + offset_y + sim_offset * 10))" -} - -# Fibonacci Grid (mit Simulator-Offset) -function fibonacci_grid_position() { - local center_x=$1 - local center_y=$2 - local n=$3 - local sim_offset=$4 - - local a=0; local b=1 - for ((i=0; i&2 - return 1 - fi - - log "${SYM_OK} ${COLOR_ACTION}Sie haben ${COLOR_OK}$regions_per_sim${COLOR_ACTION} Regionen pro Simulator gewählt.${COLOR_RESET}" - - system_ip=$(hostname -I | awk '{print $1}') - - log "\n${SYM_SERVER}${COLOR_HEADING} Starte Regionserstellung...${COLOR_RESET}" - - # Simulatoren durchlaufen (beginnt bei 2 um sim1 für Welcome-Region freizuhalten) - for ((sim_num=2; sim_num<=999; sim_num++)); do - sim_dir="${SCRIPT_DIR}/sim${sim_num}/bin/Regions" - - if [[ -d "$sim_dir" ]]; then - log "${SYM_FOLDER}${COLOR_SERVER} Simulator ${sim_num}:${COLOR_RESET} ${COLOR_ACTION}Erstelle ${regions_per_sim} Region(en)${COLOR_RESET}" >&2 - - # Bestehende Ports erfassen - local existing_port_count=0 - if [[ -d "$sim_dir" ]]; then - for existing_file in "$sim_dir"/*.ini; do - if [[ -f "$existing_file" ]]; then - existing_port=$(grep -oP 'InternalPort\s*=\s*\K\d+' "$existing_file" 2>/dev/null) - if [[ -n "$existing_port" ]]; then - used_ports["$existing_port"]=1 - ((existing_port_count++)) - fi - fi - done - fi - - # Regionen erstellen Random Fibonacci Raute Square Hexagon Spiral Checkerboard - for ((region_num=1; region_num<=regions_per_sim; region_num++)); do - # Position berechnen (mit Kollisionsprüfung) - local attempts=0 - local max_attempts=100 - - while true; do - # Hier wird die entsprechende externe Funktion aufgerufen - if [[ "$position" == "Random" ]]; then - # Zufalls-Gitter: - location=$(random_position "$center_x" "$center_y" "$region_num" "$sim_num") - elif [[ "$position" == "Fibonacci" ]]; then - # Fibonacci-Gitter: - location=$(fibonacci_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") - elif [[ "$position" == "Raute" ]]; then - # Rauten-Gitter: - location=$(diamond_position "$center_x" "$center_y" "$region_num" "$sim_num") - elif [[ "$position" == "Square" ]]; then - # Square-Gitter: - location=$(square_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") - elif [[ "$position" == "Hexagon" ]]; then - # Hexagon-Gitter: - location=$(hex_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") - elif [[ "$position" == "Spiral" ]]; then - # Spirale-Gitter: - location=$(spiral_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") - else - # Fallback zu Random bei ungültiger Eingabe - location=$(random_position "$center_x" "$center_y" "$region_num" "$sim_num") - fi - - if [[ -z "${used_locations[$location]}" ]]; then - used_locations[$location]=1 - break - fi - - attempts=$((attempts + 1)) - if (( attempts >= max_attempts )); then - log "${SYM_BAD} ${COLOR_WARNING}Fehler: Konnte nach ${max_attempts} Versuchen keine eindeutige Position finden${COLOR_RESET}" >&2 - return 1 - fi - done - - # Eindeutigen Port finden - local port_attempts=0 - local max_port_attempts=100 - local port_base=$((base_port + sim_num * 100)) # 9100, 9200, 9300 usw. - - while true; do - # Port innerhalb des reservierten Blocks (9100-9199 etc.) - port=$((port_base + region_num + existing_port_count)) - - # Sicherstellen, dass wir im Block bleiben - if (( port >= port_base + 100 )); then - log "${SYM_BAD} ${COLOR_WARNING}Fehler: Keine freien Ports mehr im Block ${port_base}-$((port_base+99))${COLOR_RESET}" >&2 - return 1 - fi - - # Prüfen ob Port verfügbar ist - if [[ -z "${used_ports[$port]}" ]] && ! nc -z localhost "$port" 2>/dev/null; then - used_ports["$port"]=1 - break - fi - - ((existing_port_count++)) - ((port_attempts++)) - - if (( port_attempts >= max_port_attempts )); then - log "${SYM_BAD} ${COLOR_WARNING}Fehler: Konnte in Simulator ${sim_num} nach ${max_port_attempts} Versuchen keinen freien Port finden (Block ${port_base}-$((port_base+99))${COLOR_RESET}" >&2 - return 1 - fi - done - - # Neu generierter Name - generate_name - genRegionName="${gennamefirst}${gennamesecond}$((RANDOM % 900 + 100))" - echo "$genRegionName" - region_name=${genRegionName} - - region_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") - - config_file="${sim_dir}/${region_name}.ini" - - # Prüfen ob Region existiert - if [[ -f "$config_file" ]]; then - log "${SYM_WAIT} ${COLOR_WARNING}Überspringe ${COLOR_VALUE}${region_name}${COLOR_RESET}${COLOR_WARNING} - existiert bereits${COLOR_RESET}" >&2 - continue - fi - - touch "$config_file" 2>/dev/null || echo "" > "$config_file" - - # Regionseinstellungen hinzufügen - add_ini_section "$config_file" "$region_name" - - # Regionseinstellungen setzen - set_ini_key "$config_file" "$region_name" "RegionUUID" "$region_uuid" - set_ini_key "$config_file" "$region_name" "Location" "$location" - set_ini_key "$config_file" "$region_name" "SizeX" "256" - set_ini_key "$config_file" "$region_name" "SizeY" "256" - set_ini_key "$config_file" "$region_name" "SizeZ" "256" - set_ini_key "$config_file" "$region_name" "InternalPort" "$port" - set_ini_key "$config_file" "$region_name" "ExternalHostName" "$system_ip" - set_ini_key "$config_file" "$region_name" "MaxPrims" "15000" - set_ini_key "$config_file" "$region_name" "MaxAgents" "40" - set_ini_key "$config_file" "$region_name" "MaptileStaticUUID" "$region_uuid" - set_ini_key "$config_file" "$region_name" "InternalAddress" "0.0.0.0" - set_ini_key "$config_file" "$region_name" "AllowAlternatePorts" "False" - set_ini_key "$config_file" "$region_name" "NonPhysicalPrimMax" "512" - set_ini_key "$config_file" "$region_name" "PhysicalPrimMax" "128" - set_ini_key "$config_file" "$region_name" ";ClampPrimSize" "false" - set_ini_key "$config_file" "$region_name" ";MaxPrimsPerUser" "-1" - set_ini_key "$config_file" "$region_name" ";ScopeID" "$region_uuid" - set_ini_key "$config_file" "$region_name" ";RegionType" "Mainland" - set_ini_key "$config_file" "$region_name" ";RenderMinHeight" "-1" - set_ini_key "$config_file" "$region_name" ";RenderMaxHeight" "100" - set_ini_key "$config_file" "$region_name" ";MapImageModule" "Warp3DImageModule" - set_ini_key "$config_file" "$region_name" ";TextureOnMapTile" "true" - set_ini_key "$config_file" "$region_name" ";DrawPrimOnMapTile" "true" - set_ini_key "$config_file" "$region_name" ";GenerateMaptiles" "true" - set_ini_key "$config_file" "$region_name" ";MaptileRefresh" "0" - set_ini_key "$config_file" "$region_name" ";MaptileStaticFile" "path/to/SomeFile.png" # Bitte verwenden sie nicht den Pfad des OpenSimulators sondern ein externen Pfad! - set_ini_key "$config_file" "$region_name" ";MasterAvatarFirstName" "John" - set_ini_key "$config_file" "$region_name" ";MasterAvatarLastName" "Doe" - set_ini_key "$config_file" "$region_name" ";MasterAvatarSandboxPassword" "passwd" - - log "${SYM_OK} ${COLOR_VALUE}${region_name} ${COLOR_DIR}(${location}, Port ${port})${COLOR_RESET}" >&2 - done - fi - done - - log "${SYM_OK}${COLOR_OK} Regionserstellung abgeschlossen!${COLOR_RESET}" - blankline - return 0 -} - -# Hauptfunktion, fragt Benutzer nach IP & Gridnamen und ruft alle Teilfunktionen auf -function iniconfig() { - # 30.04.2025 - Server-Konfiguration - - echo "Das Arbeitsverzeichnis ist: $SCRIPT_DIR" - - echo "Wie ist Ihre IP oder DNS-Adresse? ($system_ip)" - read -r ip - - # Falls die IP leer bleibt, wird system_ip verwendet - if [[ -z "$ip" ]]; then - ip=$system_ip - fi - - echo "Wie heißt Ihr Grid?" - read -r gridname - - # Falls der Gridname leer bleibt, wird eine generierte Name verwendet - if [[ -z "$gridname" ]]; then - gridname=${genGridName} - fi - - echo "Verwendete IP: $ip" - echo "Gridname: $gridname" - - # **Speicherung der Server-Daten in UserInfo.ini** - local ini_file="${SCRIPT_DIR}/UserInfo.ini" - - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_INFO}Erstelle UserInfo.ini${COLOR_RESET}" - sudo touch "$ini_file" - fi - - log "\n[ServerData]" | sudo tee -a "$ini_file" >/dev/null - echo "Arbeitsverzeichnis = ${SCRIPT_DIR}" | sudo tee -a "$ini_file" >/dev/null - echo "ServerIP = ${ip}" | sudo tee -a "$ini_file" >/dev/null - echo "GridName = ${gridname}" | sudo tee -a "$ini_file" >/dev/null - - log "${SYM_LOG} ${COLOR_LABEL}Serverdaten gespeichert in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" - - #! ${SYM_WARNING} **Wichtige Sicherheitsinformation!** - # Die Datei UserInfo.ini enthält Zugangsdaten. - # Sie **sollte danach unbedingt von eurem Server gelöscht und sicher auf eurem PC gespeichert werden**. - - # Konfigurationsfunktionen für verschiedene Komponenten aufrufen - echo "Starte moneyserveriniconfig ..." - moneyserveriniconfig "$ip" "$gridname" - echo "Starte opensiminiconfig ..." - opensiminiconfig "$ip" "$gridname" - echo "Starte robusthginiconfig ..." - robusthginiconfig "$ip" "$gridname" - echo "Starte robustiniconfig ..." - robustiniconfig "$ip" "$gridname" - echo "Starte gridcommoniniconfig ..." - gridcommoniniconfig "$ip" "$gridname" - echo "Starte standalonecommoniniconfig ..." - standalonecommoniniconfig "$ip" "$gridname" - echo "Starte flotsaminiconfig ..." - flotsaminiconfig "$ip" "$gridname" - echo "Starte osslenableiniconfig ..." - osslenableiniconfig "$ip" "$gridname" - echo "Starte welcomeiniconfig ..." - welcomeiniconfig "$ip" "$gridname" - echo "Starte database_set_iniconfig ..." - database_set_iniconfig - echo "Starte oswebinterfaceconfig ..." - oswebinterfaceconfig - - # Auswahl des Modus Hypergrid oder Geschlossener Grid. - hypergrid "hypergrid" - #hypergrid "closed" -} - - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* XML Konfigurationen für Addon Pakete wie Texturen, Avatare oder Skripte -#?────────────────────────────────────────────────────────────────────────────────────────── - -# shellcheck disable=SC2317 -function verify_xml_section() { - - local file="$1" - local section_name="$2" - - if [ ! -f "$file" ]; then - log "${SYM_BAD} ${COLOR_BAD}Error: File ${COLOR_DIR}${file}${COLOR_BAD} does not exist${COLOR_RESET}" >&2 - return 2 - fi - - if grep -q "
" "$file"; then - log "${SYM_OK} ${COLOR_LABEL}Section ${COLOR_VALUE}'$section_name'${COLOR_LABEL} exists in ${COLOR_DIR}${file}${COLOR_RESET}" - return 0 - else - log "${SYM_BAD} ${COLOR_LABEL}Section ${COLOR_VALUE}'$section_name'${COLOR_LABEL} not found in ${COLOR_DIR}${file}${COLOR_RESET}" - return 1 - fi -} - -# shellcheck disable=SC2317 -function add_xml_section() { - local file="$1" - local section_name="$2" - local content="$3" - local closing_tag="${4:-}" # Standard ist , kann überschrieben werden - - # Verifizieren ob der Abschnitt bereits existiert - if verify_xml_section "$file" "$section_name" >/dev/null; then - return 0 - fi - - # Temporäre Datei für Sicherheitskopie - local temp_file - temp_file=$(mktemp) - - log "${SYM_INFO} ${COLOR_ACTION}Adding section ${COLOR_VALUE}'$section_name'${COLOR_ACTION} to ${COLOR_DIR}${file}${COLOR_RESET}" - - # Abschnitt vor dem schließenden Tag einfügen - if sed "s|$closing_tag|
\n$content\n
\n$closing_tag|" "$file" > "$temp_file"; then - if mv "$temp_file" "$file"; then - log "${SYM_OK} ${COLOR_OK}Successfully added section ${COLOR_VALUE}'$section_name'${COLOR_OK} to ${COLOR_DIR}${file}${COLOR_RESET}" - return 0 - fi - fi - - log "${SYM_BAD} ${COLOR_BAD}Failed to add section ${COLOR_VALUE}'$section_name'${COLOR_BAD} to ${COLOR_DIR}${file}${COLOR_RESET}" >&2 - return 1 -} - -# shellcheck disable=SC2317 -function del_xml_section() { - local file="$1" - local section_name="$2" - - # Verifizieren ob der Abschnitt existiert - if ! verify_xml_section "$file" "$section_name" >/dev/null; then - return 0 # Abschnitt existiert nicht - nichts zu tun - fi - - # Temporäre Datei für Sicherheitskopie - local temp_file - temp_file=$(mktemp) - - log "${SYM_INFO} ${COLOR_ACTION}Removing section ${COLOR_VALUE}'$section_name'${COLOR_ACTION} from ${COLOR_DIR}${file}${COLOR_RESET}" - - # Abschnitt entfernen (inklusive aller Zeilen zwischen Section-Tags) - if sed "/
/,/<\/Section>/d" "$file" > "$temp_file"; then - if mv "$temp_file" "$file"; then - log "${SYM_OK} ${COLOR_OK}Successfully removed section ${COLOR_VALUE}'$section_name'${COLOR_OK} from ${COLOR_DIR}${file}${COLOR_RESET}" - return 0 - fi - fi - - log "${SYM_BAD} ${COLOR_BAD}Failed to remove section ${COLOR_VALUE}'$section_name'${COLOR_BAD} from ${COLOR_DIR}${file}${COLOR_RESET}" >&2 - return 1 -} - -#* Beispiel Implementierung für PBR Textures ohne Test eingefügt. -function configure_pbr_textures() { - local asset_sets_file="opensim/bin/assets/AssetSets.xml" - local libraries_file="opensim/bin/inventory/Libraries.xml" - - log "\n${COLOR_HEADING}=== Configuring PBR Textures ===${COLOR_RESET}" - - # AssetSets.xml bearbeiten - add_xml_section "$asset_sets_file" "PBR Textures AssetSet" \ - " " || return 1 - - # Libraries.xml bearbeiten - add_xml_section "$libraries_file" "PBRTextures Library" \ - " \n " || return 1 - - log "${SYM_OK} ${COLOR_OK}PBR Textures configuration completed successfully${COLOR_RESET}" - -} - -function regionsclean() { - log "\033[33mWARNUNG: Dies wird ALLE Regionskonfigurationen in allen Simulatoren löschen!\033[0m" - echo "Sicher fortfahren? (j/N): " - read -r confirm - - if [[ "$confirm" =~ ^[jJ] ]]; then - echo "Starte Bereinigung..." - deleted_count=0 - - # Durch alle Simulatoren iterieren - for ((sim_num=1; sim_num<=999; sim_num++)); do - sim_dir="sim${sim_num}/bin/Regions" - - if [[ -d "$sim_dir" ]]; then - log "\033[33m ✓ Überprüfe $sim_dir...\033[0m" - - # Lösche nur .ini-Dateien (keine anderen Dateitypen) - while IFS= read -r -d $'\0' config_file; do - if [[ "$config_file" == *.ini ]]; then - rm -v "$config_file" - ((deleted_count++)) - fi - done < <(find "$sim_dir" -maxdepth 1 -type f -name "*.ini" -print0) - fi - done - - log "\033[32mFertig! Gelöschte Regionen: $deleted_count\033[0m" - else - echo "Abbruch: Keine Dateien wurden gelöscht." - fi - blankline -} - -function renamefiles() { - timestamp=$(date +"%Y%m%d_%H%M%S") - - if [ ! -d "$SCRIPT_DIR" ]; then - log "${RED}Fehler: Verzeichnis $SCRIPT_DIR nicht gefunden!${RESET}" - return 1 - fi - - log "${CYAN}Starte Umbenennung aller *.example Dateien in ${SCRIPT_DIR} und Unterverzeichnissen...${RESET}" - - # Verarbeite robust/bin zuerst - find "$SCRIPT_DIR" -type f -name "*.example" 2>/dev/null | while read -r example_file; do - local target_file="${example_file%.example}" # Entfernt .example - - if [ -f "$target_file" ]; then - local backup_file="${target_file}_${timestamp}.bak" - mv "$target_file" "$backup_file" - log "${YELLOW}Gesichert: ${target_file} → ${backup_file}${RESET}" - fi - - mv "$example_file" "$target_file" - log "${GREEN}Umbenannt: ${example_file} → ${target_file}${RESET}" - done - - # Jetzt alle simX/bin Verzeichnisse durchlaufen - for ((i=999; i>=1; i--)); do - sim_dir="${SCRIPT_DIR}/sim$i/bin" - if [ -d "$sim_dir" ]; then - log "${CYAN}Verarbeite: $sim_dir ${RESET}" - find "$sim_dir" -type f -name "*.example" 2>/dev/null | while read -r example_file; do - local target_file="${example_file%.example}" - - sleep 1 - - if [ -f "$target_file" ]; then - local backup_file="${target_file}_${timestamp}.bak" - mv "$target_file" "$backup_file" - log "${YELLOW}Gesichert: ${target_file} → ${backup_file}${RESET}" - fi - - mv "$example_file" "$target_file" - log "${GREEN}Umbenannt: ${example_file} → ${target_file}${RESET}" - done - fi - done - - log "${GREEN}Alle *.example Dateien wurden erfolgreich verarbeitet.${RESET}" - blankline - return 0 -} - -# Helper to clean config files (remove leading spaces/tabs) -function clean_config() { - local file=$1 - sed -i 's/^[ \t]*//' "$file" -} - -# cleanall - Removes OpenSim completely -function cleanall() { - echo "$(msg CLEANALL_PROMPT_REMOVE_ALL)" - read -r answer - - if is_yes "$answer"; then - echo "$(msg CLEANALL_START_DELETE)" - - # robust/bin Verzeichnis leeren, falls vorhanden - if [ -d "robust/bin" ]; then - rm -rf robust/bin/* - fi - - # Überprüfen, welche simX/bin Verzeichnisse existieren und leeren - for i in {1..999}; do - dir="sim$i/bin" - if [ -d "$dir" ]; then - rm -rf "${dir:?}/"* - sleep 1 - fi - done - - echo "$(msg CLEANALL_BIN_CLEARED)" - - elif is_no "$answer"; then - echo "$(msg CLEANALL_KEEP)" - - else - echo "$(msg INPUT_INVALID_YES_NO)" - fi - blankline -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* ZUSAMMENFASSUNG DER FUNKTIONEN IN LOGISCHE GRUPPEN -#?────────────────────────────────────────────────────────────────────────────────────────── - -# Kompletter OpenSim-Neustart mit Logrotation -function opensimrestart() { - opensimstop - sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp - logclean # Logbereinigung - sleep $Simulator_Start_wait # Wartezeit vor Neustart - opensimstart - log "\033[36mAktive Screen-Sessions:\033[0m" - screen -ls || echo "Keine Screen-Sessions gefunden" -} - -# Kompletter OpenSim-Neustart mit Logrotation -function opensimrestartParallel() { - opensimstopParallel - sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp - logclean # Logbereinigung - sleep $Simulator_Start_wait # Wartezeit vor Neustart - opensimstartParallel - log "\033[36mAktive Screen-Sessions:\033[0m" - screen -ls || echo "Keine Screen-Sessions gefunden" -} - -# Server-Reboot mit Vorbereitung -function reboot() { - log "\033[1;33m🔥 Server-Neustart wird eingeleitet...\033[0m" - - opensimstop - sleep $Simulator_Stop_wait - shutdown -r now -} - -# OpenSim komplett herunterladen ⚡ Vorsicht -function downloadallgit() { - # Downloads aus dem Github. - opensimgitcopy - moneygitcopy - #ruthrothgit # Funktioniert nicht richtig. - #avatarassetsgit # Funktioniert nicht richtig. - #osslscriptsgit - #pbrtexturesgit - # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() - #versionrevision - # OpenSimulator erstellen aus dem Source Code. - opensimbuild -} - -function webinstall() { -# Nach database_setup() - log "${COLOR_ACTION}Webserver (Apache/PHP) installieren? (j/n) [n] ${COLOR_RESET}" - read -r web_choice - if [[ -n "$web_choice" && "$web_choice" =~ ^[jJ] ]]; then - setup_webserver - fi -} - -function autoinstall() { - # 06.05.2025 - - # Server vorbereiten - servercheck - - # Verzeichnisse erstellen. Standard: 1 - createdirectory - - # Doppelten Konfigurationsdateien entfernen - removeconfigfiles - - # mySQL installieren. Standard: Benutzername wird generiert, dazu wird ein 16 stelliges Passwort erzeugt. - database_setup - - # Downloads aus dem Github hier OpenSim und Money. einfach beises mit Enter bestätigen. - opensimgitcopy - moneygitcopy - - # PHP installieren - #webinstall - # Webinterface aus dem Github holen - osWebinterfacegit - - # Neue standartavatare einfügen - #ruthrothgit # Funktioniert nicht richtig. - #avatarassetsgit # Funktioniert nicht richtig. - - # OSSL Beispielskripte - osslscriptsgit - - # Texturen für Normale und PBR Texturen installieren - #pbrtexturesgit - - # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() - #versionrevision - - # OpenSimulator erstellen aus dem Source Code. Standard: ja. - opensimbuild - - # Kleine Pause - sleep $Simulator_Start_wait - - # OpenSimulator kopieren - opensimcopy - - # Alles konfigurieren - iniconfig - - # Zufallsregionen erstellen - regionsiniconfig - - #Vor dem Start die letzten vorbereitungen. - firststart - - # OpenSimulator starten - opensimrestart - - # Eure Informationen sind gespeichert in UserInfo.ini bitte sicher verwahren. - -} - -function autoupgrade() { - # 05.05.2025 - opensimgitcopy - moneygitcopy - osslscriptsgit - opensimbuild - - sleep 5 - - opensimstop - opensimcopy - opensimstart -} - -function autoupgradefast() { - # 05.05.2025 - opensimgitcopy - moneygitcopy - osslscriptsgit - opensimbuild - - sleep 5 - - opensimstopParallel - opensimcopy - opensimstartParallel -} - -#* OpenSimulator bauen aus Github. -# Dies macht ausser dem OpenSimulator erstellen nichts weiter. -function buildopensim() { - opensimgitcopy - moneygitcopy - osslscriptsgit - # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() - versionrevision - opensimbuild -} - -# Standalone -function standalonesetup() { - # 12.05.2025 - log "\e[33m[Standalone] Setup wird durchgeführt...\e[0m" - - # Prüfen ob SCRIPT_DIR gesetzt ist - if [ -z "${SCRIPT_DIR}" ]; then - log "\e[31mFehler: SCRIPT_DIR ist nicht gesetzt!\e[0m" - return 1 - fi - - local opensim_bin="${SCRIPT_DIR}/opensim/bin" - local renamed=0 - local skipped=0 - - # Sicherstellen, dass das Verzeichnis existiert - if [ ! -d "${opensim_bin}" ]; then - log "\e[31mFehler: Verzeichnis ${opensim_bin} nicht gefunden!\e[0m" - return 1 - fi - - # Verarbeite alle .example Dateien - while IFS= read -r -d '' file; do - target="${file%.example}" - - if [ -e "${target}" ]; then - log "\e[33mÜbersprungen: ${target} existiert bereits\e[0m" - ((skipped++)) - else - if mv "${file}" "${target}"; then - log "\e[32mUmbenannt: ${file} → ${target}\e[0m" - ((renamed++)) - else - log "\e[31mFehler beim Umbenennen von ${file}\e[0m" - ((skipped++)) - fi - fi - done < <(find "${opensim_bin}" -type f -name "*.example" -print0) - - genPasswort=$(tr -dc 'A-Za-z0-9!@#$%^&*()' < /dev/urandom | head -c 16) - #genUserid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") - user_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") - - log "${COLOR_INFO}OpenSim User Erstellung${COLOR_RESET}" - - echo -n "Vorname: " - read -r VORNAME - - echo -n "Nachname: " - read -r NACHNAME - - echo -n "Passwort: " - read -r PASSWORT - - echo -n "E-Mail: " - read -r EMAIL - - # **Speicherung der Benutzerdaten in UserInfo.ini** NEU - ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" - log "${COLOR_INFO}Erstelle OpenSimUserInfo.ini neu${COLOR_RESET}" - sudo rm -f "$ini_file" - sudo touch "$ini_file" - - log "\n[UserData]" | sudo tee -a "$ini_file" >/dev/null - echo "System IP = ${system_ip}" | sudo tee -a "$ini_file" >/dev/null - echo "Vorname = ${VORNAME}" | sudo tee -a "$ini_file" >/dev/null - echo "Nachname = ${NACHNAME}" | sudo tee -a "$ini_file" >/dev/null - echo "Passwort = ${PASSWORT}" | sudo tee -a "$ini_file" >/dev/null - echo "E-Mail = ${EMAIL}" | sudo tee -a "$ini_file" >/dev/null - echo "UserID = ${user_uuid}" | sudo tee -a "$ini_file" >/dev/null - - log "${SYM_LOG} ${COLOR_LABEL}Benutzerdaten hinzugefügt in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" - - blankline -} - -function createstandaloneuser() { - # 12.05.2025 OpenSim Avatar erstellen - - # opensim starten - echo "opensim starten, erster start..." - if [[ -d "opensim/bin" && -f "opensim/bin/OpenSim.dll" ]]; then - log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}opensim ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}opensim/bin...${COLOR_RESET}" - cd opensim/bin || exit 1 - - screen -fa -S opensim -d -U -m dotnet OpenSim.dll - cd - >/dev/null 2>&1 || exit 1 - else - log "${SYM_BAD} ${COLOR_SERVER}opensim: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" - fi - - - # 1. INI-Datei auslesen mit angepasstem Parsing - ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" - return 1 - fi - - # Parsing-Funktion mit Trim und Leerzeichen im Pattern - ini_get() { - local section="$1" key="$2" - awk -F ' = ' ' - /^\[/ { current_section = substr($0, 2, length($0)-2) } - current_section == "'"$section"'" && $1 == "'"$key"'" { - sub(/^[ \t]+/, "", $2) # Trim leading whitespace - sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace - print $2 - exit - } - ' "$ini_file" - } - - # Werte auslesen - VORNAME=$(ini_get "UserData" "Vorname") - NACHNAME=$(ini_get "UserData" "Nachname") - PASSWORT=$(ini_get "UserData" "Passwort") - EMAIL=$(ini_get "UserData" "E-Mail") - user_uuid=$(ini_get "UserData" "UserID") - - # Überprüfe ob opensim läuft - if ! screen -list | grep -q "opensim"; then - log "${COLOR_BAD}CREATEUSER: opensim existiert nicht oder läuft nicht${COLOR_RESET}" - return 1 - fi - - # Benutzer in Robust erstellen - screen -S opensim -p 0 -X eval "stuff 'create user'^M" - screen -S opensim -p 0 -X eval "stuff '$VORNAME'^M" - screen -S opensim -p 0 -X eval "stuff '$NACHNAME'^M" - screen -S opensim -p 0 -X eval "stuff '$PASSWORT'^M" - screen -S opensim -p 0 -X eval "stuff '$EMAIL'^M" - screen -S opensim -p 0 -X eval "stuff '$user_uuid'^M" - screen -S opensim -p 0 -X eval "stuff ''^M" - - screen -S opensim -p 0 -X eval "stuff ''^M" - screen -S opensim -p 0 -X eval "stuff ''^M" - - log "${COLOR_OK}Masteruser $VORNAME $NACHNAME wurde erstellt${COLOR_RESET}" - log "${COLOR_INFO}UserID: $user_uuid${COLOR_RESET}" - blankline -} - -function createstandalonregion() { - # 12.05.2025 Standalone Region erstellen - local config_file="${PATH_OPENSIM_BIN}/Regions/opensim.ini" - local region_name="OpenSim" - local location="1000,1000" - local port="9015" - system_ip=$(hostname -I | awk '{print $1}') - region_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") - SIZES=768 - - # 1. INI-Datei auslesen mit angepasstem Parsing - ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" - return 1 - fi - - # Parsing-Funktion mit Trim und Leerzeichen im Pattern - ini_get() { - local section="$1" key="$2" - awk -F ' = ' ' - /^\[/ { current_section = substr($0, 2, length($0)-2) } - current_section == "'"$section"'" && $1 == "'"$key"'" { - sub(/^[ \t]+/, "", $2) # Trim leading whitespace - sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace - print $2 - exit - } - ' "$ini_file" - } - - # Werte auslesen - VORNAME=$(ini_get "UserData" "Vorname") - NACHNAME=$(ini_get "UserData" "Nachname") - PASSWORT=$(ini_get "UserData" "Passwort") - - touch "$config_file" - { - echo "[${VORNAME}${NACHNAME}]" - echo "RegionUUID = ${region_uuid}" - echo "Location = ${location}" - echo "SizeX = ${SIZES}" - echo "SizeY = ${SIZES}" - echo "SizeZ = ${SIZES}" - echo "InternalPort = ${port}" - echo "ExternalHostName = ${system_ip}" - echo "MaxPrims = 45000" - echo "MaxAgents = 40" - echo "MaptileStaticUUID = 20000000-1000-1000-1000-200000000000" - echo "InternalAddress = 0.0.0.0" - echo "AllowAlternatePorts = False" - echo "NonPhysicalPrimMax = 512" - echo "PhysicalPrimMax = 128" - echo ";ClampPrimSize = false" - echo ";MaxPrimsPerUser = -1" - echo ";ScopeID = 30000000-1000-1000-1000-300000000000" - echo ";RegionType = Mainland" - echo ";RenderMinHeight = -1" - echo ";RenderMaxHeight = 100" - echo ";MapImageModule = Warp3DImageModule" - echo ";TextureOnMapTile = true" - echo ";DrawPrimOnMapTile = true" - echo ";GenerateMaptiles = true" - echo ";MaptileRefresh = 0" - echo ";MaptileStaticFile = path/to/SomeFile.png" - echo ";MasterAvatarFirstName = ${VORNAME}" - echo ";MasterAvatarLastName = ${NACHNAME}" - echo ";MasterAvatarSandboxPassword = ${PASSWORT}" - } > "$config_file" - - echo "Region '${region_name}' wurde erfolgreich erstellt in ${config_file} (Location: ${location}, Port: ${port})" - - # Datei Regions.ini löschen - rm -v "opensim/bin/Regions/Regions.ini" -} - -function createstandaloneconfig() { - system_ip=$(hostname -I | awk '{print $1}') - file="$SCRIPT_DIR/opensim/bin/OpenSim.ini" - standalonehg="ja" - - # 1. INI-Datei auslesen mit angepasstem Parsing - ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" - if [[ ! -f "$ini_file" ]]; then - log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" - return 1 - fi - - # Parsing-Funktion mit Trim und Leerzeichen im Pattern - ini_get() { - local section="$1" key="$2" - awk -F ' = ' ' - /^\[/ { current_section = substr($0, 2, length($0)-2) } - current_section == "'"$section"'" && $1 == "'"$key"'" { - sub(/^[ \t]+/, "", $2) # Trim leading whitespace - sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace - print $2 - exit - } - ' "$ini_file" - } - - # Werte auslesen - VORNAME=$(ini_get "UserData" "Vorname") - NACHNAME=$(ini_get "UserData" "Nachname") - PASSWORT=$(ini_get "UserData" "Passwort") - - if [[ -z "$standalonehg" ]]; then - log "${COLOR_BAD}FEHLER: Variable 'standalonehg' nicht definiert!${COLOR_RESET}" - return 1 - fi - - # [Const] - set_ini_key "$file" "Const" "BaseHostname" "\"${system_ip}\"" - set_ini_key "$file" "Const" "PublicPort" "\"9010\"" - # [Estates] - set_ini_key "$file" "Estates" "DefaultEstateName" "\"$VORNAME$NACHNAME Estate\"" - set_ini_key "$file" "Estates" "DefaultEstateOwnerName" "\"9010\"" - set_ini_key "$file" "Estates" "DefaultEstateOwnerUUID" "\"10000000-1000-1000-1000-100000000000\"" - set_ini_key "$file" "Estates" "DefaultEstateOwnerPassword" "\"${PASSWORT}\"" - # [Terrain] - set_ini_key "$file" "Terrain" "InitialTerrain" "\"flat\"" - - if [[ "$standalonehg" = "ja" ]]; then - # [Architecture] - set_ini_key "$file" "Architecture" "Include-Architecture" "\"config-include/StandaloneHypergrid.ini\"" - log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" - else - # [Architecture] - set_ini_key "$file" "Architecture" "Include-Architecture" "\"config-include/Standalone.ini\"" - log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" - fi -} - -#* Standalone Installation -function buildstandalone() { - # OpenSimulator herunterladen und bauen - opensimgitcopy - # Skripte einfügen - osslscriptsgit - # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() - versionrevision - # OpenSimulator bauen - opensimbuild - # Standalone Setup - standalonesetup - # Create Standalone Config - createstandaloneconfig - # Create Startregion - createstandalonregion - # create user - createstandaloneuser - # Standalone neu starten - standalonerestart - - log "${COLOR_OK}Standalone OpenSimulator wurde erfolgreich installiert, die Daten stehen in der Datei OpenSimUserInfo.ini${COLOR_RESET}" - -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Hilfefunktionen -#?────────────────────────────────────────────────────────────────────────────────────────── - -function help() { - # Allgemeine Befehle - log "${COLOR_SECTION}${SYM_SERVER} OpenSim Grundbefehle:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_START}opensimstart${COLOR_RESET} \t\t # Startet OpenSimulator komplett" - log "${SYM_VOR} ${COLOR_STOP}opensimstop${COLOR_RESET} \t\t # Stoppt OpenSimulator komplett" - log "${SYM_VOR} ${COLOR_RESTART}opensimrestart${COLOR_RESET} \t # Startet den OpenSimulator komplett neu" - echo - log "${SYM_VOR} ${COLOR_START}simstart${COLOR_RESET} \t\t # simX angeben - startet einen Regionsserver" - log "${SYM_VOR} ${COLOR_STOP}simstop${COLOR_RESET} \t\t # simX angeben - stoppt einen Regionsserver" - log "${SYM_VOR} ${COLOR_RESTART}simrestart${COLOR_RESET} \t\t # simX angeben - startet einen Regionsserver neu" - echo "" - log "${SYM_VOR} ${COLOR_START}standalonestart${COLOR_RESET} \t # Standalone starten" - log "${SYM_VOR} ${COLOR_STOP}standalonestop${COLOR_RESET} \t # Standalone stoppen" - log "${SYM_VOR} ${COLOR_RESTART}standalonerestart${COLOR_RESET} \t # Standalone neu starten" - echo "" - log "${SYM_VOR} ${COLOR_RESTART}simkill${COLOR_RESET} \t\t # Wenn der Simulator nicht beendet werden kann" - echo "" - - # System-Checks - log "${COLOR_SECTION}${SYM_TOOLS} System-Checks:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}check_screens${COLOR_RESET} \t\t # Prüft laufende Prozesse und handelt entsprechend" - echo "" - - # Setup - log "${COLOR_SECTION}${SYM_TOOLS} Setup:${COLOR_RESET}" - #log "${SYM_VOR} ${COLOR_OK}servercheck${COLOR_RESET} \t\t # Installiert und Prüft den Server" - #log "${SYM_VOR} ${COLOR_OK}createdirectory${COLOR_RESET} \t\t # Erstellt alle benötigten Verzeichnisse" - log "${SYM_VOR} ${COLOR_OK}autoinstall${COLOR_RESET} \t\t # OpenSimulator Automatisiert installieren und einrichten" - log "${SYM_VOR} ${COLOR_OK}setcrontab${COLOR_RESET} \t\t # Richtet Crontab ein damit der Server wartungsfrei laeuft" - echo "" - - # Git-Operationen - #log "${COLOR_SECTION}${SYM_BOOK} Git-Operationen:${COLOR_RESET}" - #log "${SYM_VOR} ${COLOR_OK}opensimgitcopy${COLOR_RESET} \t\t # Klont den OpenSim Code" - #log "${SYM_VOR} ${COLOR_OK}moneygitcopy${COLOR_RESET} \t\t # Baut den MoneyServer in den OpenSimulator ein" - #log "${SYM_VOR} ${COLOR_OK}osslscriptsgit${COLOR_RESET} \t\t # Klont OSSL-Skripte" - #log "${SYM_VOR} ${COLOR_OK}versionrevision${COLOR_RESET} \t\t # Setzt Versionsrevision" - #echo "" - - # OpenSim Build & Deploy - #log "${COLOR_SECTION}${SYM_FOLDER} OpenSim Build & Deploy:${COLOR_RESET}" - #log "${SYM_VOR} ${COLOR_OK}opensimbuild${COLOR_RESET} \t\t # Kompiliert OpenSim zu ausführbaren Dateien" - #log "${SYM_VOR} ${COLOR_OK}opensimcopy${COLOR_RESET} \t\t # Kopiert OpenSim in alle Verzeichnisse" - #log "${SYM_VOR} ${COLOR_OK}opensimupgrade${COLOR_RESET} \t\t # Upgradet OpenSim" - #log "${SYM_VOR} ${COLOR_OK}database_setup${COLOR_RESET} \t\t # Erstellt alle Datenbanken" - #echo "" - - # Konfigurationsmanagement - #log "${COLOR_SECTION}${SYM_CONFIG} Konfigurationsmanagement:${COLOR_RESET}" - #log "${SYM_VOR} ${COLOR_WARNING}moneyserveriniconfig${COLOR_RESET}\t# Konfiguriert MoneyServer.ini (experimentell)" - #log "${SYM_VOR} ${COLOR_WARNING}opensiminiconfig${COLOR_RESET}\t# Konfiguriert OpenSim.ini (experimentell)" - #log "${SYM_VOR} ${COLOR_WARNING}regionsiniconfig${COLOR_RESET}\t# Konfiguriert Regionen (experimentell)" - #echo "" - - # Systembereinigung - log "${COLOR_SECTION}${SYM_CLEAN} Systembereinigung:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}cacheclean${COLOR_RESET} \t\t # Bereinigt OpenSimulator Cache" - log "${SYM_VOR} ${COLOR_OK}logclean${COLOR_RESET} \t\t # Bereinigt OpenSimulator Logs" - log "${SYM_VOR} ${COLOR_OK}mapclean${COLOR_RESET} \t\t # Bereinigt OpenSimulator Maptiles" - #log "${SYM_VOR} ${COLOR_OK}clean_linux_logs${COLOR_RESET}\t# Bereinigt Systemlogs" - echo "" - - # Hilfe - log "${COLOR_SECTION}${SYM_INFO} Hilfe:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}help${COLOR_RESET} \t\t\t # Zeigt diese Hilfe" - log "${SYM_VOR} ${COLOR_OK}prohelp${COLOR_RESET} \t\t # Zeigt die Pro Hilfe" - echo "" - log "${COLOR_SECTION}${SYM_INFO} Aufruf mit: bash osmtool.sh ${COLOR_RESET}" -} - -function prohelp() { - #* OpenSim Grundbefehle - log "${COLOR_SECTION}${SYM_SERVER} OpenSim Grundbefehle:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_START}opensimstart${COLOR_RESET} \t\t # OpenSim starten" - log "${SYM_VOR} ${COLOR_STOP}opensimstop${COLOR_RESET} \t\t # OpenSim stoppen" - log "${SYM_VOR} ${COLOR_RESTART}opensimrestart${COLOR_RESET} \t # OpenSim neu starten" - log "${SYM_VOR} ${COLOR_OK}check_screens${COLOR_RESET} \t\t # Laufende OpenSim-Prozesse prüfen und neu starten" - log "${SYM_VOR} ${COLOR_OK}autoupgrade${COLOR_RESET} \t\t # Automatisches OpenSim upgrade" - echo " " - log "${SYM_VOR} ${COLOR_START}opensimstartParallel${COLOR_RESET} \t # Startet alle Regionen parallel" - log "${SYM_VOR} ${COLOR_STOP}opensimstopParallel${COLOR_RESET} \t # Stoppt alle Regionen parallel" - log "${SYM_VOR} ${COLOR_RESTART}opensimrestartParallel${COLOR_RESET} # Startet alle Regionen neu (parallel)" - - log "${SYM_VOR} ${COLOR_START}simstart${COLOR_RESET} \t\t # Startet eine bestimmte Region" - log "${SYM_VOR} ${COLOR_STOP}simstop${COLOR_RESET} \t\t # Stoppt eine bestimmte Region" - log "${SYM_VOR} ${COLOR_RESTART}simrestart${COLOR_RESET} \t\t # Startet eine bestimmte Region neu" - echo " " - log "${SYM_VOR} ${COLOR_RESTART}simkill${COLOR_RESET} \t\t # Wenn der Simulator nicht beendet werden kann" - echo "" - - #* Standalone-Operationen - log "${COLOR_SECTION}${SYM_SCRIPT} Standalone-Operationen:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_START}standalonestart${COLOR_RESET} \t\t # Standalone starten" - log "${SYM_VOR} ${COLOR_STOP}standalonestop${COLOR_RESET} \t\t # Standalone stoppen" - log "${SYM_VOR} ${COLOR_RESTART}standalonerestart${COLOR_RESET} \t\t # Standalone neu starten" - log "${SYM_VOR} ${COLOR_OK}standalonestatus${COLOR_RESET} \t\t # Standalone Status anzeigen" - echo " " - log "${SYM_VOR} ${COLOR_OK}buildstandalone${COLOR_RESET} \t\t # Standalone erstellen" - log "${SYM_VOR} ${COLOR_OK}opensimgitcopy${COLOR_RESET} \t\t # OpenSimulator aus Git kopieren" - log "${SYM_VOR} ${COLOR_OK}osslscriptsgit${COLOR_RESET} \t\t # Skripte aus Repository einfügen" - log "${SYM_VOR} ${COLOR_OK}versionrevision${COLOR_RESET} \t\t # OpenSimulator-Version festlegen" - log "${SYM_VOR} ${COLOR_OK}opensimbuild${COLOR_RESET} \t\t\t # OpenSimulator bauen" - log "${SYM_VOR} ${COLOR_OK}standalonesetup${COLOR_RESET} \t\t # Standalone Setup durchführen" - log "${SYM_VOR} ${COLOR_OK}createmasteruser${COLOR_RESET} \t\t # Master-Benutzer erstellen" - echo " " - - #* System-Checks - log "${COLOR_SECTION}${SYM_TOOLS} System-Checks:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}servercheck${COLOR_RESET} \t\t # Serverbereitschaft prüfen und Abhängigkeiten installieren" - echo " " - - #* Setup - log "${COLOR_SECTION}${SYM_TOOLS} Setup:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}createdirectory${COLOR_RESET} \t # OpenSim-Verzeichnisse erstellen" - log "${SYM_VOR} ${COLOR_OK}setcrontab${COLOR_RESET} \t\t # Crontab Automatisierungen einrichten" - log "${SYM_VOR} ${COLOR_OK}setup_webserver${COLOR_RESET} \t # Webserver einrichten" - log "${SYM_VOR} ${COLOR_OK}webinstall${COLOR_RESET} \t\t # Webinterface installieren" - log "${SYM_VOR} ${COLOR_OK}osWebinterfacegit${COLOR_RESET} \t # Webinterface aus Git holen" - log "${SYM_VOR} ${COLOR_OK}autoinstall${COLOR_RESET} \t\t # OpenSimulator Automatisiert installieren und einrichten" - log "${SYM_VOR} ${COLOR_OK}firststart${COLOR_RESET} \t\t # Erststart-Konfiguration durchführen" - log "${SYM_VOR} ${COLOR_OK}setup_email_server${COLOR_RESET} \t # E-Mail-Server einrichten" - log "${SYM_VOR} ${COLOR_OK}remove_ubuntu_pro${COLOR_RESET} \t # Ubuntu Pro entfernen" - echo " " - - #* Git-Operationen - log "${COLOR_SECTION}${SYM_BOOK} Git-Operationen:${COLOR_RESET}" - - log "${SYM_VOR} ${COLOR_OK}opensimgitcopy${COLOR_RESET} \t # OpenSim aus Git herunterladen" - log "${SYM_VOR} ${COLOR_OK}moneygitcopy${COLOR_RESET} \t\t # MoneyServer aus Git holen" - log "${SYM_VOR} ${COLOR_WARNING}ruthrothgit${COLOR_RESET} \t\t # Ruth Roth IAR Dateien ${COLOR_BAD}(Vorsicht)${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_WARNING}avatarassetsgit${COLOR_RESET} \t # Avatar-Assets ${COLOR_BAD}(Vorsicht)${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}osslscriptsgit${COLOR_RESET} \t # OSSL Beispielskripte herunterladen" - log "${SYM_VOR} ${COLOR_WARNING}pbrtexturesgit${COLOR_RESET} \t # PBR-Texturen ${COLOR_BAD}(Vorsicht)${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}downloadallgit${COLOR_RESET} \t # Alle Git-Repos herunterladen" - log "${SYM_VOR} ${COLOR_OK}versionrevision${COLOR_RESET} \t # Versionsverwaltung aktivieren" - echo " " - - #* OpenSim Build & Deployment - log "${COLOR_SECTION}${SYM_FOLDER} OpenSim Build & Deploy:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}opensimbuild${COLOR_RESET} \t\t\t # OpenSim kompilieren" - log "${SYM_VOR} ${COLOR_OK}opensimcopy${COLOR_RESET} \t\t\t # OpenSim Dateien kopieren" - log "${SYM_VOR} ${COLOR_OK}opensimupgrade${COLOR_RESET} \t\t # OpenSim aktualisieren" - log "${SYM_VOR} ${COLOR_OK}database_setup${COLOR_RESET} \t\t # Datenbank für OpenSim einrichten" - log "${SYM_VOR} ${COLOR_OK}removeconfigfiles${COLOR_RESET} \t\t # Konfigurationsdateien entfernen" - log "${SYM_VOR} ${COLOR_OK}cleanconfig${COLOR_RESET} \t\t\t # Konfiguration bereinigen" - echo " " - log "${SYM_VOR} ${COLOR_OK}autoupgrade${COLOR_RESET} \t\t\t # Führt automatisches Update durch" - log "${SYM_VOR} ${COLOR_OK}autoupgradefast${COLOR_RESET} \t\t # Automatisches OpenSim Parallel upgraden" - log "${SYM_VOR} ${COLOR_OK}regionbackup${COLOR_RESET} \t\t\t # Sichert aktuelle Regionen-Daten" - log "${SYM_VOR} ${COLOR_OK}robustbackup${COLOR_RESET} \t\t\t # Backup der Robust-Datenbank (mit Zeitraumfilter)" - log "${SYM_VOR} ${COLOR_OK}robustrestore [teil]${COLOR_RESET} # Wiederherstellung aus robustbackup ${COLOR_BAD} experimentell${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}robustrepair [aktion]${COLOR_RESET} # Reparatur oder Bereinigung der Robust-DB ${COLOR_BAD} experimentell${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}restoreRobustDump ${COLOR_RESET} # Robust Wiederherstellung${COLOR_BAD} experimentell${COLOR_RESET}" - echo " " - - #* Konfigurationsmanagement - log "${COLOR_SECTION}${SYM_CONFIG} Konfigurationsmanagement:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_WARNING}moneyserveriniconfig${COLOR_RESET} \t\t # Konfiguriert MoneyServer.ini" - log "${SYM_VOR} ${COLOR_WARNING}opensiminiconfig${COLOR_RESET} \t\t # Konfiguriert OpenSim.ini" - log "${SYM_VOR} ${COLOR_WARNING}robusthginiconfig${COLOR_RESET} \t\t # Konfiguriert Robust.HG.ini" - log "${SYM_VOR} ${COLOR_WARNING}robustiniconfig${COLOR_RESET} \t\t # Konfiguriert Robust.local.ini" - log "${SYM_VOR} ${COLOR_WARNING}gridcommoniniconfig${COLOR_RESET} \t\t # Erstellt GridCommon.ini" - log "${SYM_VOR} ${COLOR_WARNING}standalonecommoniniconfig${COLOR_RESET} \t # Erstellt StandaloneCommon.ini" - log "${SYM_VOR} ${COLOR_WARNING}flotsaminiconfig${COLOR_RESET} \t\t # Erstellt FlotsamCache.ini" - log "${SYM_VOR} ${COLOR_WARNING}osslenableiniconfig${COLOR_RESET} \t\t # Konfiguriert osslEnable.ini" - log "${SYM_VOR} ${COLOR_WARNING}welcomeiniconfig${COLOR_RESET} \t\t # Konfiguriert Begrüßungsregion" - log "${SYM_VOR} ${COLOR_WARNING}regionsiniconfig${COLOR_RESET} \t\t # Startet neue Regionen-Konfigurationen" - log "${SYM_VOR} ${COLOR_WARNING}database_set_iniconfig${COLOR_RESET} \t # Datenbank-Konfiguration setzen" - log "${SYM_VOR} ${COLOR_WARNING}oswebinterfaceconfig${COLOR_RESET} \t\t # Webinterface konfigurieren" - log "${SYM_VOR} ${COLOR_WARNING}iniconfig${COLOR_RESET} \t\t\t # Startet ALLE Konfigurationen" - echo " " - - #* INI-Operationen - log "${COLOR_SECTION}${SYM_SCRIPT} INI-Operationen:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}verify_ini_section${COLOR_RESET} \t\t # INI-Abschnitt verifizieren" - log "${SYM_VOR} ${COLOR_OK}verify_ini_key${COLOR_RESET} \t\t # INI-Schlüssel verifizieren" - log "${SYM_VOR} ${COLOR_OK}add_ini_section${COLOR_RESET} \t\t # INI-Abschnitt hinzufügen" - log "${SYM_VOR} ${COLOR_OK}add_ini_before_section${COLOR_RESET} \t # INI-Abschnitt vor anderem einfügen" - log "${SYM_VOR} ${COLOR_OK}set_ini_key${COLOR_RESET} \t\t\t # INI-Schlüssel setzen" - log "${SYM_VOR} ${COLOR_OK}add_ini_key${COLOR_RESET} \t\t\t # INI-Schlüssel hinzufügen" - log "${SYM_VOR} ${COLOR_WARNING}del_ini_section${COLOR_RESET} \t\t # INI-Abschnitt löschen" - log "${SYM_VOR} ${COLOR_OK}uncomment_ini_line${COLOR_RESET} \t\t # INI-Zeile entkommentieren" - log "${SYM_VOR} ${COLOR_OK}uncomment_ini_section_line${COLOR_RESET} \t # INI-Zeile in Abschnitt entkommentieren" - log "${SYM_VOR} ${COLOR_OK}comment_ini_line${COLOR_RESET} \t\t # INI-Zeile auskommentieren" - echo " " - - #* XML-Operationen - log "${COLOR_SECTION}${SYM_SCRIPT} XML-Operationen:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}verify_xml_section${COLOR_RESET} \t\t # XML-Abschnitt verifizieren" - log "${SYM_VOR} ${COLOR_OK}add_xml_section${COLOR_RESET} \t\t # XML-Abschnitt hinzufügen" - log "${SYM_VOR} ${COLOR_WARNING}del_xml_section${COLOR_RESET} \t\t # XML-Abschnitt löschen" - echo " " - - #* Experimental - log "${COLOR_SECTION}${SYM_WARNING} Experimental:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_WARNING}configure_pbr_textures${COLOR_RESET} \t # PBR-Texturen konfigurieren" - log "${SYM_VOR} ${COLOR_OK}buildopensim${COLOR_RESET} \t\t\t # OpenSim Experimental Build" - log "${SYM_VOR} ${COLOR_OK}rootrights${COLOR_RESET} \t\t\t # Root-Rechte setzen" - echo " " - - #* System-Bereinigung - log "${COLOR_SECTION}${SYM_CLEAN} Systembereinigung:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}reboot${COLOR_RESET} \t\t # Linux Server neu starten" - log "${SYM_VOR} ${COLOR_OK}dataclean${COLOR_RESET} \t\t # OpenSimulator Daten bereinigen" - log "${SYM_VOR} ${COLOR_OK}pathclean${COLOR_RESET} \t\t # Pfade bereinigen" - log "${SYM_VOR} ${COLOR_OK}cacheclean${COLOR_RESET} \t\t # OpenSimulator Cache bereinigen" - log "${SYM_VOR} ${COLOR_OK}logclean${COLOR_RESET} \t\t # OpenSimulator Logs bereinigen" - log "${SYM_VOR} ${COLOR_OK}mapclean${COLOR_RESET} \t\t # OpenSimulator Maptiles bereinigen" - log "${SYM_VOR} ${COLOR_OK}autoallclean${COLOR_RESET} \t\t # Automatische Komplettbereinigung" - echo " " - log "${SYM_VOR} ${COLOR_OK}regionsclean${COLOR_RESET} \t\t # Alle Regionsdateien löschen" - log "${SYM_VOR} ${COLOR_OK}cleanall${COLOR_RESET} \t\t # Löscht OpenSim komplett" - log "${SYM_VOR} ${COLOR_OK}renamefiles${COLOR_RESET} \t\t # OpenSimulator Beispieldateien umbenennen" - log "${SYM_VOR} ${COLOR_OK}clean_linux_logs${COLOR_RESET} \t # Linux-Logs bereinigen" - log "${SYM_VOR} ${COLOR_OK}delete_opensim${COLOR_RESET} \t # OpenSimulator mit Verzeichnisse entfernen" - echo " " - - #* Hilfe - log "${COLOR_SECTION}${SYM_INFO} Hilfe:${COLOR_RESET}" - log "${SYM_VOR} ${COLOR_OK}help${COLOR_RESET} \t\t\t # Einfache Hilfeseite anzeigen" - log "${SYM_VOR} ${COLOR_OK}prohelp${COLOR_RESET} \t\t # Diese erweiterte Hilfe anzeigen" - #log "${SYM_VOR} ${COLOR_OK}generate_all_name${COLOR_RESET} \t\t # Namen generieren" - echo " " - log "${COLOR_SECTION}${SYM_INFO} Aufruf mit: bash osmtool.sh ${COLOR_RESET}" -} - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Eingabeauswertung -#?────────────────────────────────────────────────────────────────────────────────────────── - -case $KOMMANDO in - # Allgemeine Befehle # - check_screens) check_screens ;; - start|opensimstart) opensimstart ;; - stop|opensimstop) opensimstop ;; - osrestart|autorestart|restart|opensimrestart) opensimrestart ;; - simstart) simstart "$2" ;; - simstop) simstop "$2" ;; - simrestart) simrestart "$2" ;; - - # SYSTEM-CHECKS & SETUP # - servercheck) servercheck ;; - createdirectory) createdirectory ;; - setcrontab) setcrontab ;; - - # GIT-OPERATIONEN # - opensimgitcopy|opensimgit) opensimgitcopy ;; - moneygitcopy|moneygit) moneygitcopy ;; - ruthrothgit) ruthrothgit ;; - avatarassetsgit) avatarassetsgit ;; - osslscriptsgit) osslscriptsgit ;; - pbrtexturesgit) pbrtexturesgit ;; - downloadallgit) downloadallgit ;; - versionrevision) versionrevision ;; - osWebinterfacegit) osWebinterfacegit ;; - - # OPENSIM BUILD & DEPLOY # - opensimbuild) opensimbuild ;; - opensimcopy) opensimcopy ;; - opensimupgrade) opensimupgrade ;; - database_setup) database_setup ;; - setup_webserver) setup_webserver ;; - removeconfigfiles) removeconfigfiles ;; - webinstall) webinstall ;; - autoinstall) autoinstall ;; - - # KONFIGURATIONS-MGMT AUTOKONFIGURATION # - moneyserveriniconfig) moneyserveriniconfig "$2" "$3" ;; - opensiminiconfig) opensiminiconfig "$2" "$3" ;; - robusthginiconfig) robusthginiconfig "$2" "$3" ;; - robustiniconfig) robustiniconfig "$2" "$3" ;; - gridcommoniniconfig) gridcommoniniconfig "$2" "$3" ;; - standalonecommoniniconfig) standalonecommoniniconfig "$2" "$3" ;; - flotsaminiconfig) flotsaminiconfig "$2" "$3" ;; - osslenableiniconfig) osslenableiniconfig "$2" "$3" ;; - welcomeiniconfig) welcomeiniconfig "$2" "$3" ;; - database_set_iniconfig) database_set_iniconfig ;; - regionsiniconfig) regionsiniconfig ;; # Alle neuen Konfigurationen starten. - cleanconfig) clean_config "$2" ;; - createmasteruser) createmasteruser "$2" "$3" "$4" "$5" "$6" ;; - oswebinterfaceconfig) oswebinterfaceconfig ;; - firststart) firststart ;; - - # Experimental # - configure_pbr_textures) configure_pbr_textures ;; - - # INI-OPERATIONEN # - verify_ini_section) verify_ini_section "$2" "$3" "$4" ;; - verify_ini_key) verify_ini_key "$2" "$3" "$4" ;; - add_ini_section) add_ini_section "$2" "$3" ;; - add_ini_before_section) add_ini_before_section "$2" "$3" "$4" ;; - set_ini_key) set_ini_key "$2" "$3" "$4" "$5" ;; - add_ini_key) add_ini_key "$2" "$3" "$4" "$5" ;; - del_ini_section) del_ini_section "$2" "$3" ;; - uncomment_ini_line) uncomment_ini_line "$2" "$3" ;; - uncomment_ini_section_line) uncomment_ini_section_line "$2" "$3" "$4" ;; - comment_ini_line) comment_ini_line "$2" "$3" "$4" ;; - iniconfig) iniconfig ;; - - # XML-OPERATIONEN # - verify_xml_section) verify_xml_section "$2" "$3" ;; - add_xml_section) add_xml_section "$2" "$3" "$4" ;; - del_xml_section) del_xml_section "$2" "$3" ;; - - # STANDALONE-MODUS # - standalonesetup) standalonesetup ;; - standalonestart) standalonestart ;; - standalonestop) standalonestop ;; - standalonerestart) standalonerestart ;; - standalonestatus) standalonestatus ;; - - # SYSTEM-BEREINIGUNG # - reboot) reboot ;; - dataclean) dataclean ;; - pathclean) pathclean ;; - cacheclean) cacheclean ;; - logclean) logclean ;; - mapclean) mapclean ;; - autoallclean) autoallclean ;; - regionsclean) regionsclean ;; - cleanall) cleanall ;; - renamefiles) renamefiles ;; - clean_linux_logs) clean_linux_logs ;; - delete_opensim) delete_opensim ;; - - # Tests # - opensimstartParallel) opensimstartParallel ;; # Das Parallel verarbeiten kann bei großen Regionen den Server - faststop|opensimstopParallel) opensimstopParallel ;; # so belasten das er nicht mehr reagieren kann. - opensimrestartParallel) opensimrestartParallel ;; - autoupgrade) autoupgrade ;; - autoupgradefast) autoupgradefast ;; - regionbackup) regionbackup ;; - robustbackup) robustbackup ;; - robustrestore) robustrestore "$2" "$3" "$4" ;; - robustrepair) robustrepair "$2" "$3" "$4" ;; - restoreRobustDump) restoreRobustDump "$2" "$3" "$4" "$5" ;; - rootrights) rootrights ;; - buildopensim) buildopensim ;; - buildstandalone) buildstandalone ;; - setup_email_server) setup_email_server ;; - remove_ubuntu_pro) remove_ubuntu_pro ;; - simkill) simkill "$2" ;; - newservercheck) newservercheck ;; - - # Laden und Speichern von iar und oar - loadinventar) loadinventar "$2" "$3" "$4" "$5" ;; #loadinventar MyInventory mydirectory mypassword myinventory.iar - saveinventar) saveinventar "$2" "$3" "$4" "$5" ;; #saveinventar "MeinInventar" "/pfad/zum/verzeichnis" "geheimesPasswort" "inventar.iar" - loadoar) loadoar "$2" "$3" "$4" ;; #loadoar "RestoreScreen" "MyRegion" "/pfad/zum/verzeichnis" - saveoar) saveoar "$2" "$3" "$4" ;; #saveoar "RestoreScreen" "MyRegion" "/pfad/zum/verzeichnis" - autoregionbackup) autoregionbackup ;; - - # HILFE & SONSTIGES # - generate_all_name) generate_all_name ;; - prohelp) prohelp ;; - h|help|hilfe|*) help ;; -esac - -# Programm Ende mit Zeitstempel -blankline -log "\e[36m${SCRIPTNAME}\e[0m ${VERSION} wurde beendet $(date +'%Y-%m-%d %H:%M:%S')" >&2 -exit 0 - -# Ein Metaversum sind viele kleine Räume, die nahtlos aneinander passen, sowie direkt sichtbar und begehbar sind, als wäre es aus einem Guss. -# Ein Metaversum besteht aus vielen kleinen, nahtlos verbundenen Räumen, die direkt sichtbar und begehbar sind – als wäre alles aus einem Guss erschaffen. -# Das Metaversum setzt sich aus zahlreichen virtuellen Räumen zusammen, die ohne Ladezeiten oder Übergänge miteinander verbunden sind und sich wie eine zusammenhängende Welt erleben lassen. +#!/bin/bash + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Debug in log Datei +#! ACHTUNG das loggen speichert alles auch vertrauliche Daten. +#?────────────────────────────────────────────────────────────────────────────────────────── + +#* ====================================================================== +#* DEBUG-LOG-SYSTEM (Überarbeitete Version) +#* +#* Merkmale: +#* - Vollständig abwärtskompatibel zu bestehenden Aufrufen +#* - Thread-sicherer Zugriff auf Log-Datei (mit flock) +#* - Automatische Log-Rotation bei Größenüberschreitung +#* - Unterstützt farbige Konsolenausgabe und bereinigte Log-Dateien +#* - Robustere Fehlerbehandlung +#* ====================================================================== + +#* 1. LOGGING-KONFIGURATION +#* ---------------------------------------------------------------------- + +# Logging global aktivieren/deaktivieren (true/false) +LOG_ENABLED=true # Default: true (Logging aktiv) +#LOG_ENABLED=false # Zum Deaktivieren + +# Soll die Log-Datei beim Start gelöscht werden? +OLD_LOG_DEL=true # Default: true (alte Logs löschen) +#OLD_LOG_DEL=false # Zum Deaktivieren + +# Log-Datei Name und Speicherort +DEBUG_LOG="osmtool_debug.log" # Default: im aktuellen Verzeichnis + +# Maximale Log-Größe in MB bevor Rotation erfolgt (0 = deaktiviert) +MAX_LOG_SIZE_MB=10 # 10MB empfohlen + +#* 1b. KONFIGURATION AUS JSON (osmtool_config.json) +#* ---------------------------------------------------------------------- + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +CONFIG_FILE_DEFAULT="$SCRIPT_DIR/osmtool_config.json" +CONFIG_FILE="${OSMTOOL_CONFIG_FILE:-$CONFIG_FILE_DEFAULT}" + +function json_get_raw_value() { + local key="$1" + local file="$2" + + [[ -f "$file" ]] || return 1 + + if command -v jq >/dev/null 2>&1; then + jq -r --arg k "$key" '.[$k] // empty' "$file" 2>/dev/null + return 0 + fi + + sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*\"([^\"]*)\"[[:space:]]*,?[[:space:]]*$/\1/p" "$file" | head -n1 +} + +function json_get_string() { + local key="$1" + local default_value="$2" + local value + + value="$(json_get_raw_value "$key" "$CONFIG_FILE")" + if [[ -n "$value" ]]; then + printf '%s' "$value" + else + printf '%s' "$default_value" + fi +} + +function json_get_bool() { + local key="$1" + local default_value="$2" + local value + + if command -v jq >/dev/null 2>&1; then + value="$(jq -r --arg k "$key" '.[$k] // empty' "$CONFIG_FILE" 2>/dev/null)" + else + value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*(true|false)[[:space:]]*,?[[:space:]]*$/\1/p" "$CONFIG_FILE" | head -n1)" + fi + + case "$value" in + true|false) printf '%s' "$value" ;; + *) printf '%s' "$default_value" ;; + esac +} + +function json_get_int() { + local key="$1" + local default_value="$2" + local value + + if command -v jq >/dev/null 2>&1; then + value="$(jq -r --arg k "$key" '.[$k] // empty' "$CONFIG_FILE" 2>/dev/null)" + else + value="$(sed -n -E "s/^[[:space:]]*\"${key}\"[[:space:]]*:[[:space:]]*([0-9]+)[[:space:]]*,?[[:space:]]*$/\1/p" "$CONFIG_FILE" | head -n1)" + fi + + if [[ "$value" =~ ^[0-9]+$ ]]; then + printf '%s' "$value" + else + printf '%s' "$default_value" + fi +} + +function resolve_cfg_path() { + local path_value="$1" + if [[ -z "$path_value" ]]; then + printf '%s' "$SCRIPT_DIR" + return + fi + + if [[ "$path_value" = /* ]]; then + printf '%s' "$path_value" + else + printf '%s' "$SCRIPT_DIR/$path_value" + fi +} + +if [[ -f "$CONFIG_FILE" ]]; then + LOG_ENABLED="$(json_get_bool "log_enabled" "$LOG_ENABLED")" + OLD_LOG_DEL="$(json_get_bool "old_log_del" "$OLD_LOG_DEL")" + DEBUG_LOG="$(json_get_string "debug_log" "$DEBUG_LOG")" + MAX_LOG_SIZE_MB="$(json_get_int "max_log_size_mb" "$MAX_LOG_SIZE_MB")" +fi + +CFG_LANGUAGE="$(json_get_string "language" "de")" +CFG_LANG_DIR_REL="$(json_get_string "path_lang_dir" "lang")" +CFG_ROBUST_BIN_REL="$(json_get_string "path_robust_bin" "robust/bin")" +CFG_OPENSIM_BIN_REL="$(json_get_string "path_opensim_bin" "opensim/bin")" +CFG_WORKDIR_REL="$(json_get_string "path_workdir" ".")" + +LANG_DIR="$(resolve_cfg_path "$CFG_LANG_DIR_REL")" +PATH_ROBUST_BIN="$(resolve_cfg_path "$CFG_ROBUST_BIN_REL")" +PATH_OPENSIM_BIN="$(resolve_cfg_path "$CFG_OPENSIM_BIN_REL")" +WORK_DIR="$(resolve_cfg_path "$CFG_WORKDIR_REL")" + +export LANG_DIR PATH_ROBUST_BIN PATH_OPENSIM_BIN WORK_DIR + +if [[ ! -d "$WORK_DIR" ]]; then + WORK_DIR="$SCRIPT_DIR" +fi + +#* 2. LOG-SYSTEM INITIALISIERUNG +#* ---------------------------------------------------------------------- + +# Logdatei vorbereiten (wird nur aufgerufen wenn LOG_ENABLED=true) +function init_log_system() { + # Alte Log-Datei löschen falls gewünscht + if [[ "$OLD_LOG_DEL" == "true" ]]; then + : > "$DEBUG_LOG" 2>/dev/null || { + echo "FEHLER: Kann Logdatei nicht zurücksetzen: $DEBUG_LOG" >&2 + return 1 + } + else + touch "$DEBUG_LOG" 2>/dev/null || { + echo "FEHLER: Kann Logdatei nicht erstellen: $DEBUG_LOG" >&2 + return 1 + } + fi + + # Schreibrechte prüfen + if [ ! -w "$DEBUG_LOG" ]; then + echo "FEHLER: Keine Schreibrechte für Logdatei: $DEBUG_LOG" >&2 + return 1 + fi + + return 0 +} + +# System bei Start initialisieren +if [[ "$LOG_ENABLED" == "true" ]]; then + if ! init_log_system; then + echo "WARNUNG: Logging wird deaktiviert (Initialisierung fehlgeschlagen)" >&2 + LOG_ENABLED=false + fi +fi + +#* 3. HILFSFUNKTIONEN +#* ---------------------------------------------------------------------- + +# Entfernt ANSI-Farbcodes aus Text (für Log-Datei) +function clean_ansi() { + echo -e "$1" | sed -E 's/\x1B\[([0-9]{1,3}(;[0-9]{1,3})*)?[mGK]//g' +} + +# Führt Log-Rotation durch wenn MAX_LOG_SIZE_MB überschritten wird +function rotate_log_if_needed() { + [[ "$MAX_LOG_SIZE_MB" -eq 0 ]] && return # Rotation deaktiviert + + local log_size_mb + log_size_mb=$(du -m "$DEBUG_LOG" 2>/dev/null | cut -f1) || return + + if [[ "$log_size_mb" -ge "$MAX_LOG_SIZE_MB" ]]; then + mv "$DEBUG_LOG" "${DEBUG_LOG}.old" 2>/dev/null + : > "$DEBUG_LOG" 2>/dev/null + fi +} + +#* 4. HAUPT-LOG-FUNKTION (abwärtskompatibel!) +#* ---------------------------------------------------------------------- + +function log() { + local message="$1" + local level="${2:-INFO}" # Default-Level: INFO (abwärtskompatibel) + timestamp=$(date "+%Y-%m-%d %H:%M:%S") + + # 1. Immer zur Konsole ausgeben (mit Farben, genau wie bisher) + echo -e "$message" + + # 2. Nur in Log-Datei schreiben wenn Logging aktiviert + if [[ "$LOG_ENABLED" == "true" ]]; then + # Log-Rotation prüfen + rotate_log_if_needed + + # ANSI-Codes entfernen für Log-Datei + clean_message=$(clean_ansi "$message") + + # Thread-sicheres Schreiben (falls flock verfügbar) + if command -v flock >/dev/null; then + ( + flock -x 200 + echo "[${timestamp}] [${level}] ${clean_message}" >> "$DEBUG_LOG" + ) 200>>"$DEBUG_LOG" + else + echo "[${timestamp}] [${level}] ${clean_message}" >> "$DEBUG_LOG" + fi + fi +} + +#* 5. I18N-SYSTEM (de|en|fr|es) +#* ---------------------------------------------------------------------- + +APP_LANG="${OSM_LANG:-$CFG_LANGUAGE}" + +declare -A I18N_CURRENT=() +declare -A I18N_EN=() + +function normalize_lang() { + case "$1" in + de|en|fr|es) echo "$1" ;; + *) echo "de" ;; + esac +} + +function load_lang_file() { + local lang_file="$1" + local target_array_name="$2" + local line key value + + [[ -f "$lang_file" ]] || return 1 + + while IFS= read -r line || [[ -n "$line" ]]; do + [[ -z "$line" || "${line:0:1}" == "#" ]] && continue + [[ "$line" == *=* ]] || continue + key="${line%%=*}" + value="${line#*=}" + if [[ "$target_array_name" == "I18N_EN" ]]; then + I18N_EN["$key"]="$value" + else + I18N_CURRENT["$key"]="$value" + fi + done < "$lang_file" + + return 0 +} + +function init_i18n() { + APP_LANG="$(normalize_lang "$APP_LANG")" + I18N_CURRENT=() + I18N_EN=() + + load_lang_file "$LANG_DIR/en.lang" I18N_EN || true + load_lang_file "$LANG_DIR/${APP_LANG}.lang" I18N_CURRENT || true +} + +function msg() { + local key="$1" + if [[ -n "${I18N_CURRENT[$key]:-}" ]]; then + printf '%s' "${I18N_CURRENT[$key]}" + return + fi + if [[ -n "${I18N_EN[$key]:-}" ]]; then + printf '%s' "${I18N_EN[$key]}" + return + fi + printf '%s' "$key" +} + +function is_yes() { + case "${1,,}" in + j|ja|y|yes|o|oui|s|si) return 0 ;; + *) return 1 ;; + esac +} + +function is_no() { + case "${1,,}" in + n|no|nein|non) return 0 ;; + *) return 1 ;; + esac +} + +function parse_lang_arg() { + local -a filtered=() + local i=1 + while [[ $i -le $# ]]; do + local arg="${!i}" + if [[ "$arg" == "--lang" ]]; then + local next_index=$((i + 1)) + if [[ $next_index -le $# ]]; then + APP_LANG="$(normalize_lang "${!next_index}")" + i=$((i + 2)) + continue + fi + elif [[ "$arg" == --lang=* ]]; then + APP_LANG="$(normalize_lang "${arg#--lang=}")" + i=$((i + 1)) + continue + fi + filtered+=("$arg") + i=$((i + 1)) + done + + set -- "${filtered[@]}" + FILTERED_ARGS=("$@") +} + +parse_lang_arg "$@" +set -- "${FILTERED_ARGS[@]}" +export OSM_LANG="$APP_LANG" +init_i18n + +#* ====================================================================== +#* BEISPIELAUFRUFE: +#* +#* log "${COLOR_BAD}FEHLER: Robust.HG.ini nicht gefunden in $robust_dir${COLOR_RESET}" >&2 +#* log "Eine normale Info-Meldung" +#* ====================================================================== + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Informationen Kopfzeile +#?────────────────────────────────────────────────────────────────────────────────────────── + +# Quelle: +# https://github.com/ManfredAabye/opensimMULTITOOLS-II/blob/main/osmtool.sh + +tput reset # Bildschirmausgabe loeschen inklusive dem Scrollbereich. +SCRIPTNAME="opensimMULTITOOL II" + +#testmodus=1 # Testmodus: 1=aktiviert, 0=deaktiviert + +# Versionsnummer besteht aus: Jahr.Monat.Funktionsanzahl.Eigentliche_Versionsnummer +VERSION="V26.4.230.588" +log "\e[36m$SCRIPTNAME\e[0m $VERSION" +echo "$(msg INFO_TOOL_PURPOSE)" +echo "$(msg INFO_USE_OWN_RISK)" +log "\e[33m$(msg INFO_ABORT_HINT)\e[0m" +echo " " + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Variablen setzen +#?────────────────────────────────────────────────────────────────────────────────────────── + +#* FARBDEFINITIONEN +COLOR_OK='\e[32m' # Grün (Haken) +COLOR_BAD='\e[31m' # Rot (Kreuz) +COLOR_HEADING='\e[97m' # Weiß (Überschriften) +COLOR_START='\e[92m' # Hellgrün (Startaktionen) +COLOR_STOP='\e[91m' # Hellrot (Stopaktionen) +COLOR_SERVER='\e[36m' # Cyan (Server/Verzeichnisse/IPs) +COLOR_DIR='\e[90m' # Grau (Pfade) +COLOR_LABEL='\e[97m' # Weiß (Beschriftungen) +COLOR_WARNING='\e[33m' # Gelb (Warnungen) +COLOR_VALUE='\e[36m' # Cyan für Werte +COLOR_ACTION='\e[92m' # Hellgrün für Aktionen +COLOR_RESET='\e[0m' # Farbreset +COLOR_RESTART='\e[93m' # Gelb (RESTART) +COLOR_INFO='\e[31m' # Rot (INFO) +COLOR_SERVER='\e[34m' # Blau (SERVER) + +# Standardfarben +# COLOR_RED='\e[31m' # Rot +# COLOR_GREEN='\e[32m' # Grün +# COLOR_YELLOW='\e[33m' # Gelb +# COLOR_BLUE='\e[34m' # Blau (korrigiert für SERVER) +# COLOR_MAGENTA='\e[35m' # Magenta (dein aktueller "SERVER"-Wert) +# COLOR_CYAN='\e[36m' # Cyan +# COLOR_WHITE='\e[37m' # Weiß + +#* SYMBOLDEFINITIONEN +SYM_OK="${COLOR_OK}✓${COLOR_RESET}" +SYM_BAD="${COLOR_BAD}✗${COLOR_RESET}" +SYM_INFO="${COLOR_INFO}❓${COLOR_RESET}" +SYM_WAIT="${COLOR_VALUE}⏳${COLOR_RESET}" +SYM_LOG="${COLOR_VALUE}📋${COLOR_RESET}" +COLOR_SECTION='\e[0;35m' # Magenta für Sektionsnamen +COLOR_FILE='\e[0;33m' # Gelb für Dateipfade + +#* SYSTEM & SERVER +SYM_SERVER="${COLOR_SERVER}💻${COLOR_RESET}" # Server/Computer +#SYM_STORAGE="${COLOR_VALUE}💾${COLOR_RESET}" # Speicher (Diskette) +#SYM_NETWORK="${COLOR_VALUE}📡${COLOR_RESET}" # Netzwerk/Antenne +#SYM_SECURITY="${COLOR_VALUE}🔒${COLOR_RESET}" # Sicherheit + +#* DATEIEN & ORDNER +SYM_FOLDER="${COLOR_VALUE}📂${COLOR_RESET}" # Geöffneter Ordner +SYM_FILE="${COLOR_VALUE}📄${COLOR_RESET}" # Dokument +#SYM_ARCHIVE="${COLOR_VALUE}📦${COLOR_RESET}" # Archiv/Paket +#SYM_SEARCH="${COLOR_VALUE}🔍${COLOR_RESET}" # Suche + +#* TOOLS & AKTIONEN +SYM_TOOLS="${COLOR_VALUE}🧮${COLOR_RESET}" # Werkzeuge +SYM_CONFIG="${COLOR_VALUE}🔧${COLOR_RESET}" # Konfiguration +#SYM_MAINTENANCE="${COLOR_VALUE}🛠️${COLOR_RESET}" # Wartung +SYM_CLEAN="${COLOR_WARNING}🧹${COLOR_RESET}" # Bereinigung + +#* DOKUMENTATION +SYM_SCRIPT="${COLOR_VALUE}📜${COLOR_RESET}" # Skript +SYM_BOOK="${COLOR_VALUE}📖${COLOR_RESET}" # Dokumentation +#SYM_NOTES="${COLOR_VALUE}📝${COLOR_RESET}" # Notizen + +#* STATUS & KONTROLLE +SYM_OK="${COLOR_OK}✔${COLOR_RESET}" # Erfolg +SYM_BAD="${COLOR_BAD}✘${COLOR_RESET}" # Fehler +SYM_WARNING="${COLOR_WARNING}🔥${COLOR_RESET}" # Warnung +#SYM_RESTART="${COLOR_RESTART}🔄${COLOR_RESET}" # Neustart + +#* ERWEITERTE SYMBOLE (Für spezielle Funktionen) +#SYM_DATABASE="${COLOR_VALUE}💽${COLOR_RESET}" # Datenbank +#SYM_BACKUP="${COLOR_VALUE}💾${COLOR_RESET}" # Backup +#SYM_EMAIL="${COLOR_VALUE}📧${COLOR_RESET}" # E-Mail +#SYM_MONITORING="${COLOR_VALUE}📈${COLOR_RESET}" # Monitoring + +#* WARTEZEITEN muessen leider sein damit der Server nicht überfordert wird. +Simulator_Start_wait=15 # Sekunden +MoneyServer_Start_wait=30 # Sekunden +RobustServer_Start_wait=30 # Sekunden +Simulator_Stop_wait=15 # Sekunden +MoneyServer_Stop_wait=30 # Sekunden +RobustServer_Stop_wait=30 # Sekunden + +if [[ -f "$CONFIG_FILE" ]]; then + Simulator_Start_wait="$(json_get_int "simulator_start_wait" "$Simulator_Start_wait")" + MoneyServer_Start_wait="$(json_get_int "moneyserver_start_wait" "$MoneyServer_Start_wait")" + RobustServer_Start_wait="$(json_get_int "robustserver_start_wait" "$RobustServer_Start_wait")" + Simulator_Stop_wait="$(json_get_int "simulator_stop_wait" "$Simulator_Stop_wait")" + MoneyServer_Stop_wait="$(json_get_int "moneyserver_stop_wait" "$MoneyServer_Stop_wait")" + RobustServer_Stop_wait="$(json_get_int "robustserver_stop_wait" "$RobustServer_Stop_wait")" +fi + +# Sprachwert nach dem Bereinigen der Argumente fuer nachfolgende Logik sichern +KOMMANDO="${1:-}" + +#* Leere Zeile +function blankline() { + # Konfiguration: Zeichen für Linien (beliebig erweiterbar) + #local line_chars=("-" "_" "=" "#" "*" "~") + local line_chars=("_") + local line_length=80 # Standardlänge der Linie + + sleep 0.25 + + # Erzeuge jede Linie mit Verzögerung + for char in "${line_chars[@]}"; do + printf "%${line_length}s\n" | tr " " "$char" # Linie dynamisch generieren + echo " " # Leerzeile nach jeder Linie + done +} + +#* Hauptpfad des Skripts automatisch setzen +cd "$WORK_DIR" || exit 1 +system_ip=$(hostname -I | awk '{print $1}') +log "${COLOR_LABEL}$(msg INFO_WORKDIR)${COLOR_RESET} ${COLOR_VALUE}$WORK_DIR${COLOR_RESET}" +log "${COLOR_LABEL}$(msg INFO_SYSTEM_IP)${COLOR_RESET} ${COLOR_VALUE}$system_ip${COLOR_RESET}" +blankline + +#* Rootrechte erforderlich +function rootrights() { + # Root-Privilegien erforderlich + if [[ $EUID -ne 0 ]]; then + log "${COLOR_WARNING}$(msg ROOT_WARN_USER_MODE_1)${COLOR_RESET}" >&2 + log "$(msg ROOT_WARN_USER_MODE_2)${COLOR_RESET}" >&2 + log "[sudo bash osmtool.sh]" >&2 + + while true; do + log "$(msg ROOT_PROMPT_CONTINUE_NO_ROOT)" >&2 + read -r answer + + if is_yes "$answer"; then + log "$(msg ROOT_CONTINUE_NO_ROOT)" >&2 + return 0 + elif is_no "$answer"; then + log "${COLOR_STOP}$(msg COMMON_ABORTED)${COLOR_RESET}" >&2 + exit 1 + else + log "${COLOR_WARNING}$(msg INPUT_INVALID_YES_NO)${COLOR_RESET}" >&2 + fi + done + fi +} + + +#* Soll im Hypergrid Modus gearbeitet werden oder in einem Geschlossenen Grid? +function hypergrid() { + local modus="$1" + local robust_dir="$PATH_ROBUST_BIN" # Konfigurierbarer Pfad zu Robust-Dateien + + echo "$(msg MODE_CONFIG)" + + if [[ "$modus" == "hypergrid" ]]; then + echo "$(msg MODE_HYPERGRID_ENABLED)" + + # Prüfen ob Robust.HG.ini existiert + if [[ ! -f "$robust_dir/Robust.HG.ini" ]]; then + log "${COLOR_BAD}FEHLER: Robust.HG.ini nicht gefunden in $robust_dir${COLOR_RESET}" >&2 + return 1 + fi + + cp "$robust_dir/Robust.HG.ini" "$robust_dir/Robust.ini" || { + log "${COLOR_BAD}FEHLER: Konnte Robust.HG.ini nicht kopieren${COLOR_RESET}" >&2 + return 1 + } + + else + echo "$(msg MODE_CLOSEDGRID_ENABLED)" + + # Prüfen ob Robust.local.ini existiert + if [[ ! -f "$robust_dir/Robust.local.ini" ]]; then + log "${COLOR_BAD}FEHLER: Robust.local.ini nicht gefunden in $robust_dir${COLOR_RESET}" >&2 + return 1 + fi + + cp "$robust_dir/Robust.local.ini" "$robust_dir/Robust.ini" || { + log "${COLOR_BAD}FEHLER: Konnte Robust.local.ini nicht kopieren${COLOR_RESET}" >&2 + return 1 + } + fi + + log "${COLOR_OK}$(msg MODE_SET_OK): $modus${COLOR_RESET}" + return 0 +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Abhängigkeiten installieren +#?────────────────────────────────────────────────────────────────────────────────────────── + +# Nach git clone/pull prüfen +check_repo_integrity() { + local repo_dir=${1:-.} + + pushd "$repo_dir" > /dev/null || return 1 + + if ! git fsck --no-progress; then + log "${SYM_BAD} ${COLOR_ERROR}Repository-Prüfung fehlgeschlagen!${COLOR_RESET}" + popd > /dev/null + return 1 + fi + + if [ "$(git status --porcelain)" ]; then + log "${COLOR_WARNING}Uncommittete Änderungen vorhanden.${COLOR_RESET}" + fi + + popd > /dev/null + log "${SYM_OK} ${COLOR_ACTION}Repository-Integrität OK.${COLOR_RESET}" + return 0 +} + +function warn_if_desktop_environment() { + log "${COLOR_SECTION}=== Systemtyp-Erkennung (Server vs. Desktop) ===${COLOR_RESET}" + + # Prüfen auf Anzeichen einer Desktop-Umgebung + if [[ -n "$XDG_CURRENT_DESKTOP" || -n "$DESKTOP_SESSION" || $(pgrep -lE 'gnome|plasma|xfce|mate|lxde|cinnamon' 2>/dev/null) ]]; then + log "${SYM_WARNING} ${COLOR_WARNING}Desktop-Umgebung erkannt!${COLOR_RESET}" + log "${COLOR_WARNING}${SYM_WARNING} Du führst dieses Skript auf einem Desktop-System aus.${COLOR_RESET}" + log "${COLOR_ACTION}Dieses Setup installiert einen Server und benötigt Root-Rechte.${COLOR_RESET}" + log "${COLOR_WARNING}Bitte stelle sicher, dass du weißt, was du tust.${COLOR_RESET}" + echo -ne "${COLOR_ACTION}Trotzdem fortfahren? (j/n) [n] ${COLOR_RESET}" + read -r user_continue + user_continue=${user_continue:-n} + + if [[ "$user_continue" =~ ^[nN]$ ]]; then + log "${SYM_BAD} ${COLOR_BAD}Installation abgebrochen vom Benutzer.${COLOR_RESET}" + exit 1 + fi + fi +} + +# -------------------------- +# Neuer Servercheck mit installationen. +# -------------------------- + +# -------------------------- +# 🛠️ HAUPTFUNKTION: servercheck() +# -------------------------- +function newservercheck() { + log "${COLOR_HEADING}🔍 Server-Kompatibilitätscheck wird durchgeführt...${COLOR_RESET}" + + rootrights + warn_if_desktop_environment + + # 1. Distro erkennen + detect_distro + + # 2. .NET prüfen/installieren + install_dotnet + + # 3. MariaDB prüfen/installieren + install_mariadb + + # 4. Abhängigkeiten installieren + install_dependencies + + log "${SYM_OK} ${COLOR_HEADING}Server-Check abgeschlossen!${COLOR_RESET}" +} + +# -------------------------- +# 🖥️ NEBENFUNKTIONEN (modular & erweiterbar) +# -------------------------- + +function detect_distro() { + # OS-Details global speichern + #log "detect_distro:" + declare -g os_id os_version os_codename # Explizit deklarieren + os_id=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"') + os_version=$(grep '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"') + os_codename=$(grep '^VERSION_CODENAME=' /etc/os-release | cut -d= -f2 | tr -d '"') + + log "${COLOR_LABEL}Server läuft mit:${COLOR_RESET} ${COLOR_SERVER}$os_id $os_version ($os_codename)${COLOR_RESET}" +} + +function install_dotnet() { + # Paketnamen-Mapping (erweiterbar!) + #log "install_dotnet:" + declare -A dotnet_pkg=( + ["ubuntu"]="dotnet-sdk-8.0" + ["debian"]="dotnet-sdk-8.0" + ["linuxmint"]="dotnet-sdk-8.0" + ["pop_os"]="dotnet-sdk-8.0" + ["arch"]="dotnet-sdk" + ["manjaro"]="dotnet-sdk" + ["raspbian"]="dotnet-sdk-8.0" + ) + + # Distro-spezifische Logik + case "$os_id" in + ubuntu|linuxmint|pop_os) + if [[ "$os_version" == "18.04" ]]; then + required_dotnet="dotnet-sdk-6.0" + elif [[ "$os_version" == "24.04" ]]; then + required_dotnet=${dotnet_pkg[$os_id]} + log "${SYM_INFO} Ubuntu 24.04 verwendet das .NET Repository für 22.04 (jammy)" + elif dpkg --compare-versions "$os_version" ge "20.04"; then + required_dotnet=${dotnet_pkg[$os_id]} + else + log "${SYM_BAD} Nicht unterstützte Ubuntu-Version: $os_version!" + return 1 + fi + ;; + debian|raspbian) + [[ "$os_version" -ge "11" ]] || { log "${SYM_BAD} Debian $os_version wird nicht unterstützt!"; return 1; } + required_dotnet=${dotnet_pkg[$os_id]} + ;; + arch|manjaro) + required_dotnet=${dotnet_pkg[$os_id]} + ;; + *) + log "${SYM_BAD} Nicht unterstützte Distribution: $os_id!" + return 1 + ;; + esac + + # Installationslogik (pacman vs. apt) + if [[ "$os_id" =~ ^(arch|manjaro)$ ]]; then + pacman_install "$required_dotnet" + else + apt_install "$required_dotnet" + # Microsoft-Repo für Debian/Ubuntu + [[ "$os_id" =~ ^(ubuntu|debian|linuxmint|pop_os|raspbian)$ ]] && add_microsoft_repo + fi +} + +function install_mariadb() { + #log "install_mariadb:" + if ! command -v mariadb >/dev/null; then + apt_install "mariadb-server" || return 1 + fi + + # Version anzeigen & Service starten + log "${SYM_OK} MariaDB-Version: $(mariadb --version)" + systemctl start mariadb || { log "${SYM_BAD} MariaDB start fehlgeschlagen!"; return 1; } +} + +function install_dependencies() { + #log "install_dependencies:" + # Dependency-Mapping (erweiterbar!) + declare -A required_packages=( + ["ubuntu"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" + ["arch"]="git glibc gcc-libs krb5 icu lttng-ust openssl libunwind zlib gdiplus zip screen" + # ... weitere Distros hier ergänzen + ) + + # Fallback-Pakete + local pkg_list=("git" "libc6" "libgcc-s1" "libssl3" "zip" "screen") + [[ -n "${required_packages[$os_id]}" ]] && IFS=' ' read -r -a pkg_list <<< "${required_packages[$os_id]}" + + # Installieren + for pkg in "${pkg_list[@]}"; do + if [[ "$os_id" =~ ^(arch|manjaro)$ ]]; then + pacman_install "$pkg" + else + apt_install "$pkg" + fi + done +} + +# -------------------------- +# 🔧 HELFERFUNKTIONEN (DRY-Prinzip) +# -------------------------- +function apt_install() { + #log "apt_install: $1" + if ! dpkg-query -W "$1" >/dev/null 2>&1; then + log "${SYM_OK} Installiere $1..." + sudo apt-get install -y "$1" || { log "${SYM_BAD} Installation von $1 fehlgeschlagen!"; return 1; } + fi +} + +function pacman_install() { + #log "pacman_install:" + if ! pacman -Qi "$1" >/dev/null 2>&1; then + log "${SYM_OK} Installiere $1..." + sudo pacman -S --noconfirm "$1" || { log "${SYM_BAD} Installation von $1 fehlgeschlagen!"; return 1; } + fi +} + +function add_microsoft_repo() { + #log "add_microsoft_repo:" + # Prüfen, ob das Repo existiert UND funktioniert (via apt-key) + if ! apt-cache policy | grep -q "packages.microsoft.com" || \ + ! grep -q "packages.microsoft.com" /etc/apt/sources.list.d/* 2>/dev/null; then + log "${SYM_INFO} Füge Microsoft-Repository hinzu..." + + # Download & Install mit Fehlerabfrage + if ! wget -qO packages-microsoft-prod.deb "https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb"; then + log "${SYM_BAD} Download des Microsoft-Repos fehlgeschlagen!" + return 1 + fi + + if ! sudo dpkg -i packages-microsoft-prod.deb >/dev/null; then + log "${SYM_BAD} Installation des Microsoft-Repos fehlgeschlagen!" + rm -f packages-microsoft-prod.deb + return 1 + fi + + rm -f packages-microsoft-prod.deb + sudo apt-get update >/dev/null || { log "${SYM_BAD} apt-get update fehlgeschlagen!"; return 1; } + else + log "${SYM_INFO} Microsoft-Repository ist bereits konfiguriert." + fi +} + +# -------------------------- +# Neuer Servercheck mit installationen ENDE +# -------------------------- + +function servercheck() { + # Direkt kompatible Distributionen: + # Debian 11+ (Bullseye, Bookworm) – Offiziell unterstützt für .NET 8 + # Ubuntu 20.04, 22.04, 24.04 – Microsoft bietet direkt kompatible Pakete + # Linux Mint (basierend auf Ubuntu 20.04 oder 22.04) + # Pop!_OS (System76, basiert auf Ubuntu) + # MX Linux (Debian-basiert, integriert Ubuntu-Funktionen) + # Arch Linux – Offiziell unterstützte Pakete über pacman + # Manjaro – Bietet .NET-Pakete direkt über die Arch-Repositorys + + # Mögliche kompatible Distributionen (mit Anpassungen): + # Kali Linux (basierend auf Debian 12, Anpassungen nötig für .NET-Pakete) + # Zorin OS (Ubuntu-basiert, Unterstützung abhängig von Version) + # elementary OS (Ubuntu-basiert, kann .NET aus Ubuntu-Quellen beziehen) + # Raspberry Pi OS (Debian-basiert, erfordert manuelle Installation für .NET) + + log "${COLOR_HEADING}🔍 Server-Kompatibilitätscheck wird durchgeführt...${COLOR_RESET}" + + rootrights + warn_if_desktop_environment + + # Ermitteln der Distribution und Version + os_id=$(grep '^ID=' /etc/os-release | cut -d= -f2 | tr -d '"') + os_version=$(grep '^VERSION_ID=' /etc/os-release | cut -d= -f2 | tr -d '"') + os_codename=$(grep '^VERSION_CODENAME=' /etc/os-release | cut -d= -f2 | tr -d '"') + + log "${COLOR_LABEL}Server läuft mit:${COLOR_RESET} ${COLOR_SERVER}$os_id $os_version ($os_codename)${COLOR_RESET}" + + # Paketnamen für verschiedene Distributionen definieren + declare -A dotnet_pkg=( + ["ubuntu"]="dotnet-sdk-8.0" + ["debian"]="dotnet-sdk-8.0" + ["linuxmint"]="dotnet-sdk-8.0" + ["pop_os"]="dotnet-sdk-8.0" + ["arch"]="dotnet-sdk" + ["manjaro"]="dotnet-sdk" + ["raspbian"]="dotnet-sdk-8.0" + ) + + # Abhängigkeiten für verschiedene Distributionen + declare -A required_packages=( + ["ubuntu"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" + ["debian"]="git libc6 libgcc1 libgssapi-krb5-2 libicu67 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" + ["linuxmint"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" + ["pop_os"]="git libc6 libgcc-s1 libgssapi-krb5-2 libicu70 liblttng-ust1 libssl3 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" + ["arch"]="git glibc gcc-libs krb5 icu lttng-ust openssl libunwind zlib gdiplus zip screen" + ["manjaro"]="git glibc gcc-libs krb5 icu lttng-ust openssl libunwind zlib gdiplus zip screen" + ["raspbian"]="git libc6 libgcc1 libgssapi-krb5-2 libicu67 liblttng-ust0 libssl1.1 libstdc++6 libunwind8 zlib1g libgdiplus zip screen" + ) + + # Prüfen, welche .NET-Version installiert werden muss + if [[ "$os_id" == "ubuntu" || "$os_id" == "linuxmint" || "$os_id" == "pop_os" ]]; then + if [[ "$os_version" == "18.04" ]]; then + required_dotnet="dotnet-sdk-6.0" + elif dpkg --compare-versions "$os_version" ge "20.04"; then + required_dotnet=${dotnet_pkg[$os_id]} + + # Spezialfall Ubuntu 24.04 (verwendet jammy Repository) + if [[ "$os_version" == "24.04" ]]; then + log "${SYM_INFO} Ubuntu 24.04 verwendet das .NET Repository für Ubuntu 22.04 (jammy)" + fi + else + log "${SYM_BAD} ${COLOR_WARNING}Nicht unterstützte Ubuntu-Version: $os_version!${COLOR_RESET}" + return 1 + fi + elif [[ "$os_id" == "debian" ]]; then + if [[ "$os_version" -ge "11" ]]; then + required_dotnet=${dotnet_pkg[$os_id]} + else + log "${SYM_BAD} ${COLOR_WARNING}Debian Version $os_version wird nicht unterstützt (mindestens Debian 11 erforderlich)!${COLOR_RESET}" + return 1 + fi + elif [[ "$os_id" == "arch" || "$os_id" == "manjaro" ]]; then + required_dotnet=${dotnet_pkg[$os_id]} + elif [[ "$os_id" == "raspbian" ]]; then + if [[ "$os_version" -ge "11" ]]; then + required_dotnet=${dotnet_pkg[$os_id]} + log "${SYM_INFO} Raspberry Pi OS erfordert möglicherweise manuelle Anpassungen für .NET 8.0" + else + log "${SYM_BAD} ${COLOR_WARNING}Raspberry Pi OS Version $os_version wird nicht unterstützt!${COLOR_RESET}" + return 1 + fi + else + log "${SYM_BAD} ${COLOR_WARNING}Keine unterstützte Distribution für .NET gefunden!${COLOR_RESET}" + return 1 + fi + + # .NET-Installationsstatus prüfen + log "${COLOR_HEADING}🔄 .NET Runtime-Überprüfung:${COLOR_RESET}" + + if [[ "$os_id" == "arch" || "$os_id" == "manjaro" ]]; then + if ! pacman -Qi "$required_dotnet" >/dev/null 2>&1; then + log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$required_dotnet${COLOR_RESET}..." + sudo pacman -S --noconfirm "$required_dotnet" + log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}wurde erfolgreich installiert.${COLOR_RESET}" + else + log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}ist bereits installiert.${COLOR_RESET}" + fi + else + #if ! dpkg -s "$required_dotnet" >/dev/null 2>&1; then + # dpkg-query -W hat eine bessere Fehlerabfrage + if ! dpkg-query -W "$required_dotnet" >/dev/null 2>&1; then + log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$required_dotnet${COLOR_RESET}..." + + # Microsoft Repository hinzufügen für Debian/Ubuntu-basierte Systeme + if [[ "$os_id" == "ubuntu" || "$os_id" == "debian" || "$os_id" == "linuxmint" || "$os_id" == "pop_os" || "$os_id" == "raspbian" ]]; then + log "${SYM_INFO} Füge Microsoft Repository hinzu..." + wget https://packages.microsoft.com/config/ubuntu/22.04/packages-microsoft-prod.deb -O packages-microsoft-prod.deb + sudo dpkg -i packages-microsoft-prod.deb + rm packages-microsoft-prod.deb + sudo apt-get update + fi + + sudo apt-get install -y "$required_dotnet" + log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}wurde erfolgreich installiert.${COLOR_RESET}" + else + log "${SYM_OK} ${COLOR_SERVER}$required_dotnet${COLOR_RESET} ${COLOR_ACTION}ist bereits installiert.${COLOR_RESET}" + fi + fi + + # Prüfen, ob MariaDB installiert ist + if ! command -v mariadb >/dev/null 2>&1; then + log "${SYM_BAD} ${COLOR_BAD}MariaDB ist nicht installiert! Ich installiere mariadb über apt.${COLOR_RESET}" + # 20.05.2025 Hier wird vor der installation von MariaDB abgebrochen dabei sollte das spätestens jetzt installiert werden. + sudo apt install mariadb-server + #exit 1 + fi + + # MariaDB-Version anzeigen + mariadb_version=$(mariadb --version) + log "${SYM_OK} ${COLOR_OK}Gefundene MariaDB-Version: ${COLOR_VALUE}$mariadb_version${COLOR_RESET}" + + # Prüfen, ob Dienst läuft + if systemctl is-active --quiet mariadb; then + log "${SYM_OK} ${COLOR_OK}MariaDB-Dienst ist bereits aktiv.${COLOR_RESET}" + else + log "${SYM_STOP} ${COLOR_WARNING}MariaDB ist nicht aktiv. Versuche zu starten...${COLOR_RESET}" + sudo systemctl start mariadb + if systemctl is-active --quiet mariadb; then + log "${SYM_OK} ${COLOR_OK}MariaDB wurde erfolgreich gestartet.${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_BAD}Fehler: MariaDB konnte nicht gestartet werden!${COLOR_RESET}" + exit 1 + fi + fi + + # Prüfen, ob Datenbankverzeichnis initialisiert ist + if [ -d /var/lib/mysql/mysql ]; then + log "${SYM_INFO} ${COLOR_LABEL}MariaDB ist bereits initialisiert.${COLOR_RESET}" + else + log "${SYM_TOOLS} ${COLOR_ACTION}Initialisiere MariaDB-Datenbankverzeichnis...${COLOR_RESET}" + sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + sudo systemctl restart mariadb + log "${SYM_OK} ${COLOR_OK}MariaDB wurde initialisiert und neu gestartet.${COLOR_RESET}" + fi + # MariaDB-Version checken ende + + # Fehlende Pakete prüfen und installieren + log "${COLOR_HEADING}${SYM_PACKAGE} Überprüfe fehlende Pakete...${COLOR_RESET}" + + # Paketliste basierend auf Distribution auswählen + if [[ -n "${required_packages[$os_id]}" ]]; then + IFS=' ' read -r -a pkg_list <<< "${required_packages[$os_id]}" + else + # Fallback für nicht aufgeführte Distributionen + pkg_list=("git" "libc6" "libgcc-s1" "libgssapi-krb5-2" "libicu70" "libssl3" "libstdc++6" "zlib1g" "zip" "screen") + fi + + for package in "${pkg_list[@]}"; do + if [[ "$os_id" == "arch" || "$os_id" == "manjaro" ]]; then + if ! pacman -Qi "$package" >/dev/null 2>&1; then + log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$package${COLOR_RESET}..." + sudo pacman -S --noconfirm "$package" + fi + else + #if ! dpkg -s "$package" >/dev/null 2>&1; then + # dpkg-query -W hat eine bessere Fehlerabfrage + if ! dpkg-query -W "$package" >/dev/null 2>&1; then + log "${SYM_OK} ${COLOR_ACTION}Installiere ${COLOR_SERVER}$package${COLOR_RESET}..." + sudo apt-get install -y "$package" + fi + fi + done + + log "${SYM_OK} ${COLOR_HEADING}Alle benötigten Pakete wurden installiert.${COLOR_RESET}" + blankline +} + +function setup_webserver() { + log "${COLOR_SECTION}=== Web Server Setup (Apache/PHP) ===${COLOR_RESET}" + + rootrights + + # 1. Paketlisten mit erweiterten PHP-Modulen + declare -A web_packages=( + ["ubuntu"]="apache2 php libapache2-mod-php php-mysql php-gd php-curl php-mbstring php-xml php-zip" + ["debian"]="apache2 php libapache2-mod-php php-mysql php-gd php-curl php-mbstring php-xml php-zip" + ["arch"]="apache php php-apache php-gd php-curl php-mysql mariadb-libs php-mbstring php-xml" + ["manjaro"]="apache php php-apache php-gd php-curl php-mysql mariadb-libs php-mbstring php-xml" + ["centos"]="httpd php php-mysqlnd php-gd php-curl php-mbstring php-xml" + ["fedora"]="httpd php php-mysqlnd php-gd php-curl php-mbstring php-xml" + ) + + # 2. Installation + case $current_distro in + ubuntu|debian|linuxmint|pop|raspbian) + log "${SYM_INFO} ${COLOR_ACTION}Installiere Apache/PHP (apt)...${COLOR_RESET}" + sudo apt-get update + sudo apt-get install -y "${web_packages[ubuntu]}" || { + log "${SYM_BAD} ${COLOR_ERROR}Installation fehlgeschlagen!${COLOR_RESET}"; + return 1; + } + sudo a2enmod rewrite + sudo systemctl restart apache2 + ;; + + arch|manjaro) + log "${SYM_INFO} ${COLOR_ACTION}Installiere Apache/PHP (pacman)...${COLOR_RESET}" + sudo pacman -Sy --noconfirm "${web_packages[arch]}" || { + log "${SYM_BAD} ${COLOR_ERROR}Installation fehlgeschlagen!${COLOR_RESET}"; + return 1; + } + + # Apache-Konfiguration für PHP + sudo sed -i 's/LoadModule mpm_event_module/#LoadModule mpm_event_module/' /etc/httpd/conf/httpd.conf + sudo sed -i 's/#LoadModule mpm_prefork_module/LoadModule mpm_prefork_module/' /etc/httpd/conf/httpd.conf + log "\n# PHP-Konfiguration\nLoadModule php_module modules/libphp.so\nAddHandler php-script .php\nInclude conf/extra/php_module.conf" | sudo tee -a /etc/httpd/conf/httpd.conf >/dev/null + + sudo systemctl restart httpd + ;; + + centos|fedora) + log "${SYM_INFO} ${COLOR_ACTION}Installiere Apache/PHP (yum/dnf)...${COLOR_RESET}" + [[ "$current_distro" == "centos" ]] && sudo yum install -y epel-release + sudo yum install -y "${web_packages[centos]}" || { + log "${SYM_BAD} ${COLOR_ERROR}Installation fehlgeschlagen!${COLOR_RESET}"; + return 1; + } + sudo systemctl restart httpd + sudo firewall-cmd --permanent --add-service=http + sudo firewall-cmd --reload + ;; + esac + + # 3. PHP-Check (OHNE Dateianlage) + log "${SYM_INFO} ${COLOR_ACTION}Prüfe PHP-Konfiguration...${COLOR_RESET}" + php_check() { + log "${COLOR_HEADING}=== PHP-Status ===${COLOR_RESET}" + log "Version: ${COLOR_VALUE}$(php -r 'echo PHP_VERSION;')${COLOR_RESET}" + + declare -A modules=( + ["mysqli"]="MySQL-Datenbank" + ["gd"]="GD-Grafikbibliothek" + ["curl"]="cURL" + ["xml"]="XML-Unterstützung" + ["mbstring"]="Multibyte-Strings" + ) + + for mod in "${!modules[@]}"; do + if php -m | grep -q "^$mod$"; then + log "${SYM_OK} ${COLOR_OK}${modules[$mod]} (${mod})${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_ERROR}Fehlend: ${modules[$mod]} (${mod})${COLOR_RESET}" + fi + done + } + + # Führe Check aus und protokolliere Ausgabe + php_check | while IFS= read -r line; do log "$line"; done + + # 4. osWebinterface Deployment + if [[ -d "oswebinterface" ]]; then + log "${SYM_INFO} ${COLOR_ACTION}Kopiere osWebinterface...${COLOR_RESET}" + sudo cp -r oswebinterface/* /var/www/html/ + sudo chown -R www-data:www-data /var/www/html 2>/dev/null || sudo chown -R apache:apache /var/www/html + + log "${SYM_OK} ${COLOR_OK}osWebinterface erfolgreich deployt${COLOR_RESET}" + fi + + log "${COLOR_SUCCESS}Webserver-Setup abgeschlossen!${COLOR_RESET}" + blankline +} + +# function setup_email_server() { +# # SMTP-Server Konfiguration (z.B. mail.gridname.de) +# local smtp_server="mail.gridname.de" +# local sender_email="noresponse@gridname.de" +# local sender_password="DEIN_PASSWORT" # Passwort für noresponse@ + +# echo -e "\n\033[32m=== Konfiguriere E-Mail-Server für PHP mail() ===\033[0m" + +# # Postfix installieren +# sudo apt update +# sudo DEBIAN_FRONTEND=noninteractive apt install -y postfix mailutils + +# # Postfix als SMTP-Relay einrichten +# sudo tee /etc/postfix/main.cf > /dev/null <&2 + return 2 # Spezieller Fehlercode für ungültige Eingabe + fi + screen -list | grep -q "$target_session" # Rückgabewert 0 = läuft, 1 = nicht läuft +} + +function standalonestart() { + if is_opensim_running; then + echo "OpenSim läuft bereits (Screen: $SCREEN_NAME)." + else + echo "Starte OpenSim in screen '$SCREEN_NAME'..." + cd "$OPENSIM_DIR" || exit 1 + screen -fa -S "$SCREEN_NAME" -d -U -m dotnet OpenSim.dll + echo "OpenSim starten abgeschlossen." + fi + blankline +} + +function standalonestop() { + if is_opensim_running; then + echo "Sende Shutdown-Befehl an OpenSim..." + screen -S "$SCREEN_NAME" -p 0 -X stuff "$SHUTDOWN_CMD^M" + sleep 5 # Warte auf saubere Beendigung + if ! is_opensim_running; then + echo "OpenSim wurde gestoppt." + else + echo "Warnung: OpenSim reagiert nicht auf 'shutdown'. Versuche hartes Stoppen..." + screen -S "$SCREEN_NAME" -X quit + fi + else + echo "OpenSim läuft nicht." + fi + blankline +} + +# Standalone-Service-Neustart (ohne Logbereinigung) +function standalonerestart() { + standalonestop + sleep $Simulator_Stop_wait # Wartezeit für sauberen Shutdown + standalonestart +} + +function standalonestatus() { + if is_opensim_running; then + echo "✅ OpenSim läuft (Screen: $SCREEN_NAME)." + else + echo "❌ OpenSim läuft nicht." + fi +} + +function validate_sim_name() { + local sim_name=$1 + # Überprüfe ob der Name dem Muster sim[1-99] entspricht (case-sensitive) + if [[ ! "$sim_name" =~ ^sim([1-9]|[1-9][0-9])$ ]]; then + log "${SYM_BAD} ${COLOR_WARNING}Ungültiger Sim-Name! Bitte verwende sim1 bis sim99.${COLOR_RESET}" + return 1 + fi + return 0 +} + +# Einzelne Instanzen starten und stoppen + +function simstart() { + local sim_name="$1" + local sim_dir="${sim_name}/bin" + local max_wait=${Simulator_Start_wait:-10} # Default 10 Sekunden Timeout + + # 1. Validierung + if ! validate_sim_name "$sim_name"; then + log "${SYM_BAD} ${COLOR_ERROR}Ungültiger Simulationsname!${COLOR_RESET}" + return 1 + fi + + # 2. Prüfen ob die Simulation bereits läuft + if is_opensim_running "$sim_name"; then + log "${SYM_INFO} ${COLOR_WARNING}Simulation '${sim_name}' läuft bereits!${COLOR_RESET}" + blankline + return 0 + fi + + # 3. Verzeichnisprüfung + if [[ ! -d "$sim_dir" ]]; then + log "${SYM_BAD} ${COLOR_ERROR}Verzeichnis nicht gefunden: ${sim_dir}${COLOR_RESET}" + return 1 + fi + + # 4. Startversuch + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}${sim_name}${COLOR_RESET}" + if ! (cd "$sim_dir" && screen -fa -S "$sim_name" -d -U -m dotnet OpenSim.dll); then + log "${SYM_BAD} ${COLOR_ERROR}Start fehlgeschlagen!${COLOR_RESET}" + return 1 + fi + + # 5. Startüberprüfung mit Timeout + local waited=0 + while ! is_opensim_running "$sim_name" && ((waited < max_wait)); do + sleep 1 + ((waited++)) + echo -n "." + done + echo "" + + # 6. Ergebnis auswerten + if is_opensim_running "$sim_name"; then + log "${SYM_OK} ${COLOR_START}Simulation erfolgreich gestartet (${waited}s).${COLOR_RESET}" + blankline + return 0 + else + log "${SYM_BAD} ${COLOR_ERROR}Timeout: Simulation startet nicht (${max_wait}s)${COLOR_RESET}" + return 1 + fi +} + +function simstop() { + local simstop="$1" + local max_wait=${Simulator_Stop_wait:-15} # Default 15 Sekunden Timeout + + # 1. Validierung + if ! validate_sim_name "$simstop"; then + log "${SYM_BAD} ${COLOR_ERROR}Ungültiger Simulationsname!${COLOR_RESET}" + return 1 + fi + + # 2. Prüfen ob die Simulation läuft + if ! is_opensim_running "$simstop"; then + log "${SYM_INFO} ${COLOR_WARNING}Simulation '$simstop' ist nicht aktiv.${COLOR_RESET}" + blankline + return 0 + fi + + # 3. Stop-Befehl senden + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}${simstop}${COLOR_RESET}" + if ! screen -S "$simstop" -p 0 -X stuff "shutdown^M"; then + log "${SYM_BAD} ${COLOR_ERROR}Konnte Stop-Befehl nicht senden!${COLOR_RESET}" + return 1 + fi + + # 4. Graceful Shutdown mit Timeout + local waited=0 + while is_opensim_running "$simstop" && ((waited < max_wait)); do + sleep 1 + ((waited++)) + echo -n "." + done + echo "" + + # 5. Ergebnis auswerten + if is_opensim_running "$simstop"; then + log "${SYM_BAD} ${COLOR_ERROR}Timeout: Simulation reagiert nicht auf shutdown (${max_wait}s)${COLOR_RESET}" + log "${SYM_INFO} ${COLOR_WARNING}Versuche hartes Stoppen...${COLOR_RESET}" + screen -S "$simstop" -X quit && return 0 || return 1 + else + log "${SYM_OK} ${COLOR_STOP}Simulation sauber gestoppt (${waited}s).${COLOR_RESET}" + blankline + return 0 + fi +} + +function simrestart() { + local simrestart=$1 + if ! validate_sim_name "$simrestart"; then + exit 1 + fi + + simstop "$simrestart" + simstart "$simrestart" + echo + echo "OpenSim Restart abgeschlossen." +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Start Stop Grid +#?────────────────────────────────────────────────────────────────────────────────────────── + +#* OpenSim starten (robust → money → sim1 bis sim999) +function opensimstart() { + log "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}" + + # RobustServer starten + if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" + cd robust/bin || exit 1 + # -inifile=Robust.HG.ini + + screen -fa -S robustserver -d -U -m dotnet Robust.dll + cd - >/dev/null 2>&1 || exit 1 + sleep $RobustServer_Start_wait + else + log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" + fi + + # MoneyServer starten + if [[ -f "robust/bin/MoneyServer.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" + cd robust/bin || exit 1 + screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll + cd - >/dev/null 2>&1 || exit 1 + sleep $MoneyServer_Start_wait + else + log "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}MoneyServer.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" + fi + + # Sim-Regionen starten + for ((i=1; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}" + cd "$sim_dir" || continue + screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll + cd - >/dev/null 2>&1 || continue + sleep $Simulator_Start_wait + fi + done + echo "OpenSim starten abgeschlossen." + blankline +} +# Test OpenSim starten Parallel +function opensimstartParallel() { + log "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}" + + # 1. RobustServer (muss zuerst laufen) + if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" + (cd robust/bin && screen -fa -S robustserver -d -U -m dotnet Robust.dll) + sleep "$RobustServer_Start_wait" + else + log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" + fi + + # 2. MoneyServer (optional) + if [[ -f "robust/bin/MoneyServer.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" + (cd robust/bin && screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll) + sleep "$MoneyServer_Start_wait" + fi + + # 3. SIM1 ZUERST (sequentiell) + if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_START}(primäre Region)...${COLOR_RESET}" + (cd sim1/bin && screen -fa -S sim1 -d -U -m dotnet OpenSim.dll) + sleep "$Simulator_Start_wait" + else + log "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET}" + fi + + # 4. SIM2-SIM99 PARALLEL + log "${SYM_INFO} ${COLOR_START}Starte sekundäre Simulatoren parallel...${COLOR_RESET}" + + # Maximal 10 parallele Jobs + MAX_JOBS=10 + for ((i=2; i<=99; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then + + # Warten falls zu viele Jobs laufen + while (( $(jobs -p | wc -l) >= MAX_JOBS )); do + sleep 1 + done + + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}" + (cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll) & + fi + done + + wait # Warte auf alle Hintergrundjobs + log "${SYM_OK} ${COLOR_START}Alle Simulatoren gestartet.${COLOR_RESET}" + blankline +} + +#* OpenSim stoppen (sim999 bis sim1 → money → robust) +function opensimstop() { + log "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}" + + # Sim-Regionen stoppen + for ((i=999; i>=1; i--)); do + sim_dir="sim$i" + if screen -list | grep -q "$sim_dir"; then + screen -S "sim$i" -p 0 -X stuff "shutdown^M" + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" + sleep $Simulator_Stop_wait + fi + done + + # MoneyServer stoppen + if screen -list | grep -q "moneyserver"; then + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" + screen -S moneyserver -p 0 -X stuff "shutdown^M" + sleep $MoneyServer_Stop_wait + else + log "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET} ${COLOR_STOP}Überspringe Stopp.${COLOR_RESET}" + fi + + # RobustServer stoppen + if screen -list | grep -q "robust"; then + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" + screen -S robustserver -p 0 -X stuff "shutdown^M" + sleep $RobustServer_Stop_wait + else + log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET} ${COLOR_STOP}Überspringe Stopp.${COLOR_RESET}" + fi + echo "OpenSim stoppen abgeschlossen." + blankline +} + +# Das parallele Stoppen in der Reihenfolge sim999 → sim2 parallel, dann sim1 → MoneyServer → RobustServer +function opensimstopParallel() { + log "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}" + local MAX_PARALLEL=10 # Maximale parallele Stopp-Vorgänge + + # 1. Paralleles Stoppen von sim999 bis sim2 + log "${SYM_INFO} ${COLOR_STOP}Stoppe sekundäre Simulatoren parallel...${COLOR_RESET}" + for ((i=999; i>=2; i--)); do + sim_name="sim$i" + + # Warten falls zu viele parallele Jobs laufen + #while [ $(jobs -p | wc -l) -ge $MAX_PARALLEL ]; do + while [ "$(jobs -p | wc -l)" -ge $MAX_PARALLEL ]; do + sleep 0.5 + done + + if screen -list | grep -q "$sim_name"; then + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}$sim_name${COLOR_RESET}" + ( + screen -S "$sim_name" -p 0 -X stuff "shutdown^M" + sleep $Simulator_Stop_wait + ) & + fi + done + wait # Warte auf alle parallelen Stopp-Vorgänge + + # 2. Sim1 sequentiell stoppen + if screen -list | grep -q "sim1"; then + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_STOP}(primäre Region)...${COLOR_RESET}" + screen -S "sim1" -p 0 -X stuff "shutdown^M" + sleep $Simulator_Stop_wait + fi + + # 3. MoneyServer stoppen + if screen -list | grep -q "moneyserver"; then + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" + screen -S moneyserver -p 0 -X stuff "shutdown^M" + sleep $MoneyServer_Stop_wait + else + log "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" + fi + + # 4. RobustServer stoppen (zuletzt) + if screen -list | grep -q "robustserver"; then + log "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" + screen -S robustserver -p 0 -X stuff "shutdown^M" + sleep $RobustServer_Stop_wait + else + log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" + fi + + log "${SYM_OK} ${COLOR_STOP}Alle Dienste gestoppt.${COLOR_RESET}" + blankline +} + +# check_screens ist eine Grid Funktion und funktioniert nicht im Standalone. +function check_screens() { + # echo "Überprüfung der laufenden OpenSim-Prozesse..." + + restart_all=false + + # Überprüfen, ob RobustServer läuft + if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then + screenRO=$(screen -ls | grep -w "robustserver") + if [[ -z "$screenRO" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log + restart_all=true + else + echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft ✓" + fi + fi + + # Überprüfen, ob MoneyServer läuft + if [[ -d "robust/bin" && -f "robust/bin/MoneyServer.dll" ]];then + screenMoney=$(screen -ls | grep -w "moneyserver") + if [[ -z "$screenMoney" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log + restart_all=true + else + echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft ✓" + fi + fi + + # Überprüfen, ob sim1 läuft + if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then + screenSim1=$(screen -ls | grep -w "sim1") + if [[ -z "$screenSim1" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log + restart_all=true + else + echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft ✓" + fi + fi + + # Falls eines der kritischen Systeme ausgefallen ist, alles neu starten + if [[ "$restart_all" == true ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - Kritische Prozesse sind ausgefallen! OpenSim wird komplett neu gestartet." >> ProblemRestarts.log + # opensimstart + opensimrestart + return 0 + fi + + # Überprüfen, ob andere Regionen (sim2 bis sim999) einzeln neu gestartet werden müssen + for ((i=2; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then + screenSim=$(screen -ls | grep -w "sim$i") + if [[ -z "$screenSim" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft nicht und wird einzeln neu gestartet." >> ProblemRestarts.log + cd "$sim_dir" || continue + screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll + cd - >/dev/null 2>&1 || continue + sleep $Simulator_Start_wait + else + echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft ✓" + fi + fi + done + blankline +} + +# Falls ein Screen einmal nicht beenden will. +function simkill() { + local SIMKILL=$1 + local CONFIRM + + # Existenzprüfung + if ! screen -list | grep -q "$SIMKILL"; then + log "${SYM_BAD} ${COLOR_ERROR}Screen '${COLOR_SERVER}$SIMKILL${COLOR_ERROR}' nicht gefunden!${COLOR_RESET}" + return 1 + fi + + # Bestätigung + log "${SYM_WARNING} ${COLOR_WARNING}Warnung:${COLOR_RESET}" + read -rp "Soll Screen '${COLOR_SERVER}$SIMKILL${COLOR_RESET}' wirklich beendet werden? [y/N] " CONFIRM + [[ $CONFIRM =~ ^[Yy]$ ]] || { + log "${SYM_INFO} ${COLOR_ACTION}Abbruch durch Benutzer.${COLOR_RESET}" + return 1 + } + + # Erst ordnungsgemäß beenden versuchen + log "${SYM_WAIT} ${COLOR_ACTION}Versuche ordentliches Beenden...${COLOR_RESET}" + if screen -S "$SIMKILL" -X quit; then + log "${SYM_OK} ${COLOR_SUCCESS}Screen '${COLOR_SERVER}$SIMKILL${COLOR_SUCCESS}' erfolgreich beendet.${COLOR_RESET}" + return 0 + fi + + # Falls nötig, hart killen + log "${SYM_WARNING} ${COLOR_WARNING}Ordentliches Beenden fehlgeschlagen, erzwinge Kill...${COLOR_RESET}" + if screen -S "$SIMKILL" -X kill; then + log "${SYM_OK} ${COLOR_SUCCESS}Screen '${COLOR_SERVER}$SIMKILL${COLOR_SUCCESS}' wurde gekillt.${COLOR_RESET}" + return 0 + else + log "${SYM_BAD} ${COLOR_ERROR}Schwerer Fehler: Screen '${COLOR_SERVER}$SIMKILL${COLOR_ERROR}' konnte nicht beendet werden!${COLOR_RESET}" + return 1 + fi +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Erstellen eines OpenSimulators +#?────────────────────────────────────────────────────────────────────────────────────────── + +opensim_clone() { + # Stille Klon-Funktion mit automatischem Fallback + local max_retries=3 + local retry_delay=2 + + for ((i=1; i<=max_retries; i++)); do + # 1. Versuch: HTTPS (standard) + if git clone https://opensimulator.org/git/opensim opensim --quiet 2>/dev/null; then + return 0 + fi + + # 2. Versuch: Git-Protokoll (falls HTTPS blockiert) + if git clone git://opensimulator.org/git/opensim opensim --quiet 2>/dev/null; then + return 0 + fi + + # Bei Fehler temporäres Verzeichnis bereinigen + rm -rf opensim &>/dev/null + sleep $retry_delay + done + + return 1 +} + +function opensimgitcopy() { + log "${SYM_BOOK}${COLOR_HEADING} OpenSimulator GitHub-Verwaltung${COLOR_RESET}" + + # Zuerst versuchen, ein einfaches git pull durchzuführen, falls Repository existiert + if [[ -d "opensim/.git" ]]; then + log "${SYM_WAIT} ${COLOR_ACTION}Versuche einfaches Update via git pull...${COLOR_RESET}" + cd opensim || { + log "${SYM_BAD} ${COLOR_ERROR}Verzeichniswechsel fehlgeschlagen!${COLOR_RESET}" + return 1 + } + + old_head=$(git rev-parse HEAD) + if git pull origin master; then + if [ "$old_head" == "$(git rev-parse HEAD)" ]; then + log "${SYM_OK} ${COLOR_ACTION}Keine neuen Updates verfügbar.${COLOR_RESET}" + else + log "${SYM_OK} ${COLOR_SUCCESS}Update erfolgreich durchgeführt!${COLOR_RESET}" + fi + cd .. + + # Nach erfolgreichem Update Kompatibilität prüfen + check_dotnet_compatibility + # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() + versionrevision + log # Leerzeile für bessere Lesbarkeit + return 0 + else + log "${SYM_BAD} ${COLOR_WARNING}Einfaches Update fehlgeschlagen, fahre mit Standardverfahren fort...${COLOR_RESET}" + cd .. + fi + fi + + # Falls einfaches git pull nicht möglich ist, normale Abfrage durchführen + log "${COLOR_LABEL}Möchten Sie den OpenSimulator vom GitHub verwenden oder aktualisieren? (${COLOR_OK}[upgrade]${COLOR_LABEL}/new)${COLOR_RESET}" + read -r user_choice + user_choice=${user_choice:-upgrade} + + if [[ "$user_choice" == "new" ]]; then + if [[ -d "opensim" ]]; then + log "${COLOR_ACTION}Vorhandene OpenSimulator-Version wird gelöscht...${COLOR_RESET}" + rm -rf opensim + log "${SYM_OK} ${COLOR_ACTION}Alte OpenSimulator-Version wurde erfolgreich entfernt.${COLOR_RESET}" + fi + + log "${SYM_WAIT} ${COLOR_ACTION}OpenSimulator wird von GitHub geholt...${COLOR_RESET}" + if opensim_clone; then + log "${SYM_OK} ${COLOR_SUCCESS}Download erfolgreich!${COLOR_RESET}" + log "${SYM_WAIT} ${COLOR_ACTION}Überprüfe Repository-Integrität...${COLOR_RESET}" + + if check_repo_integrity "opensim"; then + log "${SYM_OK} ${COLOR_ACTION}Repository ist intakt.${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt!${COLOR_RESET}" + return 1 + fi + else + log "${SYM_BAD} ${COLOR_ERROR}Download fehlgeschlagen!${COLOR_RESET}" + log "${COLOR_WARNING}Bitte Netzwerkverbindung prüfen und später erneut versuchen.${COLOR_RESET}" + return 1 + fi + + elif [[ "$user_choice" == "upgrade" ]]; then + if [[ -d "opensim/.git" ]]; then + # Erneuter Versuch (falls vorheriger pull fehlgeschlagen) + cd opensim || return 1 + if git pull origin master; then + log "${SYM_OK} ${COLOR_SUCCESS}Update erfolgreich durchgeführt!${COLOR_RESET}" + cd .. + + # Nach erfolgreichem Update Kompatibilität prüfen + check_dotnet_compatibility + # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() + versionrevision + log # Leerzeile für bessere Lesbarkeit + return 0 + else + log "${SYM_BAD} ${COLOR_ERROR}Update fehlgeschlagen!${COLOR_RESET}" + cd .. + return 1 + fi + else + log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Kein Repository gefunden. Starte Neuinstallation...${COLOR_RESET}" + opensimgitcopy "new" + return $? + fi + else + log "${SYM_BAD} ${COLOR_ERROR}Ungültige Eingabe!${COLOR_RESET}" + return 1 + fi + + # .NET-Kompatibilität prüfen + check_dotnet_compatibility + # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() + versionrevision + + blankline +} + +check_dotnet_compatibility() { + cd opensim || return 1 + local dotnet_version + dotnet_version=$(dotnet --version 2>/dev/null | awk -F. '{print $1}') + + case $dotnet_version in + 6) + git checkout -q dotnet6 + log "${SYM_OK} ${COLOR_ACTION}Für .NET 6 konfiguriert.${COLOR_RESET}" + ;; + 7|8) + log "${SYM_OK} ${COLOR_ACTION}Kompatibel mit .NET $dotnet_version.${COLOR_RESET}" + ;; + *) + log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Keine .NET-Version erkannt. Verwende Standard.${COLOR_RESET}" + ;; + esac + cd .. +} + +function moneygitcopy() { + log "${COLOR_HEADING}💰 MoneyServer GitHub-Verwaltung${COLOR_RESET}" + + log "${COLOR_LABEL}Möchten Sie den MoneyServer vom GitHub verwenden oder aktualisieren? (${COLOR_OK}[upgrade]${COLOR_LABEL}/new)${COLOR_RESET}" + read -r user_choice + user_choice=${user_choice:-upgrade} + + if [[ "$user_choice" == "new" ]]; then + if [[ -d "opensimcurrencyserver" ]]; then + log "${COLOR_ACTION}Vorhandene MoneyServer-Version wird gelöscht...${COLOR_RESET}" + rm -rf opensimcurrencyserver + log "${SYM_OK} ${COLOR_ACTION}Alte MoneyServer-Version wurde erfolgreich entfernt.${COLOR_RESET}" + fi + + log "${COLOR_ACTION}MONEYSERVER: MoneyServer wird vom GIT geholt...${COLOR_RESET}" + if ! git clone https://github.com/ManfredAabye/opensimcurrencyserver-dotnet.git opensimcurrencyserver; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" + return 1 + fi + + if ! check_repo_integrity "opensimcurrencyserver"; then + log "${SYM_BAD} ${COLOR_ERROR}MoneyServer-Repository beschädigt!${COLOR_RESET}" + return 1 + fi + + log "${SYM_OK} ${COLOR_ACTION}MoneyServer wurde erfolgreich heruntergeladen.${COLOR_RESET}" + + elif [[ "$user_choice" == "upgrade" ]]; then + if [[ -d "opensimcurrencyserver/.git" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Repository gefunden. Aktualisiere mit 'git pull'...${COLOR_RESET}" + cd opensimcurrencyserver || { log "${SYM_BAD} ${COLOR_ERROR}Fehler: Kann nicht ins Verzeichnis wechseln!${COLOR_RESET}"; return 1; } + + # Branch-Erkennung mit Fehlerbehandlung + branch_name=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') + if [ -z "$branch_name" ]; then + branch_name="master" + log "${COLOR_WARNING}Standard-Branch 'master' wird verwendet.${COLOR_RESET}" + fi + + old_head=$(git rev-parse HEAD) + + if ! git pull origin "$branch_name"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Aktualisieren!${COLOR_RESET}" + cd .. + return 1 + fi + + if [ "$old_head" == "$(git rev-parse HEAD)" ]; then + log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}MoneyServer ist bereits aktuell.${COLOR_RESET}" + else + log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}MoneyServer erfolgreich aktualisiert!${COLOR_RESET}" + fi + + if ! check_repo_integrity; then + log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt nach Pull!${COLOR_RESET}" + cd .. + return 1 + fi + + cd .. + else + log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}MoneyServer-Verzeichnis nicht gefunden. Klone Repository neu...${COLOR_RESET}" + if ! git clone https://github.com/ManfredAabye/opensimcurrencyserver-dotnet.git opensimcurrencyserver; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" + return 1 + fi + log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}MoneyServer erfolgreich heruntergeladen!${COLOR_RESET}" + fi + else + log "${SYM_BAD} ${COLOR_ERROR}Abbruch: Keine Aktion durchgeführt.${COLOR_RESET}" + return 1 + fi + + # Verbesserte Dateikopierfunktion mit Prüfungen + copy_with_checks() { + local src=$1 + local dest=$2 + + if [ ! -d "$src" ]; then + log "${SYM_BAD} ${COLOR_ERROR}Quellverzeichnis $src nicht gefunden!${COLOR_RESET}" + return 1 + fi + + mkdir -p "$dest" + if ! cp -r "$src" "$dest"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Kopieren von $src!${COLOR_RESET}" + return 1 + fi + + log "${SYM_OK} ${COLOR_ACTION}Erfolgreich kopiert: $src → $dest${COLOR_RESET}" + return 0 + } + + # Kopiervorgänge mit Fehlerbehandlung + copy_with_checks "opensimcurrencyserver/addon-modules" "opensim/" || return 1 + copy_with_checks "opensimcurrencyserver/bin" "opensim/" || return 1 + + blankline + return 0 +} + +function osslscriptsgit() { + log "${COLOR_HEADING}📜 OSSL Beispiel-Skripte GitHub-Verwaltung${COLOR_RESET}" + + log "${COLOR_LABEL}Möchten Sie die OpenSim OSSL Beispiel-Skripte vom GitHub verwenden oder aktualisieren? (${COLOR_OK}[upgrade]${COLOR_LABEL}/new)${COLOR_RESET}" + read -r user_choice + user_choice=${user_choice:-upgrade} + + repo_name="opensim-ossl-example-scripts" + repo_url="https://github.com/ManfredAabye/opensim-ossl-example-scripts.git" + + if [[ "$user_choice" == "new" ]]; then + if [[ -d "$repo_name" ]]; then + log "${COLOR_ACTION}Vorhandene Version wird gelöscht...${COLOR_RESET}" + rm -rf "$repo_name" + log "${SYM_OK} ${COLOR_ACTION}Alte Version wurde erfolgreich entfernt.${COLOR_RESET}" + fi + + log "${COLOR_ACTION}Beispiel-Skripte werden vom GitHub heruntergeladen...${COLOR_RESET}" + if ! git clone "$repo_url" "$repo_name"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" + return 1 + fi + + if ! check_repo_integrity "$repo_name"; then + log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt!${COLOR_RESET}" + return 1 + fi + + log "${SYM_OK} ${COLOR_ACTION}Repository wurde erfolgreich heruntergeladen.${COLOR_RESET}" + + elif [[ "$user_choice" == "upgrade" ]]; then + if [[ -d "$repo_name/.git" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Repository gefunden. Aktualisiere mit 'git pull'...${COLOR_RESET}" + cd "$repo_name" || { log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Wechsel ins Verzeichnis!${COLOR_RESET}"; return 1; } + + branch_name=$(git symbolic-ref refs/remotes/origin/HEAD 2>/dev/null | sed 's@^refs/remotes/origin/@@') + [ -z "$branch_name" ] && branch_name="main" + + old_head=$(git rev-parse HEAD) + + if ! git pull origin "$branch_name"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Pull!${COLOR_RESET}" + cd .. + return 1 + fi + + if [ "$old_head" != "$(git rev-parse HEAD)" ]; then + log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Neue Updates wurden installiert.${COLOR_RESET}" + else + log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Repository ist bereits aktuell.${COLOR_RESET}" + fi + + if ! check_repo_integrity; then + log "${SYM_BAD} ${COLOR_ERROR}Repository beschädigt nach Pull!${COLOR_RESET}" + cd .. + return 1 + fi + + cd .. + else + log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Verzeichnis nicht gefunden oder kein Git-Repo. Klone Repository neu...${COLOR_RESET}" + if ! git clone "$repo_url" "$repo_name"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Klonen!${COLOR_RESET}" + return 1 + fi + log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Repository wurde erfolgreich heruntergeladen.${COLOR_RESET}" + fi + else + log "${SYM_BAD} ${COLOR_ERROR}Abbruch: Keine Aktion durchgeführt.${COLOR_RESET}" + return 1 + fi + + # Verbesserte Kopierfunktion + safe_copy() { + local src=$1 + local dest=$2 + + if [ ! -e "$src" ]; then + log "${SYM_BAD} ${COLOR_ERROR}Quelle '$src' existiert nicht!${COLOR_RESET}" + return 1 + fi + + mkdir -p "$(dirname "$dest")" + if ! cp -r "$src" "$dest"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Kopieren von '$src'!${COLOR_RESET}" + return 1 + fi + + log "${SYM_OK} ${COLOR_ACTION}Erfolgreich kopiert: $src → $dest${COLOR_RESET}" + return 0 + } + + # Zielverzeichnisse erstellen mit Fehlerbehandlung + mkdir -p opensim/bin/assets/ || { log "${SYM_BAD} ${COLOR_ERROR}Konnte Verzeichnis nicht erstellen!${COLOR_RESET}"; return 1; } + mkdir -p opensim/bin/inventory/ || { log "${SYM_BAD} ${COLOR_ERROR}Konnte Verzeichnis nicht erstellen!${COLOR_RESET}"; return 1; } + + # Kopiervorgänge mit Fehlerbehandlung + safe_copy "$repo_name/ScriptsAssetSet" "opensim/bin/assets/" || return 1 + safe_copy "$repo_name/inventory/ScriptsLibrary" "opensim/bin/inventory/" || return 1 + + blankline + return 0 +} + +####################################### + +#* Das ist erst halb fertig. +function ruthrothgit() { + # Schritt 1 das bereitstellen der Pakete zur weiteren bearbeitung. + log "${COLOR_HEADING}👥 Ruth & Roth Avatar-Assets Vorbereitung${COLOR_RESET}" + + base_dir="ruthroth" + mkdir -p "$base_dir" + + declare -A repos=( + ["Ruth2"]="https://github.com/ManfredAabye/Ruth2.git" + ["Roth2"]="https://github.com/ManfredAabye/Roth2.git" + ) + + for avatar in "${!repos[@]}"; do + repo_url="${repos[$avatar]}" + target_dir="$avatar" + + if [[ ! -d "$target_dir" ]]; then + log " ${COLOR_ACTION}➜ Klone ${COLOR_SERVER}$avatar${COLOR_ACTION} von GitHub...${COLOR_RESET}" + git clone "$repo_url" "$target_dir" && log " ${COLOR_OK}${SYM_OKNN} ${COLOR_SERVER}$avatar${COLOR_RESET} ${COLOR_ACTION}wurde heruntergeladen.${COLOR_RESET}" + else + log " ${COLOR_OK}${SYM_OKNN} ${COLOR_SERVER}$avatar${COLOR_RESET} ${COLOR_ACTION}ist bereits vorhanden, überspringe Download.${COLOR_RESET}" + fi + + # Kopiere nur die relevanten IAR-Dateien direkt nach ruthroth + log " ${COLOR_ACTION}➜ Kopiere benötigte IAR-Dateien nach ${COLOR_DIR}$base_dir${COLOR_ACTION}...${COLOR_RESET}" + cp "$target_dir/Artifacts/IAR/"*.iar "$base_dir/" 2>/dev/null && log " ${SYM_OK} IAR-Dateien von ${COLOR_SERVER}$avatar${COLOR_RESET} kopiert.${COLOR_RESET}" + done + + # Kopiere das updatelibrary.py-Skript ins Hauptverzeichnis ruthroth + log " ${COLOR_ACTION}➜ Kopiere updatelibrary.py nach ${COLOR_DIR}$base_dir${COLOR_ACTION}...${COLOR_RESET}" + cp "updatelibrary.py" "$base_dir/" && log " ${SYM_OK} updatelibrary.py wurde kopiert.${COLOR_RESET}" + + echo "Verzeichniswechsel in $base_dir" + + # Wechsel ins ruthroth-Verzeichnis + cd "$base_dir" || { log "${SYM_BAD} Fehler beim Wechsel ins Verzeichnis ${COLOR_DIR}$base_dir${COLOR_RESET}"; return 1; } + + # Entpacke die IAR-Dateien direkt in ruthroth + log " ${COLOR_ACTION}➜ Entpacke IAR-Pakete in ${COLOR_DIR}$base_dir${COLOR_ACTION}...${COLOR_RESET}" + for iar_file in *.iar; do + if [[ -f "$iar_file" ]]; then + target_dir="${iar_file%.iar}" # Erstellt Verzeichnisname basierend auf Dateiname ohne .iar + mkdir -p "$target_dir" + tar -xzf "$iar_file" -C "$target_dir/" && log " ✓ ${iar_file} entpackt nach ${target_dir}" + else + log " ${SYM_WARNING} IAR-Datei ${iar_file} nicht gefunden. Überspringe..." + fi + done + + log "${COLOR_OK}${SYM_OKNN} ${COLOR_ACTION}Grundlage für die OpenSimulator-Pakete wurde erfolgreich erstellt!${COLOR_RESET}" + + # Schritt 2 die verwendung von updatelibrary.py. + cd ruthroth + python3 updatelibrary.py -n "Roth2-v1" -s "Roth2-v1" -a Roth2-v1 -i Roth2-v1 + python3 updatelibrary.py -n "Roth2-v2" -s "Roth2-v2" -a Roth2-v2 -i Roth2-v2 + python3 updatelibrary.py -n "Ruth2-v3" -s "Ruth2-v3" -a Ruth2-v3 -i Ruth2-v3 + python3 updatelibrary.py -n "Ruth2-v4" -s "Ruth2-v4" -a Ruth2-v4 -i Ruth2-v4 + cd .. + # Schritt 3 das kopieren der Daten. Das einfügen der Daten in den Dateien ähnlich wie bei PBR. +} + +# Es werden die Konfiguartionen jetzt auch geändert. +function pbrtexturesgit() { + log "${COLOR_HEADING}🎨 PBR Texturen Installation${COLOR_RESET}" + + textures_zip_url="https://github.com/ManfredAabye/OpenSim_PBR_Textures/releases/download/PBR/OpenSim_PBR_Textures.zip" + zip_file="OpenSim_PBR_Textures.zip" + unpacked_dir="OpenSim_PBR_Textures" + target_dir="opensim" + + # ZIP herunterladen, wenn nicht vorhanden + if [[ ! -f "$zip_file" ]]; then + log "${COLOR_ACTION}Lade OpenSim PBR Texturen herunter...${COLOR_RESET}" + if ! wget -q --show-progress -O "$zip_file" "$textures_zip_url"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Herunterladen der Texturen!${COLOR_RESET}" + return 1 + fi + log "${SYM_OK} ${COLOR_ACTION}Download abgeschlossen: ${COLOR_DIR}$zip_file${COLOR_RESET}" + else + log "${SYM_OK} ${COLOR_ACTION}ZIP-Datei bereits vorhanden: ${COLOR_DIR}$zip_file${COLOR_RESET}" + fi + + # Entpacken, wenn Verzeichnis noch nicht existiert + if [[ ! -d "$unpacked_dir" ]]; then + log "${COLOR_ACTION}Entpacke Texturen nach ${COLOR_DIR}$unpacked_dir${COLOR_ACTION}...${COLOR_RESET}" + unzip -q "$zip_file" -d . + log "${SYM_OK} ${COLOR_ACTION}Entpackt.${COLOR_RESET}" + else + log "${SYM_OK} ${COLOR_ACTION}Verzeichnis ${COLOR_DIR}$unpacked_dir${COLOR_ACTION} existiert bereits – überspringe Entpacken.${COLOR_RESET}" + fi + + # Kopieren nach opensim/bin + if [[ -d "$unpacked_dir/bin" ]]; then + log "${COLOR_ACTION}Kopiere Texturen nach ${COLOR_DIR}$target_dir${COLOR_ACTION}...${COLOR_RESET}" + cp -r "$unpacked_dir/bin" "$target_dir" + log "${SYM_OK} ${COLOR_ACTION}Texturen erfolgreich installiert in ${COLOR_DIR}$target_dir${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_ERROR}Verzeichnis ${COLOR_DIR}$unpacked_dir/bin${COLOR_ERROR} nicht gefunden!${COLOR_RESET}" + return 1 + fi + + local asset_sets_file="opensim/bin/assets/AssetSets.xml" + local libraries_file="opensim/bin/inventory/Libraries.xml" + + # Funktion zur Überprüfung und Hinzufügung eines Eintrags + add_xml_section() { + local file="$1" + local section_name="$2" + local content="$3" + + # Überprüfen ob der Abschnitt bereits existiert + if ! grep -q "
" "$file"; then + # Abschnitt vor einfügen + sed -i "s||
\n$content\n
\n|" "$file" + echo "Added $section_name to $file" + else + echo "$section_name already exists in $file - no changes made" + fi + } + + # AssetSets.xml bearbeiten + add_xml_section "$asset_sets_file" "PBR Textures AssetSet" \ + " " + + # Libraries.xml bearbeiten + add_xml_section "$libraries_file" "PBRTextures Library" \ + " \n " + + blankline + return 0 +} + +function osWebinterfacegit() { + log "${COLOR_HEADING}🌐 Webinterface Installation${COLOR_RESET}" + + webverzeichnis="oswebinterface" + + # Abfrage zur Installation mit Default "Nein" + log "${COLOR_LABEL}Möchten Sie das OpenSim Webinterface installieren? ()j/N) ${COLOR_RESET} [n]" + read -r install_webinterface + if [[ ! "$install_webinterface" =~ ^[jJ][aA]?$ ]]; then + log "${COLOR_INFO}Installation abgebrochen (Default: Nein)${COLOR_RESET}" + blankline + return 0 + fi + + setup_webserver + + # 1. PHP-Check mit Distro-Erkennung + if ! command -v php &>/dev/null; then + log "${SYM_WARNING} ${COLOR_WARNING}PHP ist nicht installiert!${COLOR_RESET}" + + # Distro-Erkennung + # shellcheck source=/dev/null + source /etc/os-release + case $ID in + debian|ubuntu|linuxmint|pop|mx|zorin|elementary) + pkg_cmd="sudo apt-get install -y php php-mysql php-gd php-curl" + ;; + arch|manjaro) + pkg_cmd="sudo pacman -S --noconfirm php php-gd php-curl" + ;; + fedora|centos|rhel) + pkg_cmd="sudo dnf install -y php php-mysqlnd php-gd php-common" + ;; + opensuse|sles) + pkg_cmd="sudo zypper install -y php7 php7-mysql php7-gd php7-curl" + ;; + *) + log "${SYM_BAD} ${COLOR_ERROR}Unterstützte Distribution nicht erkannt!${COLOR_RESET}" + echo "Manuell installieren: php php-mysql php-gd php-curl" + return 1 + ;; + esac + + log "PHP auf ${PRETTY_NAME} installieren? (j/n) " + read -r install_php + if [[ "$install_php" =~ ^[jJ] ]]; then + log "${COLOR_ACTION}Installiere PHP... (${pkg_cmd})${COLOR_RESET}" + if ! eval "$pkg_cmd"; then + log "${SYM_BAD} ${COLOR_ERROR}PHP-Installation fehlgeschlagen!${COLOR_RESET}" + return 1 + fi + log "${COLOR_OK}${SYM_OKNN} PHP erfolgreich installiert!${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_ERROR}Abbruch: PHP ist erforderlich.${COLOR_RESET}" + return 1 + fi + else + log "${COLOR_OK}${SYM_OKNN} PHP ist installiert ($(php -v | head -n 1))${COLOR_RESET}" + fi + + # 2. Webverzeichnis-Check mit automatischer User/Group-Erkennung + local webroot="/var/www/html" + [[ -d "/var/www" && ! -d "$webroot" ]] && webroot="/var/www" # Fallback für einige Distros + + if [[ ! -d "$webroot" ]]; then + log "${SYM_BAD} ${COLOR_ERROR}Webroot nicht gefunden in:${COLOR_RESET}" + echo "/var/www/html oder /var/www" + echo "Tipp: Apache/Nginx zuerst installieren" + return 1 + fi + + # Bestimme den richtigen Benutzer und Gruppe basierend auf existierenden Dateien + local target_user target_group + # Suche nach einer existierenden Datei oder Verzeichnis im Webroot + sample_file=$(find "$webroot" -maxdepth 1 -type f -print -quit 2>/dev/null || true) + sample_dir=$(find "$webroot" -maxdepth 1 -type d ! -path "$webroot" -print -quit 2>/dev/null || true) + + if [ -n "$sample_file" ]; then + target_user=$(stat -c '%U' "$sample_file") + target_group=$(stat -c '%G' "$sample_file") + elif [ -n "$sample_dir" ]; then + target_user=$(stat -c '%U' "$sample_dir") + target_group=$(stat -c '%G' "$sample_dir") + else + # Fallback: Standard-Webserver-User je nach Distribution + # shellcheck source=/dev/null + source /etc/os-release + case $ID in + debian|ubuntu|linuxmint|pop|mx|zorin|elementary) + target_user="www-data" + target_group="www-data" + ;; + arch|manjaro) + target_user="http" + target_group="http" + ;; + fedora|centos|rhel) + target_user="apache" + target_group="apache" + ;; + opensuse|sles) + target_user="wwwrun" + target_group="www" + ;; + *) + target_user="www-data" + target_group="www-data" + ;; + esac + fi + + # 3. Git-Operationen + if [[ ! -d "oswebinterface" ]]; then + git clone https://github.com/ManfredAabye/oswebinterface.git oswebinterface || return 1 + else + cd oswebinterface || return 1 + git pull origin "$(git symbolic-ref refs/remotes/origin/HEAD | sed 's@^refs/remotes/origin/@@')" || return 1 + cd .. + fi + + # 4. Deployment mit korrekten Berechtigungen + log "${COLOR_ACTION}Kopiere Webinterface nach ${webroot}/${webverzeichnis}...${COLOR_RESET}" + if ! sudo cp -r "oswebinterface" "$webroot/$webverzeichnis"; then + log "${SYM_BAD} ${COLOR_ERROR}Kopieren fehlgeschlagen!${COLOR_RESET}" + return 1 + fi + + log "${COLOR_ACTION}Setze Besitzer auf ${target_user}:${target_group}...${COLOR_RESET}" + if ! sudo chown -R "$target_user:$target_group" "$webroot/$webverzeichnis"; then + log "${SYM_BAD} ${COLOR_ERROR}Besitzer ändern fehlgeschlagen!${COLOR_RESET}" + return 1 + fi + + log "${COLOR_ACTION}Setze Dateiberechtigungen...${COLOR_RESET}" + if ! sudo find "$webroot/$webverzeichnis" -type d -exec chmod 755 {} \; || \ + ! sudo find "$webroot/$webverzeichnis" -type f -exec chmod 644 {} \; ; then + log "${SYM_BAD} ${COLOR_ERROR}Berechtigungen setzen fehlgeschlagen!${COLOR_RESET}" + return 1 + fi + + log "${COLOR_OK}${SYM_OKNN} Erfolgreich installiert nach: ${COLOR_DIR}$webroot/$webverzeichnis${COLOR_RESET}" + log " Benutzer/Gruppe: ${COLOR_INFO}$target_user:$target_group${COLOR_RESET}" + blankline + return 0 +} + +function versionrevision() { + file="opensim/OpenSim/Framework/VersionInfo.cs" + + #xflavour="Unknown" + #xflavour="Dev" + #xflavour="RC1" + #xflavour="RC2" + #xflavour="RC3" + #xflavour="Release" + #xflavour="Post_Fixes" + xflavour="Extended" + + if [[ ! -f "$file" ]]; then + log "${SYM_BAD} ${COLOR_ERROR}Datei nicht gefunden: ${COLOR_DIR}$file${COLOR_RESET}" + return 1 + fi + + log "${SYM_OK} ${COLOR_ACTION}Bearbeite Datei: ${COLOR_DIR}$file${COLOR_RESET}" + + # Ändere Flavour.Dev + sed -i 's/public const Flavour VERSION_FLAVOUR = Flavour\.[^;]*;/public const Flavour VERSION_FLAVOUR = Flavour.'"$xflavour"';/' "$file" + + # Entferne "Nessie" aus dem Versions-String + sed -i 's/OpenSim {versionNumber} Nessie {flavour}/OpenSim {versionNumber} {flavour}/' "$file" + + log "${SYM_OK} ${COLOR_ACTION}Änderungen zu $xflavour wurden erfolgreich vorgenommen.${COLOR_RESET}" + blankline + return 0 +} + +function generate_name() { + # Arrays mit Namensbestandteilen (alle einzigartig) + + local firstnames=( + # Vornamen + "Mystic" "Arcane" "Eldritch" "Enigmatic" "Esoteric" "Occult" "Cryptic" "Celestial" "Astral" "Ethereal" + "Luminous" "Radiant" "Prismatic" "Iridescent" "Phantasmal" "Spectral" "Otherworldly" "Transcendent" "Timeless" "Unearthly" + "Enchanted" "Charmed" "Bewitched" "Mythic" "Legendary" + "Verdant" "Sylvan" "Petrified" "Thundering" "Whispering" "Howling" "Roaring" "Rumbling" "Crystalline" "Obsidian" + "Amber" "Jade" "Sapphire" "Emerald" "Ruby" "Topaz" "Opaline" "Pearlescent" "Gilded" "Argent" + "Solar" "Lunar" "Stellar" "Nebular" "Galactic" + "Aether" "Runeweaver" "Dragonheart" "Moonshadow" "Spellbinder" "Witchbloom" "Grimoire" "Shadowalker" "Starborn" "Voidwhisper" + "Dreamwalker" "Fatesender" "Glyphborn" "Hollowveil" "Ivyroot" "Jadewhisper" "Kindlespark" "Lorekeeper" "Netherflame" "Oathbound" + "Pixieglen" "Quicksilver" "Ravenoak" "Silvershade" "Twilightthorn" + "Aerendyl" "Beltharion" "Celeborn" "Diorath" "Elrondar" "Faelivrin" "Galadhor" "Haldirion" "Ithilwen" "Jarathmel" + "Kelebrind" "Lothmiriel" "Melianthar" "Nimlothiel" "Oropherion" "Pelenor" "Quelamar" "Rivendell" "Silmarion" "Thranduvar" + "Ulmoen" "Vanyarion" "Windathar" "Xylanthir" "Yavanniel" + "Andromeda" "Beowulf" "Cybernova" "Deusex" "Eclipse" "Frostbyte" "Gigawatt" "Hyperion" "Io" "Jupiter" + "Krypton" "Lunarc" "Megatron" "Nebula" "Orion" "Pulsar" "Quantum" "Robodoc" "Starbuck" "Titan" + "Uranus" "Vortex" "Warpcore" "Xenon" "Zenith" + ) + + local lastnames=( + # Nachnamen + "Forest" "Grove" "Copse" "Thicket" "Wildwood" "Jungle" "Rainforest" "Mangrove" "Taiga" "Tundra" + "Mountain" "Peak" "Summit" "Cliff" "Crag" "Bluff" "Mesa" "Plateau" "Canyon" "Ravine" + "Valley" "Dale" "Glen" "Hollow" "Basin" + "River" "Stream" "Brook" "Creek" "Fjord" "Lagoon" "Estuary" "Delta" "Bayou" "Wetland" + "Oasis" "Geyser" "Spring" "Well" "Aquifer" + "Observatory" "Planetarium" "Orrery" "Reflectory" "Conservatory" "Atrium" "Rotunda" "Gazebo" "Pavilion" "Terrace" + "Ashenwood" "Bramblethorn" "Cliffhaven" "Dewspark" "Emberglade" "Frostvein" "Goldleaf" "Hailstone" "Ironbark" "Jasperridge" + "Kelpstrand" "Lavafall" "Mossgrip" "Nettlebrook" "Oakenshield" "Pinecrest" "Quartzpeak" "Rimefrost" "Stormbreak" "Tidepool" + "Umbravale" "Vinecreep" "Willowshade" "Xylem" "Yewroot" + "Aranel" "Beleriand" "Cirdan" "Doriath" "Eregion" "Fangorn" "Gondolin" "Hithlum" "Imladris" "Jarngard" + "Kementari" "Lorien" "Mirkwood" "Nargothrond" "Osgiliath" "Pelargir" "Quendi" "Rhosgobel" "Sindar" "Tirion" + "Undomiel" "Valinor" "Westfold" "Xandoria" "Yavanna" + "Axiom" "Borg" "Coruscant" "Dyson" "Expanse" "Federation" "Genesis" "Horizon" "Infinity" "Jovian" + "Kessel" "Lazarus" "Matrix" "Nostromo" "Outland" "Prometheus" "Quadrant" "Rapture" "Serenity" "Trifid" + "Umbra" "Voyager" "Weyland" "Xenomorph" "Zodiac" + ) + + gennamefirst="${firstnames[$RANDOM % ${#firstnames[@]}]}" # übergebe das an generate_all_name() + gennamesecond="${lastnames[$RANDOM % ${#lastnames[@]}]}" # übergebe das an generate_all_name() + +} +function generate_all_name() { + # Alle Namen und Bezeichnungen für die Installation erstellen das dient dazu das die Namen im gesamten Programm verwendet werden können. + # Benutzername Vorname Nachname + generate_name + genFirstname="${gennamefirst}" + generate_name + genLastname="${gennamesecond}" + echo "$gennamefirst" + echo "$gennamesecond" + + generate_name + # database_setup + genDatabaseUserName="${gennamefirst}${gennamesecond}$((RANDOM % 900 + 100))" + echo "$genDatabaseUserName" + + # generate_name + # # Neue Region + # genRegionName="${gennamefirst}${gennamesecond}$((RANDOM % 900 + 100))" + # echo "$genRegionName" + + generate_name + genGridName="${gennamesecond}Grid" + echo "$genGridName" + + # Test Ausgabe der Variablen + #echo "genFirstname='${genFirstname}'" + #echo "genLastname='${genLastname}'" + #echo "genDatabaseUserName='${genDatabaseUserName}'" + #echo "genRegionName='${genRegionName}'" + #echo "genGridName='${genGridName}'" + #echo "${names[$RANDOM % ${#names[@]}]}" +} + +function opensimbuild() { + log "${COLOR_HEADING}🏗️ OpenSimulator Build-Prozess${COLOR_RESET}" + + log "${COLOR_LABEL}Möchten Sie den OpenSimulator jetzt erstellen? (${COLOR_OK}[ja]${COLOR_LABEL}/nein)${COLOR_RESET}" + read -r user_choice + + user_choice=${user_choice:-ja} + + if [[ "$user_choice" == "ja" ]]; then + if [[ -d "opensim" ]]; then + cd opensim || { log "${SYM_BAD} ${COLOR_ERROR}Fehler: Verzeichnis 'opensim' nicht gefunden.${COLOR_RESET}"; return 1; } + log "${COLOR_ACTION}Starte Prebuild-Skript...${COLOR_RESET}" + bash runprebuild.sh + log "${COLOR_ACTION}Baue OpenSimulator...${COLOR_RESET}" + dotnet build --configuration Release OpenSim.sln + log "${SYM_OK} ${COLOR_ACTION}OpenSimulator wurde erfolgreich erstellt.${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_ERROR}OpenSim Build Fehler: Das Verzeichnis 'opensim' existiert nicht.${COLOR_RESET}" + return 1 + fi + else + log "${SYM_BAD} ${COLOR_ERROR}Abbruch: OpenSimulator wird nicht erstellt.${COLOR_RESET}" + fi + # Wer in ein Verzeichnis wechselt sollte auch wieder zur vorherigen Verzeichnis wechseln! + cd .. + blankline +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Erstellen eines OpenSimulators Grids +#?────────────────────────────────────────────────────────────────────────────────────────── + +function removeconfigfiles() { + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + # Erstelle Backup wenn Datei existiert + if [[ -f "$ini_file" ]]; then + #echo "$(date +'%d.%m.%Y')_$(date +'%H:%M:%S')" + backup_file="${ini_file}.$(date +'%d.%m.%Y')_$(date +'%H:%M:%S').bak" + sudo mv -f "$ini_file" "$backup_file" + fi +} + +function createdirectory() { + log "${COLOR_HEADING}📂 Verzeichniserstellung${COLOR_RESET}" + + log "${COLOR_LABEL}Möchten Sie einen Gridserver oder einen Regionsserver erstellen? (${COLOR_OK}[grid]${COLOR_LABEL}/region)${COLOR_RESET}" + read -r server_type + + # Standardmäßig Gridserver wählen, falls keine Eingabe erfolgt + server_type=${server_type:-grid} + + if [[ "$server_type" == "grid" ]]; then + log "${COLOR_ACTION}Erstelle robust Verzeichnis...${COLOR_RESET}" + mkdir -p robust/bin + log "${SYM_OK} ${COLOR_ACTION}Robust Verzeichnis wurde erstellt.${COLOR_RESET}" + + # Nach der Erstellung des Gridservers auch die Regionsserver erstellen lassen + log "${COLOR_LABEL}Wie viele Regionsserver benötigen Sie? ${COLOR_OK}[1]${COLOR_RESET}" + read -r num_regions + # Standardmäßig 1 Region wählen, falls keine Eingabe erfolgt + num_regions=${num_regions:-1} + log "${SYM_OK} ${COLOR_ACTION}Sie haben $num_regions Regionsserver gew‰hlt.${COLOR_RESET}" + + elif [[ "$server_type" == "region" ]]; then + log "${COLOR_LABEL}Wie viele Regionsserver benötigen Sie? ${COLOR_OK}[1]${COLOR_RESET}" + read -r num_regions + log "${SYM_OK} ${COLOR_ACTION}Sie haben $num_regions Regionsserver gew‰hlt.${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_ERROR}Ungültige Eingabe. Bitte geben Sie 'grid' oder 'region' ein.${COLOR_RESET}" + return 1 + fi + + # Überprüfen, ob die Anzahl der Regionsserver bis 999 geht + if [[ "$num_regions" =~ ^[0-9]+$ && "$num_regions" -le 999 ]]; then + for ((i=1; i<=num_regions; i++)); do + dir_name="sim$i" + if [[ ! -d "$dir_name" ]]; then + mkdir -p "$dir_name/bin" + log "${SYM_OK} ${COLOR_DIR}$dir_name${COLOR_RESET} ${COLOR_ACTION}wurde erstellt.${COLOR_RESET}" + sleep 1 + else + log "${SYM_OK} ${COLOR_DIR}$dir_name${COLOR_RESET} ${COLOR_WARNING}existiert bereits und wird übersprungen.${COLOR_RESET}" + fi + done + else + log "${SYM_BAD} ${COLOR_ERROR}Ungültige Anzahl an Regionsserver. Bitte geben Sie eine gültige Zahl zwischen 1 und 999 ein.${COLOR_RESET}" + fi + blankline +} + +function opensimcopy() { + log "${COLOR_HEADING}${SYM_PACKAGE} OpenSim Dateikopie${COLOR_RESET}" + + # Prüfen, ob das Verzeichnis "opensim" existiert + if [[ ! -d "opensim" ]]; then + log "${SYM_BAD} ${COLOR_ERROR}OpenSim Copy Fehler: Das Verzeichnis 'opensim' existiert nicht.${COLOR_RESET}" + return 1 + fi + + # Prüfen, ob das Unterverzeichnis "opensim/bin" existiert + if [[ ! -d "opensim/bin" ]]; then + log "${SYM_BAD} ${COLOR_ERROR}OpenSim Copy Fehler: Das Verzeichnis 'opensim/bin' existiert nicht.${COLOR_RESET}" + return 1 + fi + + # Prüfen, ob das Verzeichnis "robust" existiert und Dateien kopieren + if [[ -d "robust/bin" ]]; then + cp -r opensim/bin/* robust/bin + log "${SYM_OK} ${COLOR_ACTION}Dateien aus ${COLOR_DIR}opensim/bin${COLOR_RESET} ${COLOR_ACTION}wurden nach ${COLOR_DIR}robust/bin${COLOR_RESET} ${COLOR_ACTION}kopiert.${COLOR_RESET}" + else + log "${COLOR_WARNING}${SYM_WARNING} ${COLOR_ACTION}Hinweis: 'robust' Verzeichnis nicht gefunden, keine Kopie durchgeführt.${COLOR_RESET}" + fi + + # Alle simX-Verzeichnisse suchen und Dateien kopieren + for sim_dir in sim*; do + if [[ -d "$sim_dir/bin" ]]; then + cp -r opensim/bin/* "$sim_dir/bin/" + log "${SYM_OK} ${COLOR_ACTION}Dateien aus ${COLOR_DIR}opensim/bin${COLOR_RESET} ${COLOR_ACTION}wurden nach ${COLOR_DIR}$sim_dir/bin${COLOR_RESET} ${COLOR_ACTION}kopiert.${COLOR_RESET}" + fi + done + + blankline +} + +function database_setup() { + # 06.05.2025 + log "${COLOR_SECTION}=== MariaDB/MySQL Datenbank-Setup ===${COLOR_RESET}" + + # 1. Distribution Detection + detect_distro() { + if [[ -f /etc/os-release ]]; then + awk -F= '/^ID=/ {print $2}' /etc/os-release | tr -d '"' + elif [[ -f /etc/debian_version ]]; then + echo "debian" + elif [[ -f /etc/centos-release ]]; then + echo "centos" + else + echo "unknown" + fi + } + + current_distro=$(detect_distro) + #supported_distros=("debian" "ubuntu" "linuxmint" "pop" "mx" "kali" "zorin" "elementary" "raspbian" "centos" "fedora") + supported_distros=("debian" "ubuntu" "linuxmint" "pop" "mx" "kali" "zorin" "elementary" "raspbian" "centos" "fedora" "arch" "manjaro") + + # 2. Support-Check + if ! printf '%s\n' "${supported_distros[@]}" | grep -q "^${current_distro}$"; then + log "${SYM_BAD} ${COLOR_BAD}Nicht unterstützte Distribution: '${current_distro}'${COLOR_RESET}" + log "${SYM_INFO} Unterstützt: ${supported_distros[*]}" + return 1 + fi + + # 3. Installation Check (angepasste Version) + if ! command -v mariadb &> /dev/null && ! command -v mysql &> /dev/null; then + log "${SYM_WAIT} ${COLOR_WARNING}MariaDB/MySQL ist nicht installiert${COLOR_RESET}" + echo -ne "${COLOR_ACTION}MariaDB installieren? (j/n) [j] ${COLOR_RESET}" + read -r install_choice + install_choice=${install_choice:-j} + + if [[ "$install_choice" =~ ^[jJ] ]]; then + case $current_distro in + debian|ubuntu|*mint|pop|zorin|elementary|kali|mx|raspbian) + log "${SYM_INFO} ${COLOR_ACTION}Installiere MariaDB (apt)...${COLOR_RESET}" + sudo apt-get update && sudo apt-get install -y mariadb-server + ;; + centos|fedora) + log "${SYM_INFO} ${COLOR_ACTION}Installiere MariaDB (yum)...${COLOR_RESET}" + sudo yum install -y mariadb-server + sudo systemctl start mariadb + sudo systemctl enable mariadb + ;; + arch|manjaro) + log "${SYM_INFO} ${COLOR_ACTION}Installiere MariaDB (pacman)...${COLOR_RESET}" + sudo pacman -Sy --noconfirm mariadb + sudo mariadb-install-db --user=mysql --basedir=/usr --datadir=/var/lib/mysql + sudo systemctl enable --now mariadb + ;; + *) + log "${SYM_BAD} ${COLOR_BAD}Automatische Installation nicht verfügbar${COLOR_RESET}" + return 1 + ;; + esac + + # Sicherheitskonfiguration für alle Distros + log "${SYM_INFO} ${COLOR_ACTION}Führe mysql_secure_installation aus...${COLOR_RESET}" + sudo mysql_secure_installation + else + log "${SYM_BAD} Installation abgebrochen" + return 0 + fi + else + log "${SYM_OK} ${COLOR_OK}MariaDB/MySQL ist bereits installiert${COLOR_RESET}" + fi + + # 4. Benutzeranmeldedaten + log "\n${COLOR_SECTION}=== Datenbank-Zugangsdaten ===${COLOR_RESET}" + echo -ne "${COLOR_ACTION}Zufallszugangsdaten verwenden? (j/n) [j] ${COLOR_RESET}" + read -r default_cred_choice + default_cred_choice=${default_cred_choice:-j} + + if [[ "$default_cred_choice" =~ ^[jJ] ]]; then + db_user="${genDatabaseUserName}" + db_pass=$(tr -dc 'A-Za-z0-9!@#$%^&*()' < /dev/urandom | head -c 16) + log "${SYM_INFO} ${COLOR_LABEL}Generiertes Passwort: ${COLOR_VALUE}${db_pass}${COLOR_RESET}" + else + echo -ne "${COLOR_ACTION}DB_Benutzername: ${COLOR_RESET}" + read -r db_user + echo -ne "${COLOR_ACTION}DB_Passwort: ${COLOR_RESET}" + read -rs db_pass + echo + fi + + # **Speicherung der Datenbank-Zugangsdaten in UserInfo.ini** + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_INFO}Erstelle UserInfo.ini${COLOR_RESET}" + sudo touch "$ini_file" + fi + + log "\n[DatabaseData]" | sudo tee -a "$ini_file" >/dev/null + echo "DB_Benutzername = ${db_user}" | sudo tee -a "$ini_file" >/dev/null + echo "DB_Passwort = ${db_pass}" | sudo tee -a "$ini_file" >/dev/null + + + log "${SYM_LOG} ${COLOR_LABEL}Datenbank-Zugangsdaten gespeichert in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" + + # 6. Datenbankeinrichtung + log "\n${COLOR_SECTION}=== Datenbank-Konfiguration ===${COLOR_RESET}" + + # RobustServer DB + if [[ -d "robust" ]]; then + if ! sudo mysql -e "USE robust" &> /dev/null; then + sudo mysql -e "CREATE DATABASE robust CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" + log "${SYM_OK} ${COLOR_VALUE}robust${COLOR_RESET} Datenbank angelegt" + else + log "${SYM_INFO} ${COLOR_WARNING}robust-Datenbank existiert bereits${COLOR_RESET}" + fi + fi + + # simX Server DBs + for ((i=1; i<=1000; i++)); do + if [[ -d "sim${i}" ]]; then + db_name="sim${i}" + if ! sudo mysql -e "USE ${db_name}" &> /dev/null; then + sudo mysql -e "CREATE DATABASE ${db_name} CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci" + log "${SYM_OK} ${COLOR_VALUE}${db_name}${COLOR_RESET} Datenbank angelegt" + else + log "${SYM_INFO} ${COLOR_WARNING}${db_name}-Datenbank existiert bereits${COLOR_RESET}" + fi + fi + done + + # Benutzerverwaltung + if ! sudo mysql -e "SELECT user FROM mysql.user WHERE user='${db_user}' AND host='localhost'" | grep -q "${db_user}"; then + sudo mysql -e "CREATE USER '${db_user}'@'localhost' IDENTIFIED BY '${db_pass}'" + log "${SYM_OK} ${COLOR_VALUE}${db_user}${COLOR_RESET} Benutzer angelegt" + else + log "${SYM_INFO} ${COLOR_WARNING}Benutzer ${db_user} existiert bereits${COLOR_RESET}" + fi + + # Rechte vergeben + [[ -d "robust" ]] && sudo mysql -e "GRANT ALL PRIVILEGES ON robust.* TO '${db_user}'@'localhost'" + for ((i=1; i<=1000; i++)); do + [[ -d "sim${i}" ]] && sudo mysql -e "GRANT ALL PRIVILEGES ON sim${i}.* TO '${db_user}'@'localhost'" + done + sudo mysql -e "FLUSH PRIVILEGES" + + log "${COLOR_OK} Datenbank Setup abgeschlossen!${COLOR_RESET}" +} + + +function createmasteruser() { + # 02.05.2025 Master Avatar MasterAvatar + + # RobustServer starten + echo "RobustServer starten, erster start..." + if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" + cd robust/bin || exit 1 + # -inifile=Robust.HG.ini + + screen -fa -S robustserver -d -U -m dotnet Robust.dll + cd - >/dev/null 2>&1 || exit 1 + sleep $RobustServer_Start_wait + else + log "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" + fi + + genPasswort=$(tr -dc 'A-Za-z0-9!@#$%^&*()' < /dev/urandom | head -c 16) + genUserid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") + + VORNAME="${genFirstname}" + NACHNAME="${genLastname}" + local PASSWORT="${genPasswort}" + local EMAIL="${4:-${genFirstname}@${genLastname}.com}" + userid="${5:-$genUserid}" + + log "${COLOR_INFO}Master User Erstellung (Enter für generierte Werte)${COLOR_RESET}" + + echo -n "Vorname [${VORNAME}]: " + read -r input + VORNAME="${input:-$VORNAME}" + + echo -n "Nachname [${NACHNAME}]: " + read -r input + NACHNAME="${input:-$NACHNAME}" + + echo -n "Passwort [${PASSWORT}]: " + read -r input + PASSWORT="${input:-$PASSWORT}" + + echo -n "E-Mail [${EMAIL}]: " + read -r input + EMAIL="${input:-$EMAIL}" + + echo -n "UserID [${userid}]: " + read -r input + userid="${input:-$userid}" + + # Überprüfe ob Robust läuft + if ! screen -list | grep -q "robustserver"; then + log "${COLOR_BAD}CREATEUSER: Robust existiert nicht oder läuft nicht${COLOR_RESET}" + return 1 + fi + + # Benutzer in Robust erstellen + screen -S robustserver -p 0 -X eval "stuff 'create user'^M" + screen -S robustserver -p 0 -X eval "stuff '$VORNAME'^M" + screen -S robustserver -p 0 -X eval "stuff '$NACHNAME'^M" + screen -S robustserver -p 0 -X eval "stuff '$PASSWORT'^M" + screen -S robustserver -p 0 -X eval "stuff '$EMAIL'^M" + screen -S robustserver -p 0 -X eval "stuff '$userid'^M" + screen -S robustserver -p 0 -X eval "stuff 'Ruth'^M" + + log "${COLOR_OK}Masteruser $VORNAME $NACHNAME wurde erstellt${COLOR_RESET}" + log "${COLOR_INFO}UserID: $userid${COLOR_RESET}" + + # **Speicherung der Benutzerdaten in UserInfo.ini** NEU + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_INFO}Erstelle UserInfo.ini${COLOR_RESET}" + sudo touch "$ini_file" + fi + + log "\n[UserData]" | sudo tee -a "$ini_file" >/dev/null + echo "Vorname = ${VORNAME}" | sudo tee -a "$ini_file" >/dev/null + echo "Nachname = ${NACHNAME}" | sudo tee -a "$ini_file" >/dev/null + echo "Passwort = ${PASSWORT}" | sudo tee -a "$ini_file" >/dev/null + echo "E-Mail = ${EMAIL}" | sudo tee -a "$ini_file" >/dev/null + echo "UserID = ${userid}" | sudo tee -a "$ini_file" >/dev/null + + + log "${SYM_LOG} ${COLOR_LABEL}Benutzerdaten hinzugefügt in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" + + blankline +} + +function createmasterestate() { + # 02.05.2025 Master Estate + log "${COLOR_HEADING}🏡 Master Estate Erstellung${COLOR_RESET}" + + # sim1 starten + echo "Sim1 Welcome starten, erster start..." + if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1 ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}sim1/bin...${COLOR_RESET}" + cd sim1/bin || exit 1 + screen -fa -S sim1 -d -U -m dotnet OpenSim.dll + cd - >/dev/null 2>&1 || exit 1 + sleep 10 + else + log "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" + fi + + # 1. Überprüfe ob sim1 läuft + if ! screen -list | grep -q "sim1"; then + log "${SYM_BAD} ${COLOR_ERROR}CREATEESTATE: sim1 existiert nicht oder läuft nicht${COLOR_RESET}" + log "${COLOR_INFO}Tipp: Starten Sie die Simulator-Instanz zuerst${COLOR_RESET}" + return 1 + fi + + # 1. INI-Datei auslesen mit angepasstem Parsing + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" + return 1 + fi + + # Parsing-Funktion mit Trim und Leerzeichen im Pattern + ini_get() { + local section="$1" key="$2" + awk -F ' = ' ' + /^\[/ { current_section = substr($0, 2, length($0)-2) } + current_section == "'"$section"'" && $1 == "'"$key"'" { + sub(/^[ \t]+/, "", $2) # Trim leading whitespace + sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace + print $2 + exit + } + ' "$ini_file" + } + + # Werte auslesen + gridname=$(ini_get "ServerData" "GridName") + VORNAME=$(ini_get "UserData" "Vorname") + NACHNAME=$(ini_get "UserData" "Nachname") + + # Debug-Ausgabe + log "${COLOR_DEBUG}Gelesene Werte:" + log "GridName: '${gridname:-NICHT GEFUNDEN}'" + log "Vorname: '${VORNAME:-NICHT GEFUNDEN}'" + log "Nachname: '${NACHNAME:-NICHT GEFUNDEN}'${COLOR_RESET}" + + if [[ -z "$gridname" || -z "$VORNAME" || -z "$NACHNAME" ]]; then + log "${COLOR_BAD}Fehlende Daten in UserInfo.ini${COLOR_RESET}" + log "Bitte überprüfen Sie folgende Einträge:" + log "[ServerData]" + log "GridName = ..." + log "[UserData]" + log "Vorname = ..." + log "Nachname = ..." + return 1 + fi + + # 3. Logging vor der Ausführung + log "${COLOR_INFO}Erstelle Master Estate für:" + log "- Grid: ${COLOR_VALUE}$gridname" + log "- Avatar: ${COLOR_VALUE}$VORNAME $NACHNAME${COLOR_RESET}" + + # 4. Befehle an sim1 senden mit Fehlerprüfung + if ! screen -S sim1 -p 0 -X eval "stuff '$gridname Estate'^M"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden des Estate-Befehls${COLOR_RESET}" + return 1 + fi + sleep 1 # Kurze Pause zwischen den Befehlen + + if ! screen -S sim1 -p 0 -X eval "stuff '$VORNAME'^M"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden des Vornamens${COLOR_RESET}" + return 1 + fi + sleep 1 + + if ! screen -S sim1 -p 0 -X eval "stuff '$NACHNAME'^M"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden des Nachnamens${COLOR_RESET}" + return 1 + fi + + # 5. Erfolgsmeldung + log "${SYM_OK} ${COLOR_OK}Master Estate erfolgreich erstellt${COLOR_RESET}" + log "${COLOR_INFO}Starte nun die Estate-Akzeptierung für alle Regionen...${COLOR_RESET}" + blankline + + # 6. Alle anderen Starten und Estate akzeptieren + if ! createmasterestateall; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler bei createmasterestateall${COLOR_RESET}" + return 1 + fi + + return 0 +} + +function createmasterestateall() { + # 02.05.2025 Master Estate Bestätigung mit Simulator-Start + log "${COLOR_HEADING}🌍 Starte Simulatoren & bestätige Master Estate${COLOR_RESET}" + + # 1. INI-Datei auslesen mit angepasstem Parsing + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" + return 1 + fi + + # Parsing-Funktion mit Trim und Leerzeichen im Pattern + ini_get() { + local section="$1" key="$2" + awk -F ' = ' ' + /^\[/ { current_section = substr($0, 2, length($0)-2) } + current_section == "'"$section"'" && $1 == "'"$key"'" { + sub(/^[ \t]+/, "", $2) # Trim leading whitespace + sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace + print $2 + exit + } + ' "$ini_file" + } + + # Werte auslesen + gridname=$(ini_get "ServerData" "GridName") + VORNAME=$(ini_get "UserData" "Vorname") + NACHNAME=$(ini_get "UserData" "Nachname") + + # Debug-Ausgabe + log "${COLOR_DEBUG}Gelesene Werte:" + log "GridName: '${gridname:-NICHT GEFUNDEN}'" + log "Vorname: '${VORNAME:-NICHT GEFUNDEN}'" + log "Nachname: '${NACHNAME:-NICHT GEFUNDEN}'${COLOR_RESET}" + + if [[ -z "$gridname" || -z "$VORNAME" || -z "$NACHNAME" ]]; then + log "${COLOR_BAD}Fehlende Daten in UserInfo.ini${COLOR_RESET}" + log "Bitte überprüfen Sie folgende Einträge:" + log "[ServerData]" + log "GridName = ..." + log "[UserData]" + log "Vorname = ..." + log "Nachname = ..." + return 1 + fi + + # 2. Starte alle Simulatoren + log "${COLOR_ACTION}Starte Simulator-Instanzen...${COLOR_RESET}" + local started_sims=0 + + for ((i=2; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then + echo -n -e "${SYM_INFO} ${COLOR_DIR}sim$i: ${COLOR_RESET}" + + if cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll; then + log "${COLOR_OK}gestartet${COLOR_RESET}" + ((started_sims++)) + sleep "${Simulator_Start_wait:-5}" + else + log "${COLOR_ERROR}start fehlgeschlagen${COLOR_RESET}" + fi + cd - >/dev/null 2>&1 + fi + done + + # 3. Estate-Bestätigung für alle Regionen + if [[ $started_sims -gt 0 ]]; then + log "${COLOR_ACTION}Bestätige Estate für $started_sims Simulator(en)...${COLOR_RESET}" + + for ((i=2; i<=999; i++)); do + if screen -list | grep -q "sim$i"; then + regions_dir="${SCRIPT_DIR}/sim$i/bin/Regions" + if [[ -d "$regions_dir" ]]; then + # Zähle die Anzahl der Regionen-Konfigurationen + region_count=$(find "$regions_dir" -maxdepth 1 -name "*.ini" | wc -l) + log "${SYM_INFO} ${COLOR_DIR}sim$i: ${region_count} Region(en) gefunden${COLOR_RESET}" + + # Für jede Region die Bestätigung senden + for ((r=1; r<=region_count; r++)); do + echo -n -e " ${SYM_INFO} Region ${r}: ${COLOR_RESET}" + + if ! screen -S "sim$i" -p 0 -X eval "stuff 'yes'^M"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden von yes${COLOR_RESET}" + return 1 + fi + sleep 1 + + if ! screen -S "sim$i" -p 0 -X eval "stuff '$gridname Estate'^M"; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler beim Senden von $gridname Estate${COLOR_RESET}" + return 1 + fi + log "${COLOR_OK}bestätigt${COLOR_RESET}" + sleep 1 + done + else + log "${SYM_WARNING} ${COLOR_WARNING}sim$i: Kein Regions-Verzeichnis gefunden${COLOR_RESET}" + sleep 1 + fi + fi + done + else + log "${SYM_WARNING} ${COLOR_WARNING}Keine Simulatoren gestartet!${COLOR_RESET}" + return 1 + fi + + log "${SYM_OK} ${COLOR_OK}$started_sims Simulatoren gestartet & Estate für alle Regionen bestätigt${COLOR_RESET}" + sleep 1 + blankline + return 0 +} + +function firststart() { + # 02.05.2025 + # Sind wir im Skriptverzeichnis oder noch in opensim? + cd "$SCRIPT_DIR" || exit 1 + + # Master Avatar Registrieren. + createmasteruser + + # Estate erstellen + createmasterestate + + # Erststart stoppen + #opensimstop + #killall screen + + # Regulären Start nach installation und setup. + #opensimrestart + + blankline + +} + +# bash osmtool.sh setcrontab +function setcrontab() { + # Strict Mode: Fehler sofort erkennen + set -euo pipefail + + log "${COLOR_HEADING}⏰ Cron-Job-Einrichtung (Interaktiv)${COLOR_RESET}" + + # Sicherheitsabfrage: Nur als root/sudo ausführen + if [ "$(id -u)" -ne 0 ]; then + log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Dieses Skript benötigt root-Rechte! (sudo verwenden)${COLOR_RESET}" >&2 + return 1 + fi + + # Prüfen, ob SCRIPT_DIR gesetzt und gültig ist + if [ -z "${SCRIPT_DIR:-}" ]; then + log "${SYM_BAD} ${COLOR_ERROR}FEHLER: 'SCRIPT_DIR' muss gesetzt sein!${COLOR_RESET}" >&2 + return 1 + fi + + if [ ! -d "$SCRIPT_DIR" ]; then + log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Verzeichnis '${COLOR_DIR}$SCRIPT_DIR${COLOR_ERROR}' existiert nicht!${COLOR_RESET}" >&2 + return 1 + fi + + # Temporäre Datei für neue Cron-Jobs + local temp_cron + temp_cron=$(mktemp) || { + log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Temp-Datei konnte nicht erstellt werden.${COLOR_RESET}" >&2 + return 1 + } + + ### Interaktive Abfragen ### + log "\n${COLOR_VALUE}=== Wartung am 1. des Monats ===${COLOR_RESET}" + log "Welche Aktionen sollen ausgeführt werden? (Mehrfachauswahl möglich)" + log " ${SYM_INFO} 1) Nichts (deaktivieren)" + log " ${SYM_INFO} 2) cacheclean (inkl. automatischem stop vorher)" + log " ${SYM_INFO} 3) mapclean (inkl. automatischem stop vorher)" + log " ${SYM_INFO} 4) logclean (inkl. automatischem stop vorher)" + log " ${SYM_INFO} 5) Vollständiger Neustart (stop → cacheclean → mapclean → logclean → reboot)" + log " ${SYM_INFO} 6) Nur Server neustarten (reboot)" + read -r -p "$(msg CRON_PROMPT_MONTHLY_SELECTION) " -a monthly_actions + + # Abfrage ob nach clean-Operationen ein reboot erfolgen soll + local needs_reboot=false + if [[ " ${monthly_actions[*]} " =~ [234] ]]; then + read -r -p "$(msg CRON_PROMPT_REBOOT_AFTER_CLEAN) " add_reboot + is_yes "$add_reboot" && needs_reboot=true + fi + + log "\n${COLOR_VALUE}=== Tägliche Wartung ===${COLOR_RESET}" + read -r -p "$(msg CRON_PROMPT_DAILY_RESTART) " daily_restart + if is_yes "$daily_restart"; then + read -r -p "$(msg CRON_PROMPT_DAILY_HOUR) " daily_hour + daily_hour=${daily_hour:-5} # Default: 5 Uhr + fi + + log "\n${COLOR_VALUE}=== Überwachung ===${COLOR_RESET}" + read -r -p "$(msg CRON_PROMPT_ENABLE_MONITORING) " enable_monitoring + if is_yes "$enable_monitoring"; then + read -r -p "$(msg CRON_PROMPT_MONITOR_INTERVAL) " monitor_interval + monitor_interval=${monitor_interval:-30} + fi + + ### Cron-Job-Generierung ### + { + echo "# === OpenSimGrid-Automatisierung ===" + echo "# Bedeutung: Minute Stunde Tag Monat Jahr Befehlskette" + echo "" + + # Monatliche Wartung (1. des Monats) + if [[ " ${monthly_actions[*]} " =~ "1" ]]; then + echo "# Deaktiviert: Monatliche Wartung" + else + echo "# Monatliche Wartung am 1. des Monats" + + # Berechnung der Minuten relativ zum täglichen Restart + local restart_hour=${daily_hour:-5} + local restart_minute=0 + + # Stop 30 Minuten vor täglichem Restart + if [[ " ${monthly_actions[*]} " =~ [2345] ]]; then + stop_time=$(calculate_relative_time "$restart_hour" $restart_minute -30) + echo "$stop_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' stop" + fi + + # Cacheclean 25 Minuten vor täglichem Restart (Option 2 oder 5) + if [[ " ${monthly_actions[*]} " =~ [25] ]]; then + cacheclean_time=$(calculate_relative_time "$restart_hour" $restart_minute -25) + echo "$cacheclean_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' cacheclean" + fi + + # Mapclean 20 Minuten vor täglichem Restart (Option 3 oder 5) + if [[ " ${monthly_actions[*]} " =~ [35] ]]; then + mapclean_time=$(calculate_relative_time "$restart_hour" $restart_minute -20) + echo "$mapclean_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' mapclean" + fi + + # Logclean 15 Minuten vor täglichem Restart (Option 4 oder 5) + if [[ " ${monthly_actions[*]} " =~ [45] ]]; then + logclean_time=$(calculate_relative_time "$restart_hour" $restart_minute -15) + echo "$logclean_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' logclean" + fi + + # Reboot 10 Minuten vor täglichem Restart (Option 5 oder 6 oder manuelle Bestätigung) + if [[ " ${monthly_actions[*]} " =~ [56] ]] || $needs_reboot; then + reboot_time=$(calculate_relative_time "$restart_hour" $restart_minute -10) + echo "$reboot_time 1 * * bash '$SCRIPT_DIR/osmtool.sh' reboot" + fi + fi + + # Tägliche Wartung + if [[ "$daily_restart" =~ [jJ] ]]; then + log "\n# Täglicher Restart" + echo "0 ${daily_hour} * * * bash '$SCRIPT_DIR/osmtool.sh' restart" + else + log "\n# Deaktiviert: Täglicher Restart" + fi + + # Überwachung + if [[ "$enable_monitoring" =~ [jJ] ]]; then + log "\n# Überwachung" + echo "*/${monitor_interval} * * * * bash '$SCRIPT_DIR/osmtool.sh' check_screens" + else + log "\n# Deaktiviert: Überwachung" + fi + } > "$temp_cron" + + # Cron-Jobs installieren + if crontab "$temp_cron"; then + rm -f "$temp_cron" + log "\n${SYM_OK} ${COLOR_OK}Cron-Jobs wurden aktualisiert:${COLOR_RESET}" + crontab -l | grep -v '^#' | sed '/^$/d' | while read -r line; do + log "${COLOR_DIR}$line${COLOR_RESET}" + done + return 0 + else + log "${SYM_BAD} ${COLOR_ERROR}FEHLER: Installation fehlgeschlagen. Prüfe $temp_cron manuell.${COLOR_RESET}" >&2 + return 1 + fi +} + +# Hilfsfunktion zur Berechnung relativer Zeiten +calculate_relative_time() { + local hour=$1 + local minute=$2 + local offset=$3 # in Minuten (kann negativ sein) + + # Gesamtminuten berechnen + local total_minutes=$((hour * 60 + minute + offset)) + + # Handle negative Zeiten (vor Mitternacht) + while (( total_minutes < 0 )); do + total_minutes=$((total_minutes + 1440)) # 24 Stunden in Minuten + done + + # Zurück in Stunden und Minuten umrechnen + local new_hour=$((total_minutes / 60 % 24)) + local new_minute=$((total_minutes % 60)) + + echo "$new_minute $new_hour" +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Backup und Upgrade des OpenSimulators Grids +#?────────────────────────────────────────────────────────────────────────────────────────── + +function opensimupgrade() { + log "\n${COLOR_WARNING}${SYM_WARNING} Der OpenSimulator muss zuerst im Verzeichnis 'opensim' vorliegen!${COLOR_RESET}" + log "${COLOR_LABEL}Möchten Sie den OpenSimulator aktualisieren? (${COLOR_BAD}[no]${COLOR_LABEL}/yes)${COLOR_RESET}" + read -r user_choice + user_choice=${user_choice:-no} + + # Prüfe, ob das Verzeichnis vorhanden ist + if [[ ! -d "opensim" ]]; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler: Das Verzeichnis '${COLOR_DIR}opensim${COLOR_ERROR}' existiert nicht${COLOR_RESET}" + return 1 + fi + + # Prüfe, ob im Verzeichnis 'opensim/bin' die Dateien OpenSim.dll und Robust.dll vorhanden sind + if [[ ! -f "opensim/bin/OpenSim.dll" || ! -f "opensim/bin/Robust.dll" ]]; then + log "${SYM_BAD} ${COLOR_ERROR}Fehler: Benötigte Dateien (OpenSim.dll und/oder Robust.dll) fehlen im Verzeichnis '${COLOR_DIR}opensim/bin${COLOR_ERROR}'${COLOR_RESET}" + log "\n${COLOR_WARNING}❓ Haben Sie vergessen den OpenSimulator zuerst zu Kompilieren?${COLOR_RESET}" + return 1 + fi + + if [[ "$user_choice" == "yes" ]]; then + log "${COLOR_ACTION}OpenSimulator wird gestoppt...${COLOR_RESET}" + opensimstop + sleep $Simulator_Stop_wait + + log "${COLOR_ACTION}OpenSimulator wird kopiert...${COLOR_RESET}" + opensimcopy + + log "${COLOR_ACTION}OpenSimulator wird gestartet...${COLOR_RESET}" + opensimstart + + log "${COLOR_OK}✔ ${COLOR_ACTION}Upgrade abgeschlossen.${COLOR_RESET}" + else + log "${COLOR_WARNING}Upgrade vom Benutzer abgebrochen.${COLOR_RESET}" + fi + blankline +} + +function regionbackup() { + DATUM=$(date +%Y-%m-%d_%H-%M) + BACKUPDIR="$SCRIPT_DIR/backup" + mkdir -p "$BACKUPDIR" + + log "${SYM_TOOLS} ${COLOR_HEADING}Starte automatisches Backup aller Regionen...${COLOR_RESET}" + + for ((i=1; i<=999; i++)); do + SIMNAME="sim$i" + SIMBIN="$SCRIPT_DIR/$SIMNAME/bin" + REGIONSDIR="$SIMBIN/Regions" + TARGETDIR="$BACKUPDIR/sim$i" + + if [[ -d "$REGIONSDIR" ]]; then + mkdir -p "$TARGETDIR" + log "${SYM_SERVER} ${COLOR_START}Backup für ${COLOR_SERVER}$SIMNAME${COLOR_RESET} wird vorbereitet (${COLOR_DIR}$SIMBIN${COLOR_RESET})..." + + # ➕ OpenSim.ini sichern + if [[ -f "$SIMBIN/OpenSim.ini" ]]; then + cp "$SIMBIN/OpenSim.ini" "$TARGETDIR/${DATUM}-OpenSim.ini" + log "${SYM_CONFIG} ${COLOR_LABEL}OpenSim.ini gesichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-OpenSim.ini${COLOR_RESET}" + fi + + # ➕ GridCommon.ini sichern + if [[ -f "$SIMBIN/config-include/GridCommon.ini" ]]; then + cp "$SIMBIN/config-include/GridCommon.ini" "$TARGETDIR/${DATUM}-GridCommon.ini" + log "${SYM_CONFIG} ${COLOR_LABEL}GridCommon.ini gesichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-GridCommon.ini${COLOR_RESET}" + fi + + for ini_file in "$REGIONSDIR"/*.ini; do + [[ -f "$ini_file" ]] || continue + + region_names=$(grep -oP '^\[\K[^\]]+' "$ini_file") + + for REGIONNAME in $region_names; do + blankline + log "${SYM_FOLDER} ${COLOR_LABEL}Sichere Region:${COLOR_RESET} ${COLOR_VALUE}$REGIONNAME${COLOR_RESET}" + + screen -S "$SIMNAME" -p 0 -X eval "stuff 'change region ${REGIONNAME//\"/}'^M" + sleep 1 + + screen -S "$SIMNAME" -p 0 -X eval "stuff 'save oar ${TARGETDIR}/${DATUM}-${REGIONNAME}.oar'^M" + log "${SYM_FILE} ${COLOR_LABEL}OAR gespeichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-${REGIONNAME}.oar${COLOR_RESET}" + + screen -S "$SIMNAME" -p 0 -X eval "stuff 'save xml2 ${TARGETDIR}/${DATUM}-${REGIONNAME}.xml2'^M" + log "${SYM_FILE} ${COLOR_LABEL}XML2 gespeichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-${REGIONNAME}.xml2${COLOR_RESET}" + + screen -S "$SIMNAME" -p 0 -X eval "stuff 'terrain save ${TARGETDIR}/${DATUM}-${REGIONNAME}.png'^M" + screen -S "$SIMNAME" -p 0 -X eval "stuff 'terrain save ${TARGETDIR}/${DATUM}-${REGIONNAME}.raw'^M" + log "${SYM_FILE} ${COLOR_LABEL}Terrain (PNG & RAW) gespeichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-${REGIONNAME}.{png,raw}${COLOR_RESET}" + + cp "$ini_file" "$TARGETDIR/${DATUM}-$(basename "$ini_file")" + log "${SYM_CONFIG} ${COLOR_LABEL}Konfig gesichert:${COLOR_RESET} ${COLOR_FILE}${DATUM}-$(basename "$ini_file")${COLOR_RESET}" + + sleep 1 + done + done + fi + done + + log "${SYM_OK} ${COLOR_ACTION}Automatisches Regionen-Backup abgeschlossen.${COLOR_RESET}" + blankline +} + +# todo: Testen, ob alles funktioniert. +# Erstellt ein strukturiertes Backup der Robust-Datenbank sowie wichtiger Konfigurationsdateien. +# Aufruf: +function robustbackup() { + # Variablen der Funktion. + local DB_NAME="robust" + local BACKUP_YEARS=30 + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local ini_file="$SCRIPT_DIR/UserInfo.ini" + local BACKUP_DIR="$SCRIPT_DIR/backup/robust" + local ROBUST_INI_DIR="$SCRIPT_DIR/robust/bin" + TIMESTAMP=$(date +%F_%H-%M) + TIMESTAMP_GRENZE=$(date -d "-$BACKUP_YEARS years" +%s) + ARCHIVIEREN="nein" + + # Root-Privilegien erforderlich + if [[ "$EUID" -ne 0 ]]; then + echo "Dieses Skript muss als Root ausgeführt werden (z.B. mit sudo)." >&2 + echo "Ohne Root-Privilegien müssen Sie das Passwort der Datenbank bei jedem Mal eingeben." >&2 + echo -n "Möchten Sie trotzdem ohne Root-Privilegien fortfahren? (ja/N): " >&2 + read -r answer + if [[ "$answer" != "ja" ]]; then + echo "Abbruch." >&2 + exit 1 + fi + fi + + # Zugangsdaten auslesen, falls vorhanden + local DB_USER DB_PASS + if [[ -f "$ini_file" ]]; then + DB_USER=$(grep -oP '^DB_Benutzername\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') + DB_PASS=$(grep -oP '^DB_Passwort\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') + fi + + # Falls nicht vorhanden: Benutzer fragen + if [[ -z "$DB_USER" ]]; then + echo "Bitte DB-Benutzername eingeben:" + read -r DB_USER + fi + + if [[ -z "$DB_PASS" ]]; then + echo "Bitte DB-Passwort eingeben:" + read -r DB_PASS + fi + + declare -A ASSET_NAMES=( + [-1]="NoneUnknown" [-2]="LLmaterialIAR" [0]="Texture" [1]="Sound" [2]="CallingCard" [3]="Landmark" + [4]="Unknown4" [5]="Clothing" [6]="Object" [7]="Notecard" [8]="Folder" [9]="Unknown9" + [10]="LSLText" [11]="LSLBytecode" [12]="TextureTGA" [13]="Bodypart" [14]="Unknown14" + [15]="Unknown15" [16]="Unknown16" [17]="SoundWAV" [18]="ImageTGA" [19]="ImageJPEG" + [20]="Animation" [21]="Gesture" [22]="Simstate" [23]="Unknown23" [24]="Link" + [25]="LinkFolder" [26]="MarketplaceFolder" [49]="Mesh" [56]="Settings" [57]="Material" + ) + + mkdir -p "$BACKUP_DIR/tables" "$BACKUP_DIR/assettypen" "$BACKUP_DIR/configs" + + log "${COLOR_HEADING}${SYM_PACKAGE} Starte Robust-Datenbank-Backup mit Zeitraumfilter ($BACKUP_YEARS Jahre)${COLOR_RESET}" + + #* Reparatur + mysqlcheck -u"$DB_USER" -p"$DB_PASS" --auto-repair "$DB_NAME" + + #* Tabellen sichern (außer assets) mit Zählung + local tabellen + local total_nonasset_rows=0 + tabellen=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SHOW TABLES IN $DB_NAME;" | grep -v '^assets$') + for table in $tabellen; do + row_count=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SELECT COUNT(*) FROM $table;" "$DB_NAME") + ((total_nonasset_rows += row_count)) + log "${SYM_LOG} Tabelleneinträge: $table (${row_count} Einträge)${COLOR_RESET}" + mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" "$table" | gzip > "$BACKUP_DIR/tables/${table}.sql.gz" + done + + log "${SYM_OK}${COLOR_INFO} Tabellen (außer assets): Insgesamt $total_nonasset_rows Einträge gesichert${COLOR_RESET}" + + #* Assettypen sichern mit Zählung + log "${SYM_PUZZLE} Starte assetType-Datensicherung mit Zeitraumfilter ab $(date -d "@$TIMESTAMP_GRENZE")" + + total_found=0 + total_saved=0 + + for assettype in "${!ASSET_NAMES[@]}"; do + local name="${ASSET_NAMES[$assettype]}" + log "${SYM_FOLDER} Exportiere assetType=$assettype ($name)${COLOR_RESET}" + + # Anzahl Datensätze in diesem Typ und Zeitraum + count=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e \ + "SELECT COUNT(*) FROM assets WHERE assetType = $assettype AND create_time >= $TIMESTAMP_GRENZE;" "$DB_NAME") + + if [[ "$count" -gt 0 ]]; then + ((total_found += count)) + ((total_saved += count)) + mysqldump -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" assets \ + --where="assetType = $assettype AND create_time >= $TIMESTAMP_GRENZE" \ + | gzip > "$BACKUP_DIR/assettypen/assets_${name}.sql.gz" + log "${SYM_OK} Gespeichert: $count Einträge für $name" + else + log "${SYM_FORWARD} Keine Daten für assetType=$assettype ($name)" + fi + done + + log "${SYM_OK}${COLOR_INFO} Asset-Sicherung abgeschlossen: $total_found gefunden, $total_saved gespeichert, Differenz: $((total_found - total_saved))${COLOR_RESET}" + + #* Konfig-Dateien sichern + log "${SYM_LOG} Sicherung der Konfigurationsdateien im robust/bin Verzeichnis${COLOR_RESET}" + find "$ROBUST_INI_DIR" -maxdepth 1 -type f \( \ + -name "MoneyServer.ini" -o -name "MoneyServer.ini.*" \ + -o -name "Robust.ini" -o -name "Robust.HG.*" -o -name "Robust.local.*" \) \ + -exec cp {} "$BACKUP_DIR/configs/" \; + + #* Archiv erstellen (Was passiert hier wird das unützerweise alles in einer Datei gepackt?) + if [ "$ARCHIVIEREN" = "ja" ]; then + log "${COLOR_HEADING}${SYM_PACKAGE} Erstelle tgz-Archiv: robustbackup_${TIMESTAMP}.tgz${COLOR_RESET}" + tar czf "$BACKUP_DIR/robustbackup_${TIMESTAMP}.tgz" -C "$BACKUP_DIR" . + log "${SYM_OKNN} Backup abgeschlossen: $BACKUP_DIR/robustbackup_${TIMESTAMP}.tgz${COLOR_RESET}" + fi +} + +# todo: Testen, ob alles funktioniert. +# Wiederherstellt eine Robust-Datenbank aus einer Dump-Datei. +# Aufruf: +#* restoreRobustDump +function restoreRobustDump() { + local DB_USER=$1 + local DB_PASS=$2 + local DUMP_FILE=$3 + local TARGET_DB=$4 + + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local TMPDIR + TMPDIR=$(mktemp -d) + local total_tables=0 + + log "${COLOR_HEADING}${SYM_PACKAGE} Starte Wiederherstellung von Dump-Datei ${COLOR_FILE}${DUMP_FILE}${COLOR_RESET} in Datenbank ${COLOR_VALUE}${TARGET_DB}${COLOR_RESET}" + + if [[ ! -f "$DUMP_FILE" ]]; then + log "${SYM_BAD} ${COLOR_BAD}Fehler:${COLOR_RESET} Dump-Datei nicht gefunden: ${COLOR_FILE}$DUMP_FILE${COLOR_RESET}" + return 1 + fi + + #* Datenbank vorbereiten + log "${SYM_TOOLS} Entferne vorhandene Datenbank (falls vorhanden) und erstelle neu: ${COLOR_VALUE}$TARGET_DB${COLOR_RESET}" + mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP DATABASE IF EXISTS \`$TARGET_DB\`; CREATE DATABASE \`$TARGET_DB\`;" + + #* Dump-Datei aufteilen + log "${SYM_SCRIPT} Zerlege Dump-Datei in einzelne Tabellen im Temp-Verzeichnis: ${COLOR_FILE}$TMPDIR${COLOR_RESET}" + csplit -z -f "$TMPDIR/table_" -b "%03d.sql" "$DUMP_FILE" '/DROP TABLE IF EXISTS/' '{*}' > /dev/null + + #* Import der Tabellen + for sqlfile in "$TMPDIR"/table_*.sql; do + local tablename + tablename=$(grep -i "CREATE TABLE" "$sqlfile" | awk -F'\`' '{print $2}') + if [[ -n "$tablename" ]]; then + log "${SYM_FILE} Importiere Tabelle: ${COLOR_FILE}$tablename${COLOR_RESET}" + mysql -u"$DB_USER" -p"$DB_PASS" "$TARGET_DB" < "$sqlfile" + ((total_tables++)) + fi + done + + log "${SYM_OK}${COLOR_INFO} Import abgeschlossen: $total_tables Tabellen importiert${COLOR_RESET}" + + #* Asset-Typen prüfen und reparieren + log "${SYM_PUZZLE} Prüfe asset.assetType auf ungültige Werte..." + invalid_count=$(mysql -u"$DB_USER" -p"$DB_PASS" -sse "SELECT COUNT(*) FROM asset WHERE assetType NOT BETWEEN 0 AND 49;" "$TARGET_DB") + + if ((invalid_count > 0)); then + log "${SYM_WARNING} Ungültige assetType-Werte gefunden: $invalid_count — korrigiere auf 0" + mysql -u"$DB_USER" -p"$DB_PASS" -e "UPDATE asset SET assetType = 0 WHERE assetType NOT BETWEEN 0 AND 49;" "$TARGET_DB" + else + log "${SYM_OK} Alle assetType-Werte sind gültig" + fi + + #* Datenbank reparieren + log "${SYM_TOOLS} Führe mysqlcheck mit Reparatur durch..." + mysqlcheck -u"$DB_USER" -p"$DB_PASS" --auto-repair "$TARGET_DB" + + log "${SYM_OK} ${COLOR_OK}Wiederherstellung erfolgreich abgeschlossen für:${COLOR_RESET} ${COLOR_VALUE}$TARGET_DB${COLOR_RESET}" +} + + +# todo: Testen, ob alles funktioniert. +# robustrestore +# dbuser: SQL-Benutzername +# dbpass: Passwort des SQL-Benutzers +# all: Wiederherstellung aller Nicht-Asset-Tabellen und Konfig-Dateien +# tables: Wiederherstellung aller Nicht-Asset-Tabellen +# assets: Wiederherstellung der assetType-Tabellen und Konfig-Dateien +# assettype: Wiederherstellung der angegebenen assetType-Tabellen +function robustrestore() { + local DB_USER=$1 + local DB_PASS=$2 + local DB_NAME="robust" + local RESTORE_SCOPE=$3 # "all", "tables", "assets" oder Asset-Typ-Name + SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" + local BACKUP_DIR="$SCRIPT_DIR/backup/robust" + + log "${COLOR_HEADING}${SYM_PACKAGE} Starte Wiederherstellung für: ${COLOR_VALUE}${RESTORE_SCOPE}${COLOR_RESET}" + + case "$RESTORE_SCOPE" in + all) + log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung aller Nicht-Asset-Tabellen...${COLOR_RESET}" + for file in "$BACKUP_DIR/tables/"*.sql.gz; do + table_name=$(basename "$file" .sql.gz) + log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Tabelle: ${COLOR_LABEL}${table_name}${COLOR_RESET}" + gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" + done + + log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung aller Asset-Typen...${COLOR_RESET}" + for file in "$BACKUP_DIR/assettypen/"*.sql.gz; do + asset_name=$(basename "$file" .sql.gz) + log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Asset-Typ: ${COLOR_LABEL}${asset_name}${COLOR_RESET}" + gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" + done + ;; + tables) + log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung nur der Nicht-Asset-Tabellen...${COLOR_RESET}" + for file in "$BACKUP_DIR/tables/"*.sql.gz; do + table_name=$(basename "$file" .sql.gz) + log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Tabelle: ${COLOR_LABEL}${table_name}${COLOR_RESET}" + gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" + done + ;; + assets) + log "${SYM_LOG} ${COLOR_LABEL}Wiederherstellung aller Asset-Typen...${COLOR_RESET}" + for file in "$BACKUP_DIR/assettypen/"*.sql.gz; do + asset_name=$(basename "$file" .sql.gz) + log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET} ${COLOR_ACTION}→ Importiere Asset-Typ: ${COLOR_LABEL}${asset_name}${COLOR_RESET}" + gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" + done + ;; + *) + local file="$BACKUP_DIR/assettypen/assets_${RESTORE_SCOPE}.sql.gz" + if [[ -f "$file" ]]; then + log "${SYM_FOLDER} ${COLOR_LABEL}Wiederherstellung für Asset-Typ: ${COLOR_VALUE}${RESTORE_SCOPE}${COLOR_RESET}" + log "${SYM_FILE} ${COLOR_FILE}${file}${COLOR_RESET}" + gunzip -c "$file" | mysql -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" + else + log "${SYM_BAD} ${COLOR_BAD}Fehler: Kein Backup für Asset-Typ '${RESTORE_SCOPE}' gefunden!${COLOR_RESET}" + return 1 + fi + ;; + esac + + log "${SYM_OK} ${COLOR_OK}Wiederherstellung erfolgreich abgeschlossen für Bereich: ${COLOR_VALUE}${RESTORE_SCOPE}${COLOR_RESET}" +} + +# todo: Testen, ob alles funktioniert. +# robustrepair +# dbuser: SQL-Benutzername +# dbpass: Passwort des SQL-Benutzers +# check: Prüft alle Tabellen auf Fehler +# repair: Repariert alle Tabellen automatisch +# truncate: Leert alle Inhalte, behält aber Tabellenstrukturen +# dropassets: Löscht alle Assets und Asset-Typen +# dropall: Löscht alle Tabelleninhalte +function robustrepair() { + local DB_USER=$1 + local DB_PASS=$2 + local DB_NAME="robust" + local ACTION=$3 # "check", "repair", "truncate", "dropassets", "dropall" + + log "${COLOR_HEADING}${SYM_TOOLS} Starte Datenbankwartung: ${COLOR_VALUE}${ACTION}${COLOR_RESET}" + + case "$ACTION" in + check) + log "${SYM_WAIT} ${COLOR_LABEL}Überprüfe Tabellen auf Fehler...${COLOR_RESET}" + mysqlcheck -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" + ;; + repair) + log "${SYM_BOOK} ${COLOR_LABEL}Repariere beschädigte Tabellen automatisch...${COLOR_RESET}" + mysqlcheck -u"$DB_USER" -p"$DB_PASS" --auto-repair "$DB_NAME" + ;; + truncate) + log "${SYM_WARNING} ${COLOR_WARNING}${SYM_WARNING} Achtung: Leert alle Inhalte, behält aber Tabellenstrukturen!${COLOR_RESET}" + echo -ne "${COLOR_BAD}$(msg LEGACY_PROMPT_CONTINUE_YESNO): ${COLOR_RESET}" + read -r confirm + if is_yes "$confirm"; then + local tables + tables=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SHOW TABLES IN $DB_NAME;") + for t in $tables; do + log "${SYM_CLEAN} Leere Tabelle: ${COLOR_LABEL}${t}${COLOR_RESET}" + mysql -u"$DB_USER" -p"$DB_PASS" -e "TRUNCATE TABLE $DB_NAME.$t;" + done + log "${SYM_OK} ${COLOR_OK}Alle Tabellen wurden geleert.${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_BAD}Abgebrochen.${COLOR_RESET}" + fi + ;; + dropassets) + log "${SYM_WARNING} ${COLOR_WARNING}${SYM_WARNING} Achtung: Löscht ALLE Einträge in der 'assets'-Tabelle!${COLOR_RESET}" + echo -ne "${COLOR_BAD}$(msg LEGACY_PROMPT_CONTINUE_YESNO): ${COLOR_RESET}" + read -r confirm + if is_yes "$confirm"; then + mysql -u"$DB_USER" -p"$DB_PASS" -e "DELETE FROM $DB_NAME.assets;" + log "${SYM_OK} ${COLOR_OK}Tabelle 'assets' wurde geleert.${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_BAD}Abgebrochen.${COLOR_RESET}" + fi + ;; + dropall) + log "${SYM_WARNING} ${COLOR_WARNING}${SYM_WARNING} Achtung: Alle Tabellen der Datenbank werden gelöscht!${COLOR_RESET}" + echo -ne "${COLOR_BAD}$(msg PROMPT_DROP_ALL_TABLES): ${COLOR_RESET}" + read -r confirm + if is_yes "$confirm"; then + local tables + tables=$(mysql -u"$DB_USER" -p"$DB_PASS" -N -e "SHOW TABLES IN $DB_NAME;") + for t in $tables; do + log "${SYM_CLEAN} Lösche Tabelle: ${COLOR_LABEL}${t}${COLOR_RESET}" + mysql -u"$DB_USER" -p"$DB_PASS" -e "DROP TABLE $DB_NAME.$t;" + done + log "${SYM_OK} ${COLOR_OK}Alle Tabellen gelöscht.${COLOR_RESET}" + else + log "${SYM_BAD} ${COLOR_BAD}Abgebrochen.${COLOR_RESET}" + fi + ;; + *) + log "${SYM_BAD} ${COLOR_BAD}Unbekannte Aktion: ${ACTION}${COLOR_RESET}" + log "${SYM_INFO} Mögliche Optionen: check | repair | truncate | dropassets | dropall" + return 1 + ;; + esac +} + +# todo: Wenn die Parameter der Eingabe nicht stimmt, ausgeben was fehlt und der Aufruf der Funktion anzeigen: + +###* load und save oar und iar + +# - $1: Der Name des Besitzers. +# - $2: Das Verzeichnis, in das das IAR geladen werden soll +# - $3: Das Passwort fuer das IAR +# - $4: Der Dateiname des IAR +# bash osmtool.sh loadinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar" +function loadinventar() { + # Letzte Bearbeitung 30.09.2023 + LOADINVSCREEN="sim1" + NAME=$1 + VERZEICHNIS=$2 + local PASSWORD=$3 + DATEI=$4 + + if [ $# -ne 4 ]; then + echo "Falsche Anzahl an Parametern." + echo 'Verwendung: bash osmtool.sh loadinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar"' + return 1 + fi + + # Benutzer um Bestätigung fragen + echo "Soll die Datei '$DATEI' von '$VERZEICHNIS' für '$NAME' hochgeladen werden? (j/n)" + read -r ANTWORT + + if [[ "$ANTWORT" != "j" ]]; then + echo "Upload abgebrochen." + return 1 + fi + + # ueberpruefen, ob der 'screen'-Prozess existiert. + if screen -list | grep -q "$LOADINVSCREEN"; then + log "OSCOMMAND: load iar $NAME $VERZEICHNIS ***** $DATEI" + screen -S "$LOADINVSCREEN" -p 0 -X eval "stuff 'load iar $NAME $VERZEICHNIS $PASSWORD $DATEI'^M" + return 0 + else + log error "OSCOMMAND: Der Screen $LOADINVSCREEN existiert nicht" + return 1 + fi +} + +# $1 - Name des Inventars +# $2 - Verzeichnis, in dem das Inventar gespeichert werden soll +# $3 - Passwort (optional) +# $4 - Dateiname, unter dem das Inventar gespeichert wird +#? Verwendungsbeispiel: +# bash osmtool.sh saveinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar" +function saveinventar() { + # Letzte Bearbeitung 01.10.2023 + SAVEINVSCREEN="sim1" + NAME=$1 + VERZEICHNIS=$2 + local PASSWORD=$3 + DATEI=$4 + + if [ $# -ne 4 ]; then + echo "Falsche Anzahl an Parametern." + echo 'Verwendung: bash osmtool.sh saveinventar "Vorname Nachname" "/pfad/zum/verzeichnis" "Benutzerpasswort" "/pfad/zum/Inventarname.iar"' + return 1 + fi + + # Benutzer um Bestätigung fragen + echo "Soll die Datei '$DATEI' von '$VERZEICHNIS' für '$NAME' wirklich gespeichert werden? (j/n)" + read -r ANTWORT + + if [[ "$ANTWORT" != "j" ]]; then + echo "Speichern abgebrochen." + return 1 + fi + + # todo: fragen j/n ob tatsächlich gespeichert werden soll und die Parameter dabei anzeigen + if screen -list | grep -q "$SAVEINVSCREEN"; then + log "OSCOMMAND: save iar $NAME $VERZEICHNIS ***** $DATEI " + screen -S "$SAVEINVSCREEN" -p 0 -X eval "stuff 'save iar $NAME $VERZEICHNIS $PASSWORD $DATEI'^M" + return 0 + else + log "OSCOMMAND: Der Screen $SAVEINVSCREEN existiert nicht" + return 1 + fi +} + +#? Verwendungsbeispiel: +# bash osmtool.sh loadoar "sim1" "TestRegion" "backup.oar" +function loadoar() { + RESTOREVERZEICHNISSCREENNAME=$1 + REGIONSNAME=$2 + OARFILE=$3 + + if [ $# -ne 3 ]; then + echo "Falsche Anzahl an Parametern." + echo 'Verwendung: bash osmtool.sh loadoar "sim1" "TestRegion" "backup.oar"' + return 1 + fi + + # Benutzer um Bestätigung fragen + echo "Soll die Region '$REGIONSNAME' mit der Datei '$OARFILE.oar' wirklich wiederhergestellt werden? (j/n)" + read -r ANTWORT + + if [[ "$ANTWORT" != "j" ]]; then + echo "Wiederherstellung abgebrochen." + return 1 + fi + + log "OSRESTORE: Region $NSDATEINAME wiederherstellen" + cd /"$SCRIPT_DIR"/"$RESTOREVERZEICHNISSCREENNAME"/bin || return 1 + log "Ich kann nicht pruefen ob die Region im OpenSimulator vorhanden ist." + log "Sollte sie nicht vorhanden sein wird root also alle Regionen wiederhergestellt." + # todo: fragen j/n ob tatsächlich hochgeladen werden soll und die Parameter dabei anzeigen + screen -S "$RESTOREVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'change region ${REGIONSNAME//\"/}'^M" + screen -S "$RESTOREVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'load oar $OARFILE'^M" + + log "OSRESTORE: Region $REGIONSNAME wird wiederhergestellt" + return 0 +} + +# Aufruf: saveoar "sim1" "testregion" "/pfad/zum/backup.oar" +function saveoar() { + local SCREENNAME=$1 + local REGIONNAME=$2 + local OARFILE=$3 + + if [ $# -ne 3 ]; then + echo "Falsche Anzahl an Parametern." + echo 'Verwendung: bash osmtool.sh saveoar "sim1" "testregion" "/pfad/zum/backup.oar"' + return 1 + fi + + # Prüfen, ob alle Parameter gesetzt sind + if [[ -z "$SCREENNAME" || -z "$REGIONNAME" || -z "$OARFILE" ]]; then + echo "Fehler: Screen-Name, Regionsname und OAR-Datei müssen angegeben werden!" + return 1 + fi + + # Benutzer um Bestätigung fragen + echo "Soll die Region '$REGIONNAME' wirklich in '$OARFILE' gesichert werden? (j/n)" + read -r ANTWORT + + if [[ "$ANTWORT" != "j" ]]; then + echo "Speicherung abgebrochen." + return 1 + fi + + # Prüfen, ob der Screen existiert + if ! screen -list | grep -q "$SCREENNAME"; then + echo "$SCREENNAME" + echo "Fehler: Der Screen '$SCREENNAME' existiert nicht!" + return 1 + fi + + # Region auswählen und OAR-Datei speichern + echo "Sichere Region '$REGIONNAME' in '$OARFILE'..." + screen -S "$SCREENNAME" -p 0 -X eval "stuff 'change region $REGIONNAME'^M" + screen -S "$SCREENNAME" -p 0 -X eval "stuff 'save oar \"$OARFILE\"'^M" + + echo "Region erfolgreich gesichert!" + return 0 +} + +# bash osmtool.sh autoregionbackup +function autoregionbackup() { + # Konfiguration + local BACKUP_ROOT="$SCRIPT_DIR/backup" # Relativer Pfad + local BACKUP_WAIT=180 # 180, 300 , 500 Wartezeit zwischen Backups, zu kleine Werte uberfordern den Server. + DATUM=$(date +%Y%m%d_%H%M%S) + + # Backup-Verzeichnis erstellen + mkdir -p "$BACKUP_ROOT" || { + echo "FEHLER: Backup-Verzeichnis konnte nicht erstellt werden" + return 1 + } + + # Funktion zum Extrahieren des Regionsnamens aus der INI-Datei + get_region_name() { + local ini_file="$1" + # Extrahiere den Namen zwischen [ ] + grep -oP '^\[\K[^\]]+' "$ini_file" | head -1 + } + + # Durchsuche alle simX/bin/Regions-Verzeichnisse + for ((i=1; i<=999; i++)); do + local sim_name="sim$i" + local regions_dir="$sim_name/bin/Regions" + + if [[ -d "$sim_name/bin" && -d "$regions_dir" ]]; then + echo "Verarbeite Simulator: $sim_name" + + # Backup-Verzeichnis erstellen + mkdir -p "$BACKUP_ROOT/$sim_name" || { + echo "FEHLER: Backup-Verzeichnis konnte nicht erstellt werden" + return 1 + } + + # Verarbeite jede Regions-Konfiguration + for region_file in "$regions_dir"/*.ini; do + [[ -f "$region_file" ]] || continue + + # Extrahiere den echten Regionsnamen aus der INI-Datei (mit Leerzeichen) + display_name=$(get_region_name "$region_file") + safe_name=$(basename "$region_file" .ini) # Dateiname als Fallback + + # Verwende den echten Namen wenn vorhanden, sonst Dateinamen + local region_name=${display_name:-$safe_name} + safe_filename=$(echo "$region_name" | tr ' ' '_') # Für Dateinamen + + # Überspringe Offline-Regionen + if [[ -f "$region_file.offline" ]]; then + echo "Überspringe offline Region: $region_name" + continue + fi + + echo "Starte Backup von: $sim_name $region_name" + + # 1. Region auswählen (mit Originalname und Leerzeichen) + screen -S "$sim_name" -p 0 -X eval "stuff 'change region \"${region_name//\"/}\"'^M" + echo "change region \"$region_name\"" + sleep 1 + + # 2. OAR-Backup (mit safe_filename) + screen -S "$sim_name" -p 0 -X eval "stuff 'save oar \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.oar\"'^M" + echo "Backup: $DATUM-${safe_filename}.oar" + sleep 1 + + # 3. XML2-Backup + screen -S "$sim_name" -p 0 -X eval "stuff 'save xml2 \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.xml2\"'^M" + echo "Backup: $DATUM-${safe_filename}.xml2" + sleep 1 + + # 4. Terrain-Backups + screen -S "$sim_name" -p 0 -X eval "stuff 'terrain save \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.png\"'^M" + screen -S "$sim_name" -p 0 -X eval "stuff 'terrain save \"$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.raw\"'^M" + echo "Terrain: $DATUM-${safe_filename}.png/.raw" + sleep 1 + + # 5. Regions-Konfiguration kopieren + if [[ -f "$region_file" ]]; then + cp "$region_file" "$BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.ini" + echo "Kopiere: $DATUM-${safe_filename}.ini" + sleep 1 + fi + + echo "Erstelle Backup: $BACKUP_ROOT/$sim_name/$DATUM-${safe_filename}.*" + sleep "$BACKUP_WAIT" + done + fi + done + + echo "Backup aller Regionen abgeschlossen" + return 0 +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Bereinigen des OpenSimulators Grids +#?────────────────────────────────────────────────────────────────────────────────────────── + +function dataclean() { + log "${COLOR_HEADING}🧹 Datenbereinigung wird durchgeführt...${COLOR_RESET}" + + # RobustServer bereinigen + if [[ -d "robust/bin" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Lösche Dateien im RobustServer...${COLOR_RESET}" + find "robust/bin" -maxdepth 1 -type f \( -name "*.log" -o -name "*.dll" -o -name "*.exe" -o -name "*.so" -o -name "*.xml" -o -name "*.dylib" -o -name "*.example" -o -name "*.sample" -o -name "*.txt" -o -name "*.config" -o -name "*.py" -o -name "*.old" -o -name "*.pdb" \) -delete + fi + + # Alle simX-Server bereinigen + for ((i=1; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Lösche Dateien in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" + find "$sim_dir" -maxdepth 1 -type f \( -name "*.log" -o -name "*.dll" -o -name "*.exe" -o -name "*.so" -o -name "*.xml" -o -name "*.dylib" -o -name "*.example" -o -name "*.sample" -o -name "*.txt" -o -name "*.config" -o -name "*.py" -o -name "*.old" -o -name "*.pdb" \) -delete + sleep 1 + fi + done + log "${COLOR_HEADING}${SYM_OKNN} Datenbereinigung abgeschlossen${COLOR_RESET}" + blankline +} + +function pathclean() { + directories=("assetcache" "maptiles" "MeshCache" "j2kDecodeCache" "ScriptEngines" "bakes" "addon-modules") + wildcard_dirs=("addin-db-*") # Separate Liste für Wildcard-Verzeichnisse + + log "${COLOR_HEADING}🗂️ Verzeichnisbereinigung wird durchgeführt...${COLOR_RESET}" + + # RobustServer bereinigen + if [[ -d "robust/bin" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Lösche komplette Verzeichnisse im RobustServer...${COLOR_RESET}" + + # Normale Verzeichnisse + for dir in "${directories[@]}"; do + target="robust/bin/$dir" + if [[ -d "$target" ]]; then + rm -rf "$target" + log " ${COLOR_ACTION}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" + fi + done + + # Wildcard-Verzeichnisse + for pattern in "${wildcard_dirs[@]}"; do + for target in robust/bin/$pattern; do + if [[ -d "$target" ]]; then + rm -rf "$target" + log " ${COLOR_WARNING}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" + fi + done + done + fi + + # Alle simX-Server bereinigen + for ((i=1; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Lösche komplette Verzeichnisse in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" + + # Normale Verzeichnisse + for dir in "${directories[@]}"; do + target="$sim_dir/$dir" + if [[ -d "$target" ]]; then + rm -rf "$target" + log " ${COLOR_ACTION}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" + sleep 1 + fi + done + + # Wildcard-Verzeichnisse + for pattern in "${wildcard_dirs[@]}"; do + for target in $sim_dir/$pattern; do + if [[ -d "$target" ]]; then + rm -rf "$target" + log " ${COLOR_WARNING}Verzeichnis gelöscht: ${COLOR_DIR}$target${COLOR_RESET}" + fi + done + done + fi + done + log "${COLOR_HEADING}${SYM_OKNN} Verzeichnisbereinigung abgeschlossen${COLOR_RESET}" + blankline +} + +function cacheclean() { + #cache_dirs=("assetcache" "maptiles" "MeshCache" "j2kDecodeCache" "ScriptEngines") + cache_dirs=("assetcache" "MeshCache" "j2kDecodeCache" "ScriptEngines") + + log "${COLOR_HEADING}♻️ Cache-Bereinigung wird durchgeführt...${COLOR_RESET}" + + # RobustServer bereinigen + if [[ -d "robust/bin" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Leere Cache-Verzeichnisse im RobustServer...${COLOR_RESET}" + for dir in "${cache_dirs[@]}"; do + target="robust/bin/$dir" + if [[ -d "$target" ]]; then + find "$target" -mindepth 1 -delete + log " ${COLOR_ACTION}Inhalt geleert: ${COLOR_DIR}$target${COLOR_RESET}" + fi + done + fi + + # Alle simX-Server bereinigen + for ((i=1; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Leere Cache-Verzeichnisse in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" + for dir in "${cache_dirs[@]}"; do + target="$sim_dir/$dir" + if [[ -d "$target" ]]; then + find "$target" -mindepth 1 -delete + log " ${COLOR_ACTION}Inhalt geleert: ${COLOR_DIR}$target${COLOR_RESET}" + sleep 1 + fi + done + fi + done + log "${COLOR_HEADING}${SYM_OKNN} Cache-Bereinigung abgeschlossen${COLOR_RESET}" + blankline +} + +function logclean() { + log "${SYM_LOG}${COLOR_HEADING} Log-Bereinigung wird durchgeführt...${COLOR_RESET}" + + # RobustServer bereinigen + if [[ -d "robust/bin" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Lösche Log-Dateien in ${COLOR_DIR}robust/bin...${COLOR_RESET}" + rm -f robust/bin/*.log + fi + + # Alle simX-Server bereinigen (sim1 bis sim999) + for ((i=1; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" ]]; then + log "${SYM_OK} ${COLOR_ACTION}Lösche Log-Dateien in ${COLOR_DIR}$sim_dir...${COLOR_RESET}" + rm -f "$sim_dir"/*.log + sleep 1 + fi + done + + log "${COLOR_HEADING}Log-Bereinigung abgeschlossen${COLOR_RESET}" + blankline +} + +function mapclean() { + log "${COLOR_HEADING}🗺️ Map-Tile-Bereinigung wird durchgeführt...${COLOR_RESET}" + + # Sicherheitscheck für robust/bin/maptiles + if [[ -d "robust/bin/maptiles" ]]; then + rm -rf -- "robust/bin/maptiles/"* + log "${SYM_OK} ${COLOR_ACTION}robust/bin/maptiles geleert${COLOR_RESET}" + fi + + # Sicherheitscheck für alle simX/bin/maptiles + for ((i=1; i<=999; i++)); do + local sim_dir="sim$i/bin/maptiles" + if [[ -d "$sim_dir" ]]; then + # shellcheck disable=SC2115 + rm -rf -- "${sim_dir}/"* + log "${SYM_OK} ${COLOR_ACTION}${COLOR_DIR}$sim_dir${COLOR_RESET} ${COLOR_ACTION}geleert${COLOR_RESET}" + sleep 1 + fi + done + + log "${COLOR_HEADING}${SYM_OKNN} Map-Tile-Bereinigung abgeschlossen${COLOR_RESET}" + blankline +} + +function autoallclean() { + local confirm + + # Warnung in Gelb (konsistenter mit \e anstelle von \033) + log "\e[33m" + cat >&2 <<'WARNUNG' +=== WARNUNG: Alle Daten-, Verzeichnis-, Cache-, Log- und Map-Daten werden bereinigt! === +=== DIESE OPERATION KANN NICHT RÜCKGÄNGIG GEMACHT WERDEN! === +=== DER OPENSIMULATOR MUSS IM ANSCHLUSS NEU INSTALLIERT WERDEN! === +WARNUNG + log "\e[0m" + + # Bestätigung mit Timeout (10 Sekunden) für Sicherheit + read -t 30 -r -p "$(msg PROMPT_CONTINUE_TIMEOUT_YESNO) " confirm || { + log "\n\e[31mTimeout: Keine Bestätigung erhalten. Abbruch.\e[0m" >&2 + return 1 + } + + if is_yes "$confirm"; then + log "\e[32mBereinigung wird gestartet...\e[0m" >&2 + # Jede Clean-Funktion mit Fehlerprüfung + local clean_functions=(dataclean pathclean cacheclean logclean mapclean) + for func in "${clean_functions[@]}"; do + if ! command -v "$func" &>/dev/null; then + log "\e[31mFehler: '$func' ist keine gültige Funktion!\e[0m" >&2 + return 1 + fi + "$func" || { + log "\e[31mFehler bei $func!\e[0m" >&2 + return 1 + } + done + log "\e[32mBereinigung abgeschlossen.\e[0m" >&2 + else + log "\e[33mAbbruch: Bereinigung wurde nicht durchgeführt.\e[0m" >&2 + return 1 + fi + blankline +} + +function clean_linux_logs() { + local log_files=() + log "${COLOR_SECTION}${SYM_LOG} Suche nach alten Log-Dateien...${COLOR_RESET}" + + # Find and list files to be deleted + while IFS= read -r -d $'\0' file; do + log_files+=("$file") + log "${COLOR_FILE}${SYM_INFO} ${COLOR_LABEL}Gelöscht wird:${COLOR_RESET} ${COLOR_VALUE}$file${COLOR_RESET}" + done < <(find "/var/log" -name "*.log" -type f -mtime +7 -print0) + + if [ ${#log_files[@]} -eq 0 ]; then + log "${SYM_OK} ${COLOR_LABEL}Keine alten Log-Dateien gefunden.${COLOR_RESET}" + return 0 + fi + + log "${COLOR_WARNING}${#log_files[@]} Log-Dateien werden gelöscht. Fortfahren? (j/N) ${COLOR_RESET}" + read -r confirm + case "${confirm,,}" in + j|ja|y|yes) + find "/var/log" -name "*.log" -type f -mtime +7 -delete + log "${SYM_OK} ${COLOR_OK}${#log_files[@]} Log-Dateien wurden gelöscht.${COLOR_RESET}" + ;; + *) + log "${SYM_BAD} ${COLOR_BAD}Bereinigung abgebrochen.${COLOR_RESET}" + return 1 + ;; + esac +} + +function delete_opensim() { + log "${COLOR_HEADING}🗺️ Das komplette löschen vom OpenSimulator wird durchgeführt...${COLOR_RESET}" + + # Sicherheitsabfrage hinzufügen + read -rp "Sind Sie sicher, dass Sie ALLE OpenSimulator-Daten löschen möchten? (ja/N) " answer + [[ ${answer,,} != "ja" ]] && { echo "Abbruch."; return 1; } + + # Robust-Verzeichnis sicher löschen + if [[ -d "robust" ]]; then + rm -rf -- "robust" # Keine Wildcard mehr + log "${SYM_OK} ${COLOR_ACTION}robust komplett entfernt${COLOR_RESET}" + fi + + # Simulator-Verzeichnisse sicher löschen + for ((i=1; i<=999; i++)); do + local sim_dir="sim$i" + if [[ -d "$sim_dir" ]]; then + rm -rf -- "$sim_dir" # Keine Wildcard mehr + log "${SYM_OK} ${COLOR_ACTION}${COLOR_DIR}$sim_dir${COLOR_RESET} ${COLOR_ACTION}komplett entfernt${COLOR_RESET}" + sleep 1 + fi + done + + log "${COLOR_HEADING}${SYM_OKNN} Das komplette löschen vom OpenSimulator abgeschlossen${COLOR_RESET}" + blankline +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Konfigurationen +#?────────────────────────────────────────────────────────────────────────────────────────── + +# [Abschnitt] +# Schlüssel = Wert +# ; Kommentar +# [Section] +# Key = Value +# ; Comment + +# Überprüft, ob ein bestimmter Abschnitt (Section) in einer INI-Datei existiert, und gibt das Ergebnis als Exit-Code zurück. +# Aufruf: bash osmtool.sh verify_ini_section "test.ini" "Const" +# Letzte Prüfung am: 24.04.2025 +function verify_ini_section() { + local file="$1" + local section="$2" + + if [ ! -f "$file" ]; then + log "${SYM_BAD} Error: File ${file} does not exist" >&2 + return 2 + fi + + if grep -q "^\[${section}\]" "$file"; then + log "${SYM_OK} Section [${section}] exists in ${file}" + return 0 + else + log "${SYM_BAD} Section [${section}] not found in ${file}" + return 1 + fi +} + +# Überprüft, ob ein bestimmten Wert (key) im Abschnitt (Section) in einer INI-Datei existiert, und gibt das Ergebnis als Exit-Code zurück. +# Aufruf: bash osmtool.sh verify_ini_key "test.ini" "DatabaseService" "Include-Storage" +# Letzte Prüfung am: 24.04.2025 Repariert: 24.04.2025 +function verify_ini_key() { + local file="$1" + local section="$2" + local key="$3" + + if [ ! -f "$file" ]; then + log "${SYM_BAD} Error: File ${file} does not exist" >&2 + return 2 + fi + + # Einfacher grep-Befehl, der Leerzeichen & Kommentare ignoriert + if grep -Eq "^[[:space:]]*\[${section}\][[:space:]]*$" "$file" && \ + grep -Eq "^[[:space:]]*${key}[[:space:]]*=" "$file"; then + log "${SYM_OK} Key '${key}' exists in section [${section}]" + return 0 + else + log "${SYM_BAD} Key '${key}' NOT FOUND in section [${section}]" >&2 + return 1 + fi +} + +# Fügt einene Abschnitt hinzu, wenn es noch nicht vorhanden ist am ende der Datei. +# Aufruf: bash osmtool.sh add_ini_section "test.ini" "Const" +# Letzte Prüfung am: 24.04.2025 +function add_ini_section() { + local file="$1" + local section="$2" + + if verify_ini_section "$file" "$section" >/dev/null; then + return 0 + fi + + log "${SYM_INFO} Adding section [${section}] to ${file}" + + # Abschnitt am Ende der Datei hinzufügen + if printf "\n[%s]\n" "$section" >> "$file"; then + log "${SYM_OK} Successfully added section [${section}] to ${file}" + return 0 + else + log "${SYM_BAD} Failed to add section [${section}] to ${file}" >&2 + return 1 + fi +} + +# Fügt einene Abschnitt, wenn es noch nicht vorhanden ist vor dem Zielabschnitt hinzu. +# Also [Const] wird vor [DatabaseService] hinzugefügt. +# Aufruf: bash osmtool.sh add_ini_before_section "test.ini" "Const" "DatabaseService" +function add_ini_before_section() { + local file="$1" + local section="$2" + local target_section="$3" # Neuer Parameter für den Zielabschnitt + + if verify_ini_section "$file" "$section" >/dev/null; then + return 0 + fi + + #log "${SYM_INFO} Adding section [${section}] to ${file} before [${target_section}]" + + # Temporäre Datei erstellen + temp_file=$(mktemp) + + # Zielabschnitt suchen und neuen Abschnitt davor einfügen + local found=0 + while IFS= read -r line; do + if [[ "$line" =~ ^\[${target_section}\] ]]; then + printf "[%s]\n\n" "$section" >> "$temp_file" + found=1 + fi + echo "$line" >> "$temp_file" + done < "$file" + + # Falls Zielabschnitt nicht gefunden, am Ende einfügen (Fallback) + if [[ $found -eq 0 ]]; then + printf "\n[%s]\n" "$section" >> "$temp_file" + log "${SYM_WARNING} Target section [${target_section}] not found, appended [${section}] at end of file" + fi + + # Originaldatei ersetzen + if mv "$temp_file" "$file"; then + log "${SYM_OK} Successfully added section [${section}] to ${file}" + return 0 + else + log "${SYM_BAD} Failed to update ${file}" >&2 + return 1 + fi +} + +# Setzt den Wert des Keys in der gegebenen Sektion +# bash osmtool.sh set_ini_key "test.ini" "Const" "GridSize" "256" +# [Const] +# GridSize = 256 +# +# Wenn die Sektion oder der Key nicht vorhanden ist, wird er hinzugefügt. +# Falls der Key bereits vorhanden ist, wird der Wert aktualisiert. +function set_ini_key() { + local file="$1" section="$2" key="$3" value="$4" + local temp_file + temp_file=$(mktemp) || { + log "${COLOR_BAD}Fehler beim Erstellen der temporären Datei${COLOR_RESET}" >&2 + return 1 + } + + # Key für Regex absichern + local key_escaped + key_escaped=$(printf '%s\n' "$key" | sed 's/[]\/$*.^[]/\\&/g') + + # Verarbeitung mit awk + awk -v section="[$section]" -v key="$key" -v value="$value" -v key_re="$key_escaped" ' + BEGIN { in_section = 0; key_set = 0 } + + { + trimmed = $0 + sub(/^[[:space:]]+/, "", trimmed) + if (trimmed == section) { + print + in_section = 1 + next + } + + if (in_section && trimmed ~ /^\[.*\]/) { + if (!key_set) { + printf "%s = %s\n\n", key, value + key_set = 1 + } + in_section = 0 + } + + if (in_section && $0 ~ "^[[:blank:]]*" key_re "[[:blank:]]*=") { + printf "%s = %s\n", key, value + key_set = 1 + next + } + + print + } + + END { + if (in_section && !key_set) { + printf "%s = %s\n", key, value + } else if (!key_set) { + printf "\n[%s]\n%s = %s\n", section, key, value + } + }' "$file" > "$temp_file" || { + log "${COLOR_BAD}AWK-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 + rm -f "$temp_file" + return 1 + } + + if ! mv "$temp_file" "$file"; then + log "${COLOR_BAD}Konnte Datei ${COLOR_FILE}${file}${COLOR_RESET} nicht aktualisieren" >&2 + rm -f "$temp_file" + return 1 + fi + + log "${COLOR_OK}Gesetzt: ${COLOR_KEY}${key} = ${COLOR_VALUE}${value}${COLOR_OK} in [${section}]${COLOR_RESET}" + return 0 +} + +# Setze einen Key in einer INI-Datei +# Die INI-Datei wird nach dem Schlüssel durchsucht und der Key wird +# am passenden Ort eingefügt. +function add_ini_key() { + local file="$1" section="$2" key="$3" value="$4" + local temp_file + temp_file=$(mktemp) || { + log "${COLOR_BAD}Failed to create temp file${COLOR_RESET}" >&2 + return 1 + } + + # Verarbeitung mit awk + if ! awk -v section="[${section}]" -v key="$key" -v value="$value" ' + BEGIN { in_section = 0; modified = 0 } + $0 == section { in_section = 1; print; next } + in_section && /^\[/ { + # Neue Sektion beginnt, Key einfügen (mit Leerzeichen um das =) + printf "%s = %s\n\n", key, value + modified = 1 + in_section = 0 + } + in_section && $0 ~ "^[[:blank:]]*" key "[[:blank:]]*=" { + # Existierenden Key ersetzen (mit Leerzeichen um das =) + printf "%s = %s\n", key, value + modified = 1 + in_section = 0 + next + } + { print } + END { + if (!modified && in_section) { + # Am Ende der Sektion einfügen (mit Leerzeichen um das =) + printf "%s = %s\n", key, value + } else if (!modified) { + # Neue Sektion am Dateiende (mit Leerzeichen um das =) + printf "\n[%s]\n%s = %s\n", section, key, value + } + } + ' "$file" > "$temp_file"; then + log "${COLOR_BAD}AWK processing failed${COLOR_RESET}" >&2 + rm -f "$temp_file" + return 1 + fi + + if ! mv "$temp_file" "$file"; then + log "${COLOR_BAD}Failed to update ${COLOR_FILE}${file}${COLOR_RESET}" >&2 + return 1 + fi + + log "${COLOR_OK}Set ${COLOR_KEY}${key} = ${COLOR_VALUE}${value}${COLOR_OK} in [${section}]${COLOR_RESET}" + return 0 +} + +function del_ini_section() { + local file="$1" + local section="$2" + + # Verifizieren ob der Abschnitt existiert (still, ohne Ausgabe) + if ! verify_ini_section "$file" "$section" >/dev/null; then + log "${SYM_INFO} Section [${section}] not found in ${COLOR_FILE}${file}${COLOR_RESET}" + return 0 + fi + + log "${SYM_INFO} Removing section [${COLOR_SECTION}${section}${COLOR_RESET}] from ${COLOR_FILE}${file}${COLOR_RESET}" + + # Temporäre Datei mit Fehlerbehandlung + local temp_file + temp_file=$(mktemp) || { + log "${SYM_BAD} Failed to create temporary file" >&2 + return 1 + } + + # Abschnitt entfernen + if awk -v section="[${section}]" ' + $0 == section { skip=1; next } + skip && /^\[/ { skip=0 } + !skip { print } + ' "$file" > "$temp_file"; then + + if mv "$temp_file" "$file"; then + log "${SYM_OK} Successfully removed section [${COLOR_SECTION}${section}${COLOR_RESET}]" + return 0 + else + log "${SYM_BAD} Failed to update ${COLOR_FILE}${file}${COLOR_RESET}" >&2 + rm -f "$temp_file" + return 1 + fi + + else + log "${SYM_BAD} AWK processing failed" >&2 + rm -f "$temp_file" + return 1 + fi +} + +function uncomment_ini_line() { + local file="$1" + local search_key="$2" + + # Sicherheitsprüfungen + [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } + [ -z "$search_key" ] && { log "${COLOR_BAD}Suchschlüssel darf nicht leer sein${COLOR_RESET}" >&2; return 1; } + + # Temporäre Datei erstellen + local temp_file + temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } + + # Entkommentieren der Zeile + sed -E "/^[[:space:]]*;[[:space:]]*${search_key}[[:space:]]*=/s/^[[:space:]]*;//" "$file" > "$temp_file" || { + rm -f "$temp_file" + log "${COLOR_BAD}Sed-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 + return 1 + } + + # Originaldatei ersetzen + if mv "$temp_file" "$file"; then + log "${COLOR_OK}Zeile '${search_key}' erfolgreich entkommentiert${COLOR_RESET}" + return 0 + else + log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 + return 1 + fi +} + +function uncomment_ini_section_line() { + local file="$1" + local section="$2" + local search_key="$3" + + # Sicherheitsprüfungen + [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } + [ -z "$section" ] && { log "${COLOR_BAD}Sektion darf nicht leer sein${COLOR_RESET}" >&2; return 1; } + [ -z "$search_key" ] && { log "${COLOR_BAD}Suchschlüssel darf nicht leer sein${COLOR_RESET}" >&2; return 1; } + + # Temporäre Datei erstellen + local temp_file + temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } + + # Entkommentieren der Zeile in der richtigen Sektion + awk -v section="[$section]" -v key="$search_key" ' + BEGIN { in_section = 0 } + $0 ~ "^\\[" section "\\]" { in_section = 1; print; next } + in_section && /^\[/ { in_section = 0 } # Sektion beendet + in_section && /^[[:space:]]*;[[:space:]]*"key"[[:space:]]*=[[:space:]]*/ { + sub(/^[[:space:]]*;/, "", $0) + } + { print } + ' "$file" > "$temp_file" || { + rm -f "$temp_file" + log "${COLOR_BAD}AWK-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 + return 1 + } + + # Originaldatei ersetzen + if mv "$temp_file" "$file"; then + log "${COLOR_OK}Zeile '${search_key}' in Sektion '${section}' erfolgreich entkommentiert${COLOR_RESET}" + return 0 + else + log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 + return 1 + fi +} +function comment_ini_line() { + local file="$1" + local section="$2" + local search_key="$3" + + # Sicherheitsprüfungen + [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } + [ -z "$section" ] && { log "${COLOR_BAD}Sektion darf nicht leer sein${COLOR_RESET}" >&2; return 1; } + [ -z "$search_key" ] && { log "${COLOR_BAD}Suchschlüssel darf nicht leer sein${COLOR_RESET}" >&2; return 1; } + + # Temporäre Datei erstellen + local temp_file + temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } + + # Zeile in der richtigen Sektion kommentieren + awk -v section="[$section]" -v key="$search_key" ' + BEGIN { in_section = 0 } + $0 ~ "^\\[" section "\\]" { in_section = 1; print; next } + in_section && /^\[/ { in_section = 0 } + in_section && $0 ~ key && !/^[[:space:]]*;/ { + # Nur nicht bereits kommentierte Zeilen kommentieren + sub(/^[[:space:]]*/, "&;", $0) + print $0 + next + } + { print } + ' "$file" > "$temp_file" || { + rm -f "$temp_file" + log "${COLOR_BAD}AWK-Verarbeitung fehlgeschlagen${COLOR_RESET}" >&2 + return 1 + } + + # Originaldatei ersetzen + if mv "$temp_file" "$file"; then + log "${COLOR_OK}Zeile '${search_key}' in Sektion '${section}' erfolgreich kommentiert${COLOR_RESET}" + return 0 + else + log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 + return 1 + fi +} + +function clear_ini_section() { + local file="$1" + local section="$2" + + # Sicherheitsprüfungen + [ ! -f "$file" ] && { log "${COLOR_BAD}Datei nicht gefunden: ${file}${COLOR_RESET}" >&2; return 1; } + [ -z "$section" ] && { log "${COLOR_BAD}Sektion darf nicht leer sein${COLOR_RESET}" >&2; return 1; } + + # Temporäre Datei erstellen + local temp_file + temp_file=$(mktemp) || { log "${COLOR_BAD}Temp-Datei konnte nicht erstellt werden${COLOR_RESET}" >&2; return 1; } + + # AWK zum Leeren der Sektion (behält Header) + awk -v section="$section" ' + BEGIN { in_section = 0 } + + # Sektionsanfang erkennen + $0 ~ "^\\[" section "\\]" { + in_section = 1 + print $0 # Header ausgeben + next + } + + # Sektionsende erkennen + in_section && /^\[/ { + in_section = 0 + } + + # Innerhalb der Sektion: nichts ausgeben (löschen) + in_section { next } + + # Außerhalb der Sektion: normale Ausgabe + { print } + ' "$file" > "$temp_file" + + # Originaldatei ersetzen + if mv "$temp_file" "$file"; then + log "${COLOR_OK}Sektion '[${section}]' erfolgreich geleert${COLOR_RESET}" + return 0 + else + log "${COLOR_BAD}Datei konnte nicht aktualisiert werden${COLOR_RESET}" >&2 + return 1 + fi +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Konfigurationen der einzelnen Dienste +#?────────────────────────────────────────────────────────────────────────────────────────── + +# [Abschnitt] +# Schlüssel = Wert +# ; Kommentar +# [Section] +# Key = Value +# ; Comment + + +function database_set_iniconfig() { + # 30.04.2025 + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + local section="DatabaseService" + + # Zugangsdaten auslesen + local db_user db_pass + # Zeilenumbrüche entfernen + db_user=$(grep -oP '^DB_Benutzername\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') + db_pass=$(grep -oP '^DB_Passwort\s*=\s*\K\S+' "$ini_file" | tr -d '\r\n') + + + if [[ -z "$db_user" || -z "$db_pass" ]]; then + log "${COLOR_BAD}DB_Benutzername oder DB_Passwort fehlt in UserInfo.ini${COLOR_RESET}" + return 1 + fi + + # === Robust-Datenbanken === + local db_database="robust" + local robust_conn="Data Source=localhost;Database=${db_database};User ID=${db_user};Password=${db_pass};Old Guids=true;SslMode=None;" + + # Robust.HG.ini + local robust_hg_ini="robust/bin/Robust.HG.ini" + if [[ -f "$robust_hg_ini" ]]; then + add_ini_key "$robust_hg_ini" "$section" "ConnectionString" "\"$robust_conn\"" + else + log "${COLOR_WARNING}Datei nicht gefunden: $robust_hg_ini${COLOR_RESET}" + fi + + # Robust.local.ini + local robust_ini="robust/bin/Robust.local.ini" + if [[ -f "$robust_ini" ]]; then + add_ini_key "$robust_ini" "$section" "ConnectionString" "\"$robust_conn\"" + else + log "${COLOR_WARNING}Datei nicht gefunden: $robust_ini${COLOR_RESET}" + fi + + # === simX-Datenbanken === + for ((i=1; i<=1000; i++)); do + local sim_ini="${SCRIPT_DIR}/sim${i}/bin/config-include/GridCommon.ini" + if [[ -f "$sim_ini" ]]; then + local sim_conn="Data Source=localhost;Database=sim${i};User ID=${db_user};Password=${db_pass};Old Guids=true;SslMode=None;" + add_ini_key "$sim_ini" "$section" "ConnectionString" "\"$sim_conn\"" + fi + done + + log "${COLOR_OK}Datenbanken erfolgreich konfiguriert${COLOR_RESET}" + blankline +} + + + +# Welcome-Region konfigurieren wenn sie noch nicht existiert. +function welcomeiniconfig() { + # 25.04.2025 + local ip="$1" + gridname="$2" + + # Gridname bereinigen + gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') + + local welcome_ini="${SCRIPT_DIR}/sim1/bin/Regions/$gridname.ini" + + # Überprüfen ob die Welcome-Region bereits existiert + if [[ -f "$welcome_ini" ]]; then + log "${COLOR_INFO}Überspringe Erstellung der Welcome-Region: '$gridname.ini' existiert bereits${COLOR_RESET}" + # Vorsichtshalber Region in Robust-Konfigurationen eintragen. + set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.HG.ini" "GridService" "Region_$gridname" "\"DefaultRegion, DefaultHGRegion, FallbackRegion\"" + set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.local.ini" "GridService" "Region_$gridname" "\"DefaultRegion, FallbackRegion\"" + return + fi + + # region_uuid=$(uuidgen) + #region_uuid=$(command -v uuidgen >/dev/null && uuidgen || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") + region_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") + + # Datei erstellen + #touch "$welcome_ini" + #touch "$welcome_ini" || echo "" > "$welcome_ini" + touch "$welcome_ini" 2>/dev/null || echo "" > "$welcome_ini" + + # 2. Sektion hinzufügen + add_ini_section "$welcome_ini" "$gridname" + + # 3. Alle Key-Value Paare setzen + set_ini_key "$welcome_ini" "$gridname" "RegionUUID" "$region_uuid" + set_ini_key "$welcome_ini" "$gridname" "Location" "3000,3000" + set_ini_key "$welcome_ini" "$gridname" "SizeX" "256" + set_ini_key "$welcome_ini" "$gridname" "SizeY" "256" + set_ini_key "$welcome_ini" "$gridname" "SizeZ" "256" + set_ini_key "$welcome_ini" "$gridname" "InternalPort" "9015" + set_ini_key "$welcome_ini" "$gridname" "ExternalHostName" "$system_ip" + set_ini_key "$welcome_ini" "$gridname" "MaxPrims" "15000" + set_ini_key "$welcome_ini" "$gridname" "MaxAgents" "40" + set_ini_key "$welcome_ini" "$gridname" "MaptileStaticUUID" "$region_uuid" + set_ini_key "$welcome_ini" "$gridname" "InternalAddress" "0.0.0.0" + set_ini_key "$welcome_ini" "$gridname" "AllowAlternatePorts" "False" + + set_ini_key "$welcome_ini" "$gridname" ";NonPhysicalPrimMax" "512" + set_ini_key "$welcome_ini" "$gridname" ";PhysicalPrimMax" "128" + set_ini_key "$welcome_ini" "$gridname" ";ClampPrimSize" "false" + set_ini_key "$welcome_ini" "$gridname" ";MaxPrimsPerUser" "-1" + set_ini_key "$welcome_ini" "$gridname" ";ScopeID" "$region_uuid" + set_ini_key "$welcome_ini" "$gridname" ";RegionType" "Mainland" + set_ini_key "$welcome_ini" "$gridname" ";RenderMinHeight" "-1" + set_ini_key "$welcome_ini" "$gridname" ";RenderMaxHeight" "100" + set_ini_key "$welcome_ini" "$gridname" ";MapImageModule" "Warp3DImageModule" + set_ini_key "$welcome_ini" "$gridname" ";TextureOnMapTile" "true" + set_ini_key "$welcome_ini" "$gridname" ";DrawPrimOnMapTile" "true" + set_ini_key "$welcome_ini" "$gridname" ";GenerateMaptiles" "true" + set_ini_key "$welcome_ini" "$gridname" ";MaptileRefresh" "0" + set_ini_key "$welcome_ini" "$gridname" ";MaptileStaticFile" "path/to/SomeFile.png" + set_ini_key "$welcome_ini" "$gridname" ";MasterAvatarFirstName" "John" + set_ini_key "$welcome_ini" "$gridname" ";MasterAvatarLastName" "Doe" + set_ini_key "$welcome_ini" "$gridname" ";MasterAvatarSandboxPassword" "passwd" + + # 4. Region in Robust-Konfigurationen eintragen + # DefaultRegion, DefaultHGRegion, FallbackRegion, NoDirectLogin, Persistent, LockedOut, Reservation, NoMove, Authenticate + set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.HG.ini" "GridService" "Region_$gridname" "\"DefaultRegion, DefaultHGRegion, FallbackRegion\"" + set_ini_key "${SCRIPT_DIR}/robust/bin/Robust.local.ini" "GridService" "Region_$gridname" "\"DefaultRegion, FallbackRegion\"" + + log "${COLOR_OK}Welcome_Area.ini Konfiguration abgeschlossen für $gridname${COLOR_RESET}" + blankline +} + +function moneyserveriniconfig() { + # 30.04.2025 + local ip="$1" + gridname="$2" + + # Gridname bereinigen + gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') + + # Zugangsdaten aus UserInfo.ini laden + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + local db_user db_pass + db_user=$(grep -oP '^DB_Benutzername\s*=\s*\K\S+' "$ini_file") + db_pass=$(grep -oP '^DB_Passwort\s*=\s*\K\S+' "$ini_file") + + # Falls keine Benutzer- und Passwortwerte gelesen wurden, abbrechen + if [[ -z "$db_user" || -z "$db_pass" ]]; then + log "${COLOR_BAD}Fehler: DB_Benutzername oder DB_Passwort fehlen in UserInfo.ini${COLOR_RESET}" + return 1 + fi + + local dir="$SCRIPT_DIR/robust/bin" + local file="$dir/MoneyServer.ini" + + # Sicherstellen, dass die Vorlage existiert + if [[ ! -f "$file.example" ]]; then + log "${COLOR_BAD}FEHLER: Konfigurationsvorlage '$file.example' fehlt!${COLOR_RESET}" >&2 + exit 1 + fi + + # Kopieren der Vorlage + cp "$file.example" "$file" || { + log "${COLOR_BAD}FEHLER: Konnte '$file' nicht erstellen${COLOR_RESET}" >&2 + exit 1 + } + + # [Startup] + set_ini_key "$file" "Startup" "PIDFile" "\"/tmp/MoneyServer.exe.pid\"" + + # [MySql] → Daten aus UserInfo.ini verwenden + set_ini_key "$file" "MySql" "hostname" "\"localhost\"" + set_ini_key "$file" "MySql" "database" "\"robust\"" + set_ini_key "$file" "MySql" "username" "\"$db_user\"" + set_ini_key "$file" "MySql" "password" "\"$db_pass\"" + set_ini_key "$file" "MySql" "pooling" "\"true\"" + set_ini_key "$file" "MySql" "port" "\"3306\"" + set_ini_key "$file" "MySql" "MaxConnection" "\"25\"" + + # [MoneyServer] + set_ini_key "$file" "MoneyServer" "ServerPort" "\"8008\"" + set_ini_key "$file" "MoneyServer" "CurrencyOnOff" "\"on\"" + set_ini_key "$file" "MoneyServer" "CurrencyMaximum" "\"20000\"" + set_ini_key "$file" "MoneyServer" "MoneyServerIPaddress" "\"http://$ip:8008\"" + set_ini_key "$file" "MoneyServer" "DefaultBalance" "\"1000\"" + + # [Certificate] + set_ini_key "$file" "Certificate" "CheckClientCert" "\"false\"" + set_ini_key "$file" "Certificate" "CheckServerCert" "\"false\"" + + log "${COLOR_OK}MoneyServer.ini Konfiguration abgeschlossen${COLOR_RESET}" + blankline +} + + +# Konfiguriert OpenSim.ini für alle sim1 bis sim99-Verzeichnisse +function opensiminiconfig() { + # 24.04.2025 + local ip="$1" + local gridname="$2" + local base_port=9010 + local sim_counter=1 + + # Gridname bereinigen + gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') + + # Iteration über alle sim1 bis sim99 Verzeichnisse + for i in $(seq 1 99); do + sim_dir="$SCRIPT_DIR/sim$i" + if [[ -d "$sim_dir/bin" ]]; then + local dir="$sim_dir/bin" + local file="$dir/OpenSim.ini" + + if [[ ! -f "$file.example" ]]; then + echo "FEHLER: Konfigurationsvorlage '$file.example' fehlt!" >&2 + echo "Das Programm benötigt diese Datei zum Starten." >&2 + exit 1 # Programm mit Fehlercode beenden + fi + + # Nur wenn Vorlage existiert: Kopieren + cp "$file.example" "$file" || { + echo "FEHLER: Konnte '$file' nicht erstellen" >&2 + exit 1 + } + + sleep 1 + + log "${COLOR_INFO}Konfiguriere OpenSim.ini in $dir${COLOR_RESET}" + + # Portberechnung pro Instanz + local public_port=$((base_port + (sim_counter - 1) * 100)) + + # Werte setzen + # [Const] + set_ini_key "$file" "Const" "BaseHostname" "$ip" + set_ini_key "$file" "Const" "PublicPort" "8002" + + # [Startup] + #uncomment_ini_section_line "$file" "Startup" "PIDFile" + set_ini_key "$file" "Startup" "PIDFile" "\"/tmp/OpenSim.$i.exe.pid\"" + + # [Estates] + #set_ini_key "$file" "Estates" "DefaultEstateName" "$gridname Estate" + #set_ini_key "$file" "Estates" "DefaultEstateOwnerName" "$VORNAME $NACHNAME" + + # [Network] + # http_listener_port = 9010 + uncomment_ini_section_line "$file" "Network" "http_listener_port" + set_ini_key "$file" "Network" "http_listener_port" "$public_port" + + # [SimulatorFeatures] + uncomment_ini_line "$file" "SearchServerURI" + + # [ClientStack.LindenUDP] Begrenzt die Viewer damit sie die Server leistung nicht kippen können. + set_ini_key "$file" "ClientStack.LindenUDP" "DisableFacelights" "true" + # 10.000.000 bps = 10 Mbit/s pro Client gute Einstellung ist "350.000" bis "500.000" + set_ini_key "$file" "ClientStack.LindenUDP" "client_throttle_max_bps" "350000" + # 10.000.000 bps = 10 Mbit/s pro Region "70.000.000" gute Einstellung ist "70.000.000" bis "1.000.000.000" + set_ini_key "$file" "ClientStack.LindenUDP" "scene_throttle_max_bps" "70000000" + + # [SimulatorFeatures] + set_ini_key "$file" "SimulatorFeatures" "SearchServerURI" "\${Const|BaseURL}:\${Const|PublicPort}" + set_ini_key "$file" "SimulatorFeatures" "DestinationGuideURI" "\${Const|BaseURL}:\${Const|PublicPort}" + + # [Messaging] + set_ini_key "$file" "Messaging" "OfflineMessageModule" "Offline Message Module V2" + set_ini_key "$file" "Messaging" "OfflineMessageURL" "\${Const|PrivURL}:\${Const|PrivatePort}" + set_ini_key "$file" "Messaging" "StorageProvider" "OpenSim.Data.MySQL.dll" + set_ini_key "$file" "Messaging" "MuteListModule" "MuteListModule" + set_ini_key "$file" "Messaging" "ForwardOfflineGroupMessages" "true" + + # [Materials] + set_ini_key "$file" "Materials" "MaxMaterialsPerTransaction" "250" + + # [DataSnapshot] + set_ini_key "$file" "DataSnapshot" "gridname" "$gridname" + + # [Economy] + set_ini_key "$file" "Economy" "SellEnabled" "true" + set_ini_key "$file" "Economy" "EconomyModule" "DTLNSLMoneyModule" + set_ini_key "$file" "Economy" "CurrencyServer" "\${Const|BaseURL}:8008/" + set_ini_key "$file" "Economy" "UserServer" "\${Const|BaseURL}:8002/" + set_ini_key "$file" "Economy" "CheckServerCert" "false" + set_ini_key "$file" "Economy" "PriceUpload" "0" + set_ini_key "$file" "Economy" "MeshModelUploadCostFactor" "1.0" + set_ini_key "$file" "Economy" "MeshModelUploadTextureCostFactor" "1.0" + set_ini_key "$file" "Economy" "MeshModelMinCostFactor" "1.0" + set_ini_key "$file" "Economy" "CheckServerCert" "false" + set_ini_key "$file" "Economy" "PriceUpload" "0" + set_ini_key "$file" "Economy" "MeshModelUploadCostFactor" "1.0" + set_ini_key "$file" "Economy" "MeshModelUploadTextureCostFactor" "1.0" + set_ini_key "$file" "Economy" "MeshModelMinCostFactor" "1.0" + set_ini_key "$file" "Economy" "PriceGroupCreate" "0" + set_ini_key "$file" "Economy" "ObjectCount" "0" + set_ini_key "$file" "Economy" "PriceEnergyUnit" "0" + set_ini_key "$file" "Economy" "PriceObjectClaim" "0" + set_ini_key "$file" "Economy" "PricePublicObjectDecay" "0" + set_ini_key "$file" "Economy" "PricePublicObjectDelete" "0" + set_ini_key "$file" "Economy" "PriceParcelClaim" "0" + set_ini_key "$file" "Economy" "PriceParcelClaimFactor" "1" + set_ini_key "$file" "Economy" "PriceRentLight" "0" + set_ini_key "$file" "Economy" "TeleportMinPrice" "0" + set_ini_key "$file" "Economy" "TeleportPriceExponent" "2" + set_ini_key "$file" "Economy" "EnergyEfficiency" "1" + set_ini_key "$file" "Economy" "PriceObjectRent" "0" + set_ini_key "$file" "Economy" "PriceObjectScaleFactor" "10" + set_ini_key "$file" "Economy" "PriceParcelRent" "0" + + # [Groups] + set_ini_key "$file" "Groups" "Enabled" "true" + set_ini_key "$file" "Groups" "LevelGroupCreate" "0" + set_ini_key "$file" "Groups" "Module" "\"Groups Module V2\"" + set_ini_key "$file" "Groups" "StorageProvider" "OpenSim.Data.MySQL.dll" + set_ini_key "$file" "Groups" "ServicesConnectorModule" "\"Groups HG Service Connector\"" + set_ini_key "$file" "Groups" "LocalService" "remote" + set_ini_key "$file" "Groups" "GroupsServerURI" "\${Const|BaseURL}:\${Const|PrivatePort}" + set_ini_key "$file" "Groups" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + set_ini_key "$file" "Groups" "MessagingEnabled" "true" + set_ini_key "$file" "Groups" "MessagingModule" "\"Groups Messaging Module V2\"" + set_ini_key "$file" "Groups" "NoticesEnabled" "true" + set_ini_key "$file" "Groups" "MessageOnlineUsersOnly" "true" + set_ini_key "$file" "Groups" "XmlRpcServiceReadKey" "1234" + set_ini_key "$file" "Groups" "XmlRpcServiceWriteKey" "1234" + + # [InterestManagement] + set_ini_key "$file" "InterestManagement" "UpdatePrioritizationScheme" "BestAvatarResponsiveness" + set_ini_key "$file" "InterestManagement" "ObjectsCullingByDistance" "true" + + # [MediaOnAPrim] + set_ini_key "$file" "MediaOnAPrim" "Enabled" "true" + + # [NPC] + set_ini_key "$file" "NPC" "Enabled" "true" + set_ini_key "$file" "NPC" "MaxNumberNPCsPerScene" "40" + set_ini_key "$file" "NPC" "AllowNotOwned" "true" + set_ini_key "$file" "NPC" "AllowSenseAsAvatar" "true" + set_ini_key "$file" "NPC" "AllowCloneOtherAvatars" "true" + set_ini_key "$file" "NPC" "NoNPCGroup" "true" + + # [Terrain] + set_ini_key "$file" "Terrain" "InitialTerrain" "\"flat\"" + + # [LandManagement] + set_ini_key "$file" "LandManagement" "ShowParcelBansLines" "true" + + # [UserProfiles] + set_ini_key "$file" "UserProfiles" "ProfileServiceURL" "\${Const|BaseURL}:\${Const|PublicPort}" + set_ini_key "$file" "UserProfiles" "AllowUserProfileWebURLs" "true" + + # [XBakes] + set_ini_key "$file" "XBakes" "URL" "\${Const|PrivURL}:\${Const|PrivatePort}" + + # [Architecture] + set_ini_key "$file" "Architecture" "Include-Architecture" "\"config-include/GridHypergrid.ini\"" + + ((sim_counter++)) + sleep 1 + fi + done + + log "${COLOR_OK}${sim_counter} Simulationen konfiguriert.${COLOR_RESET}" + blankline +} + +# Konfiguration von Robust.HG.ini im robust/bin Verzeichnis +function robusthginiconfig() { + # 23.04.2025 + local ip="$1" + local gridname="$2" + local dir="$SCRIPT_DIR/robust/bin" + local file="$dir/Robust.HG.ini" + webverzeichnis="oswebinterface" + + # Gridname bereinigen + gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') + + if [[ ! -f "$file.example" ]]; then + echo "FEHLER: Konfigurationsvorlage '$file.example' fehlt!" >&2 + echo "Das Programm benötigt diese Datei zum Starten." >&2 + exit 1 # Programm mit Fehlercode beenden + fi + + # Nur wenn Vorlage existiert: Kopieren + cp "$file.example" "$file" || { + echo "FEHLER: Konnte '$file' nicht erstellen" >&2 + exit 1 + } + + # [Const] + set_ini_key "$file" "Const" "BaseHostname" "$ip" + + # [Startup] + # PID-Dateien gehören grundsätzlich in /tmp warum: tmp Wird beim Neustart automatisch geleert. Keine Berechtigungsprobleme (normalerweise schreibbar für alle). + # Standard-PID-Datei: /tmp/Robust.exe.pid + uncomment_ini_line "$file" "PIDFile" + + # [ServiceList] + uncomment_ini_line "$file" "OfflineIMServiceConnector" + uncomment_ini_line "$file" "GroupsServiceConnector" + uncomment_ini_line "$file" "BakedTextureService" + uncomment_ini_line "$file" "UserProfilesServiceConnector" + uncomment_ini_line "$file" "HGGroupsServiceConnector" + + # [Network] + + # [Hypergrid] + uncomment_ini_line "$file" "HomeURI" + uncomment_ini_line "$file" "GatekeeperURI" + + # [DatabaseService] wird in database_set_iniconfig eingetragen. + + # [GridService] für osWebinterface + uncomment_ini_line "$file" "MapTileDirectory" + + # [LoginService] für osWebinterface etc. "\${Const|BaseURL}:\${Const|PublicPort}" + uncomment_ini_line "$file" "SearchURL" + uncomment_ini_line "$file" "DestinationGuide" + uncomment_ini_line "$file" "AvatarPicker" + uncomment_ini_line "$file" "MinLoginLevel" + uncomment_ini_line "$file" "Currency" + uncomment_ini_line "$file" "ClassifiedFee" + + set_ini_key "$file" "LoginService" "WelcomeMessage" "\"Willkommen im $gridname!\"" + set_ini_key "$file" "LoginService" "MapTileURL" "\"\${Const|BaseURL}:\${Const|PublicPort}/\"" + set_ini_key "$file" "LoginService" "SearchURL" "\"\${Const|BaseURL}:\${Const|PublicPort}/$webverzeichnis/searchservice.php\"" + set_ini_key "$file" "LoginService" "DestinationGuide" "\"\${Const|BaseURL}/$webverzeichnis/guide.php\"" + set_ini_key "$file" "LoginService" "AvatarPicker" "\"\${Const|BaseURL}/$webverzeichnis/avatarpicker.php\"" + set_ini_key "$file" "LoginService" "Currency" "\"OS$\"" + set_ini_key "$file" "LoginService" "DSTZone" "\"local\"" + + # [GatekeeperService] + uncomment_ini_line "$file" "ExternalName" + + # [GridInfoService] + set_ini_key "$file" "GridInfoService" "gridname" "\"$gridname\"" + set_ini_key "$file" "GridInfoService" "gridnick" "\"$gridname\"" + set_ini_key "$file" "GridInfoService" "welcome" "\"\${Const|BaseURL}/$webverzeichnis/welcomesplashpage.php\"" + set_ini_key "$file" "GridInfoService" "economy" "\"\${Const|BaseURL}:8008/\"" + set_ini_key "$file" "GridInfoService" "about" "\"\${Const|BaseURL}/$webverzeichnis/aboutinformation.php\"" + set_ini_key "$file" "GridInfoService" "register" "\"\${Const|BaseURL}/$webverzeichnis/createavatar.php\"" + set_ini_key "$file" "GridInfoService" "help" "\"\${Const|BaseURL}/$webverzeichnis/help.php\"" + set_ini_key "$file" "GridInfoService" "password" "\"\${Const|BaseURL}/$webverzeichnis/passwordreset.php\"" + set_ini_key "$file" "GridInfoService" "GridStatusRSS" "\"\${Const|BaseURL}/$webverzeichnis/gridstatusrss.php\"" + + # [UserAgentService] + uncomment_ini_line "$file" "LevelOutsideContacts" + uncomment_ini_line "$file" "ShowUserDetailsInHGProfile" + + # [Messaging] + set_ini_key "$file" "Messaging" "MaxOfflineIMs" "250" + + # [Groups] + set_ini_key "$file" "Groups" "MaxAgentGroups" "100" + + log "${COLOR_OK}Robust.HG.ini konfiguriert.${COLOR_RESET}" + blankline +} + +# Funktion zur Generierung eines 16-stelligen Passworts +function genPass() { + tr -dc 'A-Za-z0-9' "$php_config_file" < +EOF + + # config.example.php in config.php umbenennen, falls es existiert + if [[ -f "$config_example_file" ]]; then + #mv "$config_example_file" "$config_file" + cp "$config_example_file" "$config_file" + log "${SYM_OK} ${COLOR_ACTION}Konfigurationsdatei umbenannt: ${COLOR_DIR}$config_file${COLOR_RESET}" + + # Konfiguration in config.php einfügen + if [[ -f "$config_file" ]]; then + # BASE_URL ersetzen oder hinzufügen + if grep -q "define('BASE_URL'" "$config_file"; then + sed -i "s|define('BASE_URL'.*|define('BASE_URL', 'http://${server_ip}');|" "$config_file" + else + sed -i "/&2 + log "${COLOR_BAD}Das Programm benötigt diese Datei zum Starten.${COLOR_RESET}" >&2 + exit 1 + fi + + # Vorlage nach Robust.local.ini kopieren + cp "$source_file" "$target_file" || { + log "${COLOR_BAD}FEHLER: Konnte '$target_file' nicht erstellen${COLOR_RESET}" >&2 + exit 1 + } + + # [Const] + set_ini_key "$target_file" "Const" "BaseHostname" "$ip" + + # [ServiceList] + uncomment_ini_line "$target_file" "OfflineIMServiceConnector" + uncomment_ini_line "$target_file" "GroupsServiceConnector" + uncomment_ini_line "$target_file" "BakedTextureService" + uncomment_ini_line "$target_file" "UserProfilesServiceConnector" + + # [LoginService] Konfiguration + set_ini_key "$target_file" "LoginService" "Currency" "\"OS$\"" + set_ini_key "$target_file" "LoginService" "WelcomeMessage" "\"Willkommen im $gridname!\"" + set_ini_key "$target_file" "LoginService" "MapTileURL" "\"\${Const|BaseURL}:\${Const|PublicPort}/\"" + set_ini_key "$target_file" "LoginService" "SearchURL" "\"\${Const|BaseURL}/searchservice.php\"" + set_ini_key "$target_file" "LoginService" "DestinationGuide" "\"\${Const|BaseURL}/guide.php\"" + set_ini_key "$target_file" "LoginService" "AvatarPicker" "\"\${Const|BaseURL}/avatarpicker.php\"" + + # [GridInfoService] + set_ini_key "$target_file" "GridInfoService" "gridname" "\"$gridname\"" + set_ini_key "$target_file" "GridInfoService" "gridnick" "\"$gridname\"" + set_ini_key "$target_file" "GridInfoService" "welcome" "\"\${Const|BaseURL}/welcome\"" + set_ini_key "$target_file" "GridInfoService" "economy" "\"\${Const|BaseURL}:8008/\"" + set_ini_key "$target_file" "GridInfoService" "about" "\"\${Const|BaseURL}/about\"" + set_ini_key "$target_file" "GridInfoService" "register" "\"\${Const|BaseURL}/register\"" + set_ini_key "$target_file" "GridInfoService" "help" "\"\${Const|BaseURL}/help\"" + set_ini_key "$target_file" "GridInfoService" "password" "\"\${Const|BaseURL}/password\"" + set_ini_key "$target_file" "GridInfoService" "GridStatusRSS" "\"\${Const|BaseURL}:\${Const|PublicPort}/GridStatusRSS\"" + + log "${COLOR_OK}Robust.local.ini erfolgreich konfiguriert.${COLOR_RESET}" + blankline +} + +# Konfiguriert die FlotsamCache.ini Dateien +# - Erstellt die Dateien in den bin/config-include Ordner der Simulatoren +# - Setzt Optimierte Parameter den FlotsamCache.ini Dateien +function flotsaminiconfig() { + # 25.04.2025 + for i in $(seq 1 99); do + local config_dir="$SCRIPT_DIR/sim$i/bin/config-include" + local file="$config_dir/FlotsamCache.ini" + + if [[ -d "$config_dir" ]]; then + log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" + mkdir -p "$config_dir" + + # Datei erstellen + #touch "$welcome_ini" + #touch "$welcome_ini" || echo "" > "$welcome_ini" + touch "$file" 2>/dev/null || echo "" > "$file" + + # 2. Sektion hinzufügen + add_ini_section "$file" "AssetCache" + + sleep 1 + + # 3. Alle Key-Value Paare setzen + set_ini_key "$file" "AssetCache" "CacheDirectory" "./assetcache" + set_ini_key "$file" "AssetCache" "LogLevel" "0" + set_ini_key "$file" "AssetCache" "HitRateDisplay" "100" + set_ini_key "$file" "AssetCache" "MemoryCacheEnabled" "false" + set_ini_key "$file" "AssetCache" "UpdateFileTimeOnCacheHit" "false" + set_ini_key "$file" "AssetCache" "NegativeCacheEnabled" "true" + set_ini_key "$file" "AssetCache" "NegativeCacheTimeout" "120" + set_ini_key "$file" "AssetCache" "NegativeCacheSliding" "false" + set_ini_key "$file" "AssetCache" "FileCacheEnabled" "true" + set_ini_key "$file" "AssetCache" "MemoryCacheTimeout" ".016" + set_ini_key "$file" "AssetCache" "FileCacheTimeout" "48" + set_ini_key "$file" "AssetCache" "FileCleanupTimer" "1.0" + + log "${COLOR_OK}→ FlotsamCache.ini neu geschrieben für sim$i${COLOR_RESET}" + fi + done + + log "${COLOR_OK}FlotsamCache.ini konfiguriert.${COLOR_RESET}" + blankline +} + +function gridcommoniniconfig() { + local ip="$1" + local gridname="$2" + + # Gridname bereinigen + gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') + + for i in $(seq 1 99); do + local config_dir="$SCRIPT_DIR/sim$i/bin/config-include" + local file="$config_dir/GridCommon.ini" + local example_file="$config_dir/GridCommon.ini.example" + + # Strikte Prüfung - Abbruch wenn etwas fehlt + if [[ ! -d "$config_dir" ]] || [[ ! -f "$example_file" ]]; then + return 1 + fi + + # Vorlage kopieren + cp "$example_file" "$file" || return 1 + + sleep 1 + + # [Const] + add_ini_before_section "$file" "Const" "DatabaseService" + set_ini_key "$file" "Const" "BaseHostname" "\"$ip\"" + set_ini_key "$file" "Const" "BaseURL" "\"http://\${Const|BaseHostname}\"" + set_ini_key "$file" "Const" "PublicPort" "\"8002\"" + set_ini_key "$file" "Const" "PrivatePort" "\"8003\"" + + # [DatabaseService] wird in database_set_iniconfig eingetragen. + clear_ini_section "$file" "DatabaseService" + set_ini_key "$file" "DatabaseService" "StorageProvider" "\"OpenSim.Data.MySQL.dll\"" + + # [Hypergrid] + set_ini_key "$file" "Hypergrid" "GatekeeperURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + set_ini_key "$file" "Hypergrid" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + + # [Modules] + set_ini_key "$file" "Modules" "AssetCaching" "\"FlotsamAssetCache\"" + set_ini_key "$file" "Modules" "Include-FlotsamCache" "\"config-include/FlotsamCache.ini\"" + set_ini_key "$file" "Modules" "AuthorizationServices" "\"RemoteAuthorizationServicesConnector\"" + + # [AssetService] + set_ini_key "$file" "AssetService" "DefaultAssetLoader" "\"OpenSim.Framework.AssetLoader.Filesystem.dll\"" + set_ini_key "$file" "AssetService" "AssetLoaderArgs" "\"assets/AssetSets.xml\"" + set_ini_key "$file" "AssetService" "AssetServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [InventoryService] + set_ini_key "$file" "InventoryService" "InventoryServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [GridInfo] + set_ini_key "$file" "GridInfo" "GridInfoURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + + # [GridService] + set_ini_key "$file" "GridService" "GridServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + set_ini_key "$file" "GridService" "MapTileDirectory" "\"./maptiles\"" + set_ini_key "$file" "GridService" "Gatekeeper" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + + # [EstateDataStore] + set_ini_key "$file" "EstateService" "EstateServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [Messaging] + set_ini_key "$file" "Messaging" "Gatekeeper" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + + # [AvatarService] + set_ini_key "$file" "AvatarService" "AvatarServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [AgentPreferencesService] + set_ini_key "$file" "AgentPreferencesService" "AgentPreferencesServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [PresenceService] + set_ini_key "$file" "PresenceService" "PresenceServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [UserAccountService] + set_ini_key "$file" "UserAccountService" "UserAccountServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [GridUserService] + set_ini_key "$file" "GridUserService" "GridUserServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [AuthenticationService] + set_ini_key "$file" "AuthenticationService" "AuthenticationServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [FriendsService] + set_ini_key "$file" "FriendsService" "FriendsServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [HGInventoryAccessModule] + set_ini_key "$file" "HGInventoryAccessModule" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + set_ini_key "$file" "HGInventoryAccessModule" "Gatekeeper" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + + # [HGAssetService] + set_ini_key "$file" "HGAssetService" "HomeURI" "\"\${Const|BaseURL}:\${Const|PublicPort}\"" + + # [HGFriendsModule] + set_ini_key "$file" "HGFriendsModule" "LevelHGFriends" "0" + + # [MapImageService] + set_ini_key "$file" "MapImageService" "MapImageServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + # [AuthorizationService] + set_ini_key "$file" "AuthorizationService" "AuthorizationServerURI" "\"\${Const|PrivURL}/hgauth.php\"" + + # [MuteListService] + set_ini_key "$file" "MuteListService" "MuteListServerURI" "\"\${Const|PrivURL}:\${Const|PrivatePort}\"" + + log "${COLOR_OK}✓ sim$i: GridCommon.ini erfolgreich${COLOR_RESET}" + + sleep 1 + done + + log "${COLOR_OK}GridCommon.ini konfiguriert.${COLOR_RESET}" + blankline +} + +function osslenableiniconfig() { + # 25.04.2025 + for i in $(seq 1 99); do + local config_dir="$SCRIPT_DIR/sim$i/bin/config-include" + local file="$config_dir/osslEnable.ini" + + if [[ -d "$config_dir" ]]; then + log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" + mkdir -p "$config_dir" + + touch "$file" 2>/dev/null || echo "" > "$file" + + # Sektion hinzufügen + add_ini_section "$file" "OSSL" + + sleep 1 + + # Basis-Key-Value Paare + set_ini_key "$file" "OSSL" "AllowOSFunctions" "true" + set_ini_key "$file" "OSSL" "AllowMODFunctions" "true" + set_ini_key "$file" "OSSL" "AllowLightShareFunctions" "true" + set_ini_key "$file" "OSSL" "PermissionErrorToOwner" "false" + set_ini_key "$file" "OSSL" "OSFunctionThreatLevel" "VeryHigh" + set_ini_key "$file" "OSSL" "osslParcelO" "\"PARCEL_OWNER,\"" + set_ini_key "$file" "OSSL" "osslParcelOG" "\"PARCEL_GROUP_MEMBER,PARCEL_OWNER,\"" + set_ini_key "$file" "OSSL" "osslNPC" "\${OSSL|osslParcelOG}ESTATE_MANAGER,ESTATE_OWNER" + + # Alle Allow_* Einträge + set_ini_key "$file" "OSSL" "Allow_osGetAgents" "true" + set_ini_key "$file" "OSSL" "Allow_osGetAvatarList" "true" + set_ini_key "$file" "OSSL" "Allow_osGetNPCList" "true" + set_ini_key "$file" "OSSL" "Allow_osNpcGetOwner" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osSetSunParam" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osTeleportOwner" "true" + set_ini_key "$file" "OSSL" "Allow_osSetEstateSunSettings" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetRegionSunSettings" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osEjectFromGroup" "true" + set_ini_key "$file" "OSSL" "Allow_osForceBreakAllLinks" "true" + set_ini_key "$file" "OSSL" "Allow_osForceBreakLink" "true" + set_ini_key "$file" "OSSL" "Allow_osGetWindParam" "true" + set_ini_key "$file" "OSSL" "Allow_osInviteToGroup" "true" + set_ini_key "$file" "OSSL" "Allow_osReplaceString" "true" + set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureData" "true" + set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureDataFace" "true" + set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureDataBlend" "true" + set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureDataBlendFace" "true" + set_ini_key "$file" "OSSL" "Allow_osSetParcelMediaURL" "true" + set_ini_key "$file" "OSSL" "Allow_osSetParcelMusicURL" "true" + set_ini_key "$file" "OSSL" "Allow_osSetParcelSIPAddress" "true" + set_ini_key "$file" "OSSL" "Allow_osSetPrimFloatOnWater" "true" + set_ini_key "$file" "OSSL" "Allow_osSetWindParam" "true" + set_ini_key "$file" "OSSL" "Allow_osTerrainFlush" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osAvatarName2Key" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osFormatString" "true" + set_ini_key "$file" "OSSL" "Allow_osKey2Name" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osListenRegex" "true" + set_ini_key "$file" "OSSL" "Allow_osLoadedCreationDate" "true" + set_ini_key "$file" "OSSL" "Allow_osLoadedCreationID" "true" + set_ini_key "$file" "OSSL" "Allow_osLoadedCreationTime" "true" + set_ini_key "$file" "OSSL" "Allow_osMessageObject" "true" + set_ini_key "$file" "OSSL" "Allow_osRegexIsMatch" "true" + set_ini_key "$file" "OSSL" "Allow_osGetAvatarHomeURI" "true" + set_ini_key "$file" "OSSL" "Allow_osNpcSetProfileAbout" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcSetProfileImage" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osDie" "true" + set_ini_key "$file" "OSSL" "Allow_osDetectedCountry" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osDropAttachment" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osDropAttachmentAt" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetAgentCountry" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetGridCustom" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetGridGatekeeperURI" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetGridHomeURI" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetGridLoginURI" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetGridName" "true" + set_ini_key "$file" "OSSL" "Allow_osGetGridNick" "true" + set_ini_key "$file" "OSSL" "Allow_osGetNumberOfAttachments" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetRegionStats" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetSimulatorMemory" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetSimulatorMemoryKB" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osMessageAttachments" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osReplaceAgentEnvironment" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetSpeed" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetOwnerSpeed" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osRequestURL" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osRequestSecureURL" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osCauseDamage" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osCauseHealing" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetHealth" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetHealRate" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osForceAttachToAvatar" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osForceAttachToAvatarFromInventory" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osForceCreateLink" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osForceDropAttachment" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osForceDropAttachmentAt" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetLinkPrimitiveParams" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetPhysicsEngineType" "true" + set_ini_key "$file" "OSSL" "Allow_osGetRegionMapTexture" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetScriptEngineName" "true" + set_ini_key "$file" "OSSL" "Allow_osGetSimulatorVersion" "true" + set_ini_key "$file" "OSSL" "Allow_osMakeNotecard" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osMatchString" "true" + set_ini_key "$file" "OSSL" "Allow_osNpcCreate" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcGetPos" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcGetRot" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcLoadAppearance" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcMoveTo" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcMoveToTarget" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcPlayAnimation" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcRemove" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcSaveAppearance" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcSay" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcSayTo" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcSetRot" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcShout" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcSit" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcStand" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcStopAnimation" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcStopMoveToTarget" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcTouch" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osNpcWhisper" "\${OSSL|osslNPC}" + set_ini_key "$file" "OSSL" "Allow_osOwnerSaveAppearance" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osParcelJoin" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osParcelSubdivide" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osRegionRestart" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osRegionNotice" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetProjectionParams" "true" + set_ini_key "$file" "OSSL" "Allow_osSetRegionWaterHeight" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetTerrainHeight" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetTerrainTexture" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetTerrainTextureHeight" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osAgentSaveAppearance" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osAvatarPlayAnimation" "true" + set_ini_key "$file" "OSSL" "Allow_osAvatarStopAnimation" "true" + set_ini_key "$file" "OSSL" "Allow_osForceAttachToOtherAvatarFromInventory" "true" + set_ini_key "$file" "OSSL" "Allow_osForceDetachFromAvatar" "true" + set_ini_key "$file" "OSSL" "Allow_osForceOtherSit" "true" + set_ini_key "$file" "OSSL" "Allow_osGetNotecard" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetNotecardLine" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osGetNumberOfNotecardLines" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureURL" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureURLBlend" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetDynamicTextureURLBlendFace" "ESTATE_MANAGER,ESTATE_OWNER" + set_ini_key "$file" "OSSL" "Allow_osSetRot" "true" + set_ini_key "$file" "OSSL" "Allow_osSetParcelDetails" "\${OSSL|osslParcelO}ESTATE_MANAGER,ESTATE_OWNER" + + log "${COLOR_OK}→ osslEnable.ini neu geschrieben für sim$i${COLOR_RESET}" + + sleep 1 + fi + done + + log "${COLOR_OK}osslEnable.ini konfiguriert.${COLOR_RESET}" + blankline +} + +# Erstellt eine StandaloneCommon.ini +function standalonecommoniniconfig() { + local ip="$1" + local gridname="$2" + + # Gridname bereinigen + gridname=$(echo "$gridname" | sed -e 's/ä/ae/g' -e 's/ö/oe/g' -e 's/ü/ue/g' -e 's/[-&]/_/g' -e 's/ */_/g' -e 's/__\+/_/g') + + local config_dir="$SCRIPT_DIR/opensim/bin/config-include" + local file="$config_dir/StandaloneCommon.ini" + local example_file="$config_dir/StandaloneCommon.ini.example" + + log "${COLOR_FILE}Erstelle StandaloneCommon.ini in opensim/bin${COLOR_RESET}" + mkdir -p "$config_dir" + + # Datei erstellen + #touch "$welcome_ini" + #touch "$welcome_ini" || echo "" > "$welcome_ini" + touch "$file" 2>/dev/null || echo "" > "$file" + + # 2. Const-Sektion hinzufügen + add_ini_section "$file" "Const" + + # 3. Werte für Const-Sektion setzen + set_ini_key "$file" "Const" "BaseHostname" "\"$ip\"" + set_ini_key "$file" "Const" "BaseURL" "http://\${Const|BaseHostname}" + set_ini_key "$file" "Const" "PublicPort" "\"9000\"" + set_ini_key "$file" "Const" "PrivatePort" "\"9003\"" + set_ini_key "$file" "Const" "PrivURL" "http://\${Const|BaseHostname}:\${Const|PrivatePort}" + + # 4. Hypergrid- und GridInfo-Werte setzen + set_ini_key "$file" "Hypergrid" "GatekeeperURI" "\"http://$ip:8002\"" + set_ini_key "$file" "Hypergrid" "HomeURI" "\"http://$ip:8002\"" + set_ini_key "$file" "GridInfoService" "GridName" "\"$gridname\"" + set_ini_key "$file" "GridInfoService" "GridLoginURI" "\"http://$ip:8002\"" + + log "${COLOR_OK}→ StandaloneCommon.ini erfolgreich erstellt${COLOR_RESET}" + blankline +} + +# Random Position (mit Simulator-Offset) +function random_position() { + local center_x=$1 + local center_y=$2 + local n=$3 # Region-Nummer + local sim_offset=$4 # Simulator-Offset + + # Zufallsposition mit Simulator-basiertem Seed + RANDOM=$(( n + sim_offset * 1000 )) # Reproduzierbarer Zufall + local offset_x=$(( (RANDOM % 200) - 100 )) # Kleinerer Bereich (±100 Einheiten) + local offset_y=$(( (RANDOM % 200) - 100 )) + + echo "$((center_x + offset_x + sim_offset * 10)),$((center_y + offset_y + sim_offset * 10))" +} + +# Fibonacci Grid (mit Simulator-Offset) +function fibonacci_grid_position() { + local center_x=$1 + local center_y=$2 + local n=$3 + local sim_offset=$4 + + local a=0; local b=1 + for ((i=0; i&2 + return 1 + fi + + log "${SYM_OK} ${COLOR_ACTION}Sie haben ${COLOR_OK}$regions_per_sim${COLOR_ACTION} Regionen pro Simulator gewählt.${COLOR_RESET}" + + system_ip=$(hostname -I | awk '{print $1}') + + log "\n${SYM_SERVER}${COLOR_HEADING} Starte Regionserstellung...${COLOR_RESET}" + + # Simulatoren durchlaufen (beginnt bei 2 um sim1 für Welcome-Region freizuhalten) + for ((sim_num=2; sim_num<=999; sim_num++)); do + sim_dir="${SCRIPT_DIR}/sim${sim_num}/bin/Regions" + + if [[ -d "$sim_dir" ]]; then + log "${SYM_FOLDER}${COLOR_SERVER} Simulator ${sim_num}:${COLOR_RESET} ${COLOR_ACTION}Erstelle ${regions_per_sim} Region(en)${COLOR_RESET}" >&2 + + # Bestehende Ports erfassen + local existing_port_count=0 + if [[ -d "$sim_dir" ]]; then + for existing_file in "$sim_dir"/*.ini; do + if [[ -f "$existing_file" ]]; then + existing_port=$(grep -oP 'InternalPort\s*=\s*\K\d+' "$existing_file" 2>/dev/null) + if [[ -n "$existing_port" ]]; then + used_ports["$existing_port"]=1 + ((existing_port_count++)) + fi + fi + done + fi + + # Regionen erstellen Random Fibonacci Raute Square Hexagon Spiral Checkerboard + for ((region_num=1; region_num<=regions_per_sim; region_num++)); do + # Position berechnen (mit Kollisionsprüfung) + local attempts=0 + local max_attempts=100 + + while true; do + # Hier wird die entsprechende externe Funktion aufgerufen + if [[ "$position" == "Random" ]]; then + # Zufalls-Gitter: + location=$(random_position "$center_x" "$center_y" "$region_num" "$sim_num") + elif [[ "$position" == "Fibonacci" ]]; then + # Fibonacci-Gitter: + location=$(fibonacci_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") + elif [[ "$position" == "Raute" ]]; then + # Rauten-Gitter: + location=$(diamond_position "$center_x" "$center_y" "$region_num" "$sim_num") + elif [[ "$position" == "Square" ]]; then + # Square-Gitter: + location=$(square_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") + elif [[ "$position" == "Hexagon" ]]; then + # Hexagon-Gitter: + location=$(hex_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") + elif [[ "$position" == "Spiral" ]]; then + # Spirale-Gitter: + location=$(spiral_grid_position "$center_x" "$center_y" "$region_num" "$sim_num") + else + # Fallback zu Random bei ungültiger Eingabe + location=$(random_position "$center_x" "$center_y" "$region_num" "$sim_num") + fi + + if [[ -z "${used_locations[$location]}" ]]; then + used_locations[$location]=1 + break + fi + + attempts=$((attempts + 1)) + if (( attempts >= max_attempts )); then + log "${SYM_BAD} ${COLOR_WARNING}Fehler: Konnte nach ${max_attempts} Versuchen keine eindeutige Position finden${COLOR_RESET}" >&2 + return 1 + fi + done + + # Eindeutigen Port finden + local port_attempts=0 + local max_port_attempts=100 + local port_base=$((base_port + sim_num * 100)) # 9100, 9200, 9300 usw. + + while true; do + # Port innerhalb des reservierten Blocks (9100-9199 etc.) + port=$((port_base + region_num + existing_port_count)) + + # Sicherstellen, dass wir im Block bleiben + if (( port >= port_base + 100 )); then + log "${SYM_BAD} ${COLOR_WARNING}Fehler: Keine freien Ports mehr im Block ${port_base}-$((port_base+99))${COLOR_RESET}" >&2 + return 1 + fi + + # Prüfen ob Port verfügbar ist + if [[ -z "${used_ports[$port]}" ]] && ! nc -z localhost "$port" 2>/dev/null; then + used_ports["$port"]=1 + break + fi + + ((existing_port_count++)) + ((port_attempts++)) + + if (( port_attempts >= max_port_attempts )); then + log "${SYM_BAD} ${COLOR_WARNING}Fehler: Konnte in Simulator ${sim_num} nach ${max_port_attempts} Versuchen keinen freien Port finden (Block ${port_base}-$((port_base+99))${COLOR_RESET}" >&2 + return 1 + fi + done + + # Neu generierter Name + generate_name + genRegionName="${gennamefirst}${gennamesecond}$((RANDOM % 900 + 100))" + echo "$genRegionName" + region_name=${genRegionName} + + region_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") + + config_file="${sim_dir}/${region_name}.ini" + + # Prüfen ob Region existiert + if [[ -f "$config_file" ]]; then + log "${SYM_WAIT} ${COLOR_WARNING}Überspringe ${COLOR_VALUE}${region_name}${COLOR_RESET}${COLOR_WARNING} - existiert bereits${COLOR_RESET}" >&2 + continue + fi + + touch "$config_file" 2>/dev/null || echo "" > "$config_file" + + # Regionseinstellungen hinzufügen + add_ini_section "$config_file" "$region_name" + + # Regionseinstellungen setzen + set_ini_key "$config_file" "$region_name" "RegionUUID" "$region_uuid" + set_ini_key "$config_file" "$region_name" "Location" "$location" + set_ini_key "$config_file" "$region_name" "SizeX" "256" + set_ini_key "$config_file" "$region_name" "SizeY" "256" + set_ini_key "$config_file" "$region_name" "SizeZ" "256" + set_ini_key "$config_file" "$region_name" "InternalPort" "$port" + set_ini_key "$config_file" "$region_name" "ExternalHostName" "$system_ip" + set_ini_key "$config_file" "$region_name" "MaxPrims" "15000" + set_ini_key "$config_file" "$region_name" "MaxAgents" "40" + set_ini_key "$config_file" "$region_name" "MaptileStaticUUID" "$region_uuid" + set_ini_key "$config_file" "$region_name" "InternalAddress" "0.0.0.0" + set_ini_key "$config_file" "$region_name" "AllowAlternatePorts" "False" + set_ini_key "$config_file" "$region_name" "NonPhysicalPrimMax" "512" + set_ini_key "$config_file" "$region_name" "PhysicalPrimMax" "128" + set_ini_key "$config_file" "$region_name" ";ClampPrimSize" "false" + set_ini_key "$config_file" "$region_name" ";MaxPrimsPerUser" "-1" + set_ini_key "$config_file" "$region_name" ";ScopeID" "$region_uuid" + set_ini_key "$config_file" "$region_name" ";RegionType" "Mainland" + set_ini_key "$config_file" "$region_name" ";RenderMinHeight" "-1" + set_ini_key "$config_file" "$region_name" ";RenderMaxHeight" "100" + set_ini_key "$config_file" "$region_name" ";MapImageModule" "Warp3DImageModule" + set_ini_key "$config_file" "$region_name" ";TextureOnMapTile" "true" + set_ini_key "$config_file" "$region_name" ";DrawPrimOnMapTile" "true" + set_ini_key "$config_file" "$region_name" ";GenerateMaptiles" "true" + set_ini_key "$config_file" "$region_name" ";MaptileRefresh" "0" + set_ini_key "$config_file" "$region_name" ";MaptileStaticFile" "path/to/SomeFile.png" # Bitte verwenden sie nicht den Pfad des OpenSimulators sondern ein externen Pfad! + set_ini_key "$config_file" "$region_name" ";MasterAvatarFirstName" "John" + set_ini_key "$config_file" "$region_name" ";MasterAvatarLastName" "Doe" + set_ini_key "$config_file" "$region_name" ";MasterAvatarSandboxPassword" "passwd" + + log "${SYM_OK} ${COLOR_VALUE}${region_name} ${COLOR_DIR}(${location}, Port ${port})${COLOR_RESET}" >&2 + done + fi + done + + log "${SYM_OK}${COLOR_OK} Regionserstellung abgeschlossen!${COLOR_RESET}" + blankline + return 0 +} + +# Hauptfunktion, fragt Benutzer nach IP & Gridnamen und ruft alle Teilfunktionen auf +function iniconfig() { + # 30.04.2025 - Server-Konfiguration + + echo "Das Arbeitsverzeichnis ist: $SCRIPT_DIR" + + echo "Wie ist Ihre IP oder DNS-Adresse? ($system_ip)" + read -r ip + + # Falls die IP leer bleibt, wird system_ip verwendet + if [[ -z "$ip" ]]; then + ip=$system_ip + fi + + echo "Wie heißt Ihr Grid?" + read -r gridname + + # Falls der Gridname leer bleibt, wird eine generierte Name verwendet + if [[ -z "$gridname" ]]; then + gridname=${genGridName} + fi + + echo "Verwendete IP: $ip" + echo "Gridname: $gridname" + + # **Speicherung der Server-Daten in UserInfo.ini** + local ini_file="${SCRIPT_DIR}/UserInfo.ini" + + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_INFO}Erstelle UserInfo.ini${COLOR_RESET}" + sudo touch "$ini_file" + fi + + log "\n[ServerData]" | sudo tee -a "$ini_file" >/dev/null + echo "Arbeitsverzeichnis = ${SCRIPT_DIR}" | sudo tee -a "$ini_file" >/dev/null + echo "ServerIP = ${ip}" | sudo tee -a "$ini_file" >/dev/null + echo "GridName = ${gridname}" | sudo tee -a "$ini_file" >/dev/null + + log "${SYM_LOG} ${COLOR_LABEL}Serverdaten gespeichert in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" + + #! ${SYM_WARNING} **Wichtige Sicherheitsinformation!** + # Die Datei UserInfo.ini enthält Zugangsdaten. + # Sie **sollte danach unbedingt von eurem Server gelöscht und sicher auf eurem PC gespeichert werden**. + + # Konfigurationsfunktionen für verschiedene Komponenten aufrufen + echo "Starte moneyserveriniconfig ..." + moneyserveriniconfig "$ip" "$gridname" + echo "Starte opensiminiconfig ..." + opensiminiconfig "$ip" "$gridname" + echo "Starte robusthginiconfig ..." + robusthginiconfig "$ip" "$gridname" + echo "Starte robustiniconfig ..." + robustiniconfig "$ip" "$gridname" + echo "Starte gridcommoniniconfig ..." + gridcommoniniconfig "$ip" "$gridname" + echo "Starte standalonecommoniniconfig ..." + standalonecommoniniconfig "$ip" "$gridname" + echo "Starte flotsaminiconfig ..." + flotsaminiconfig "$ip" "$gridname" + echo "Starte osslenableiniconfig ..." + osslenableiniconfig "$ip" "$gridname" + echo "Starte welcomeiniconfig ..." + welcomeiniconfig "$ip" "$gridname" + echo "Starte database_set_iniconfig ..." + database_set_iniconfig + echo "Starte oswebinterfaceconfig ..." + oswebinterfaceconfig + + # Auswahl des Modus Hypergrid oder Geschlossener Grid. + hypergrid "hypergrid" + #hypergrid "closed" +} + + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* XML Konfigurationen für Addon Pakete wie Texturen, Avatare oder Skripte +#?────────────────────────────────────────────────────────────────────────────────────────── + +# shellcheck disable=SC2317 +function verify_xml_section() { + + local file="$1" + local section_name="$2" + + if [ ! -f "$file" ]; then + log "${SYM_BAD} ${COLOR_BAD}Error: File ${COLOR_DIR}${file}${COLOR_BAD} does not exist${COLOR_RESET}" >&2 + return 2 + fi + + if grep -q "
" "$file"; then + log "${SYM_OK} ${COLOR_LABEL}Section ${COLOR_VALUE}'$section_name'${COLOR_LABEL} exists in ${COLOR_DIR}${file}${COLOR_RESET}" + return 0 + else + log "${SYM_BAD} ${COLOR_LABEL}Section ${COLOR_VALUE}'$section_name'${COLOR_LABEL} not found in ${COLOR_DIR}${file}${COLOR_RESET}" + return 1 + fi +} + +# shellcheck disable=SC2317 +function add_xml_section() { + local file="$1" + local section_name="$2" + local content="$3" + local closing_tag="${4:-}" # Standard ist , kann überschrieben werden + + # Verifizieren ob der Abschnitt bereits existiert + if verify_xml_section "$file" "$section_name" >/dev/null; then + return 0 + fi + + # Temporäre Datei für Sicherheitskopie + local temp_file + temp_file=$(mktemp) + + log "${SYM_INFO} ${COLOR_ACTION}Adding section ${COLOR_VALUE}'$section_name'${COLOR_ACTION} to ${COLOR_DIR}${file}${COLOR_RESET}" + + # Abschnitt vor dem schließenden Tag einfügen + if sed "s|$closing_tag|
\n$content\n
\n$closing_tag|" "$file" > "$temp_file"; then + if mv "$temp_file" "$file"; then + log "${SYM_OK} ${COLOR_OK}Successfully added section ${COLOR_VALUE}'$section_name'${COLOR_OK} to ${COLOR_DIR}${file}${COLOR_RESET}" + return 0 + fi + fi + + log "${SYM_BAD} ${COLOR_BAD}Failed to add section ${COLOR_VALUE}'$section_name'${COLOR_BAD} to ${COLOR_DIR}${file}${COLOR_RESET}" >&2 + return 1 +} + +# shellcheck disable=SC2317 +function del_xml_section() { + local file="$1" + local section_name="$2" + + # Verifizieren ob der Abschnitt existiert + if ! verify_xml_section "$file" "$section_name" >/dev/null; then + return 0 # Abschnitt existiert nicht - nichts zu tun + fi + + # Temporäre Datei für Sicherheitskopie + local temp_file + temp_file=$(mktemp) + + log "${SYM_INFO} ${COLOR_ACTION}Removing section ${COLOR_VALUE}'$section_name'${COLOR_ACTION} from ${COLOR_DIR}${file}${COLOR_RESET}" + + # Abschnitt entfernen (inklusive aller Zeilen zwischen Section-Tags) + if sed "/
/,/<\/Section>/d" "$file" > "$temp_file"; then + if mv "$temp_file" "$file"; then + log "${SYM_OK} ${COLOR_OK}Successfully removed section ${COLOR_VALUE}'$section_name'${COLOR_OK} from ${COLOR_DIR}${file}${COLOR_RESET}" + return 0 + fi + fi + + log "${SYM_BAD} ${COLOR_BAD}Failed to remove section ${COLOR_VALUE}'$section_name'${COLOR_BAD} from ${COLOR_DIR}${file}${COLOR_RESET}" >&2 + return 1 +} + +#* Beispiel Implementierung für PBR Textures ohne Test eingefügt. +function configure_pbr_textures() { + local asset_sets_file="opensim/bin/assets/AssetSets.xml" + local libraries_file="opensim/bin/inventory/Libraries.xml" + + log "\n${COLOR_HEADING}=== Configuring PBR Textures ===${COLOR_RESET}" + + # AssetSets.xml bearbeiten + add_xml_section "$asset_sets_file" "PBR Textures AssetSet" \ + " " || return 1 + + # Libraries.xml bearbeiten + add_xml_section "$libraries_file" "PBRTextures Library" \ + " \n " || return 1 + + log "${SYM_OK} ${COLOR_OK}PBR Textures configuration completed successfully${COLOR_RESET}" + +} + +function regionsclean() { + log "\033[33mWARNUNG: Dies wird ALLE Regionskonfigurationen in allen Simulatoren löschen!\033[0m" + echo "Sicher fortfahren? (j/N): " + read -r confirm + + if [[ "$confirm" =~ ^[jJ] ]]; then + echo "Starte Bereinigung..." + deleted_count=0 + + # Durch alle Simulatoren iterieren + for ((sim_num=1; sim_num<=999; sim_num++)); do + sim_dir="sim${sim_num}/bin/Regions" + + if [[ -d "$sim_dir" ]]; then + log "\033[33m ✓ Überprüfe $sim_dir...\033[0m" + + # Lösche nur .ini-Dateien (keine anderen Dateitypen) + while IFS= read -r -d $'\0' config_file; do + if [[ "$config_file" == *.ini ]]; then + rm -v "$config_file" + ((deleted_count++)) + fi + done < <(find "$sim_dir" -maxdepth 1 -type f -name "*.ini" -print0) + fi + done + + log "\033[32mFertig! Gelöschte Regionen: $deleted_count\033[0m" + else + echo "Abbruch: Keine Dateien wurden gelöscht." + fi + blankline +} + +function renamefiles() { + timestamp=$(date +"%Y%m%d_%H%M%S") + + if [ ! -d "$SCRIPT_DIR" ]; then + log "${RED}Fehler: Verzeichnis $SCRIPT_DIR nicht gefunden!${RESET}" + return 1 + fi + + log "${CYAN}Starte Umbenennung aller *.example Dateien in ${SCRIPT_DIR} und Unterverzeichnissen...${RESET}" + + # Verarbeite robust/bin zuerst + find "$SCRIPT_DIR" -type f -name "*.example" 2>/dev/null | while read -r example_file; do + local target_file="${example_file%.example}" # Entfernt .example + + if [ -f "$target_file" ]; then + local backup_file="${target_file}_${timestamp}.bak" + mv "$target_file" "$backup_file" + log "${YELLOW}Gesichert: ${target_file} → ${backup_file}${RESET}" + fi + + mv "$example_file" "$target_file" + log "${GREEN}Umbenannt: ${example_file} → ${target_file}${RESET}" + done + + # Jetzt alle simX/bin Verzeichnisse durchlaufen + for ((i=999; i>=1; i--)); do + sim_dir="${SCRIPT_DIR}/sim$i/bin" + if [ -d "$sim_dir" ]; then + log "${CYAN}Verarbeite: $sim_dir ${RESET}" + find "$sim_dir" -type f -name "*.example" 2>/dev/null | while read -r example_file; do + local target_file="${example_file%.example}" + + sleep 1 + + if [ -f "$target_file" ]; then + local backup_file="${target_file}_${timestamp}.bak" + mv "$target_file" "$backup_file" + log "${YELLOW}Gesichert: ${target_file} → ${backup_file}${RESET}" + fi + + mv "$example_file" "$target_file" + log "${GREEN}Umbenannt: ${example_file} → ${target_file}${RESET}" + done + fi + done + + log "${GREEN}Alle *.example Dateien wurden erfolgreich verarbeitet.${RESET}" + blankline + return 0 +} + +# Helper to clean config files (remove leading spaces/tabs) +function clean_config() { + local file=$1 + sed -i 's/^[ \t]*//' "$file" +} + +# cleanall - Removes OpenSim completely +function cleanall() { + echo "$(msg CLEANALL_PROMPT_REMOVE_ALL)" + read -r answer + + if is_yes "$answer"; then + echo "$(msg CLEANALL_START_DELETE)" + + # robust/bin Verzeichnis leeren, falls vorhanden + if [ -d "robust/bin" ]; then + rm -rf robust/bin/* + fi + + # Überprüfen, welche simX/bin Verzeichnisse existieren und leeren + for i in {1..999}; do + dir="sim$i/bin" + if [ -d "$dir" ]; then + rm -rf "${dir:?}/"* + sleep 1 + fi + done + + echo "$(msg CLEANALL_BIN_CLEARED)" + + elif is_no "$answer"; then + echo "$(msg CLEANALL_KEEP)" + + else + echo "$(msg INPUT_INVALID_YES_NO)" + fi + blankline +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* ZUSAMMENFASSUNG DER FUNKTIONEN IN LOGISCHE GRUPPEN +#?────────────────────────────────────────────────────────────────────────────────────────── + +# Kompletter OpenSim-Neustart mit Logrotation +function opensimrestart() { + opensimstop + sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp + logclean # Logbereinigung + sleep $Simulator_Start_wait # Wartezeit vor Neustart + opensimstart + log "\033[36mAktive Screen-Sessions:\033[0m" + screen -ls || echo "Keine Screen-Sessions gefunden" +} + +# Kompletter OpenSim-Neustart mit Logrotation +function opensimrestartParallel() { + opensimstopParallel + sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp + logclean # Logbereinigung + sleep $Simulator_Start_wait # Wartezeit vor Neustart + opensimstartParallel + log "\033[36mAktive Screen-Sessions:\033[0m" + screen -ls || echo "Keine Screen-Sessions gefunden" +} + +# Server-Reboot mit Vorbereitung +function reboot() { + log "\033[1;33m🔥 Server-Neustart wird eingeleitet...\033[0m" + + opensimstop + sleep $Simulator_Stop_wait + shutdown -r now +} + +# OpenSim komplett herunterladen ⚡ Vorsicht +function downloadallgit() { + # Downloads aus dem Github. + opensimgitcopy + moneygitcopy + #ruthrothgit # Funktioniert nicht richtig. + #avatarassetsgit # Funktioniert nicht richtig. + #osslscriptsgit + #pbrtexturesgit + # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() + #versionrevision + # OpenSimulator erstellen aus dem Source Code. + opensimbuild +} + +function webinstall() { +# Nach database_setup() + log "${COLOR_ACTION}Webserver (Apache/PHP) installieren? (j/n) [n] ${COLOR_RESET}" + read -r web_choice + if [[ -n "$web_choice" && "$web_choice" =~ ^[jJ] ]]; then + setup_webserver + fi +} + +function autoinstall() { + # 06.05.2025 + + # Server vorbereiten + servercheck + + # Verzeichnisse erstellen. Standard: 1 + createdirectory + + # Doppelten Konfigurationsdateien entfernen + removeconfigfiles + + # mySQL installieren. Standard: Benutzername wird generiert, dazu wird ein 16 stelliges Passwort erzeugt. + database_setup + + # Downloads aus dem Github hier OpenSim und Money. einfach beises mit Enter bestätigen. + opensimgitcopy + moneygitcopy + + # PHP installieren + #webinstall + # Webinterface aus dem Github holen + osWebinterfacegit + + # Neue standartavatare einfügen + #ruthrothgit # Funktioniert nicht richtig. + #avatarassetsgit # Funktioniert nicht richtig. + + # OSSL Beispielskripte + osslscriptsgit + + # Texturen für Normale und PBR Texturen installieren + #pbrtexturesgit + + # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() + #versionrevision + + # OpenSimulator erstellen aus dem Source Code. Standard: ja. + opensimbuild + + # Kleine Pause + sleep $Simulator_Start_wait + + # OpenSimulator kopieren + opensimcopy + + # Alles konfigurieren + iniconfig + + # Zufallsregionen erstellen + regionsiniconfig + + #Vor dem Start die letzten vorbereitungen. + firststart + + # OpenSimulator starten + opensimrestart + + # Eure Informationen sind gespeichert in UserInfo.ini bitte sicher verwahren. + +} + +function autoupgrade() { + # 05.05.2025 + opensimgitcopy + moneygitcopy + osslscriptsgit + opensimbuild + + sleep 5 + + opensimstop + opensimcopy + opensimstart +} + +function autoupgradefast() { + # 05.05.2025 + opensimgitcopy + moneygitcopy + osslscriptsgit + opensimbuild + + sleep 5 + + opensimstopParallel + opensimcopy + opensimstartParallel +} + +#* OpenSimulator bauen aus Github. +# Dies macht ausser dem OpenSimulator erstellen nichts weiter. +function buildopensim() { + opensimgitcopy + moneygitcopy + osslscriptsgit + # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() + versionrevision + opensimbuild +} + +# Standalone +function standalonesetup() { + # 12.05.2025 + log "\e[33m[Standalone] Setup wird durchgeführt...\e[0m" + + # Prüfen ob SCRIPT_DIR gesetzt ist + if [ -z "${SCRIPT_DIR}" ]; then + log "\e[31mFehler: SCRIPT_DIR ist nicht gesetzt!\e[0m" + return 1 + fi + + local opensim_bin="${SCRIPT_DIR}/opensim/bin" + local renamed=0 + local skipped=0 + + # Sicherstellen, dass das Verzeichnis existiert + if [ ! -d "${opensim_bin}" ]; then + log "\e[31mFehler: Verzeichnis ${opensim_bin} nicht gefunden!\e[0m" + return 1 + fi + + # Verarbeite alle .example Dateien + while IFS= read -r -d '' file; do + target="${file%.example}" + + if [ -e "${target}" ]; then + log "\e[33mÜbersprungen: ${target} existiert bereits\e[0m" + ((skipped++)) + else + if mv "${file}" "${target}"; then + log "\e[32mUmbenannt: ${file} → ${target}\e[0m" + ((renamed++)) + else + log "\e[31mFehler beim Umbenennen von ${file}\e[0m" + ((skipped++)) + fi + fi + done < <(find "${opensim_bin}" -type f -name "*.example" -print0) + + genPasswort=$(tr -dc 'A-Za-z0-9!@#$%^&*()' < /dev/urandom | head -c 16) + #genUserid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") + user_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") + + log "${COLOR_INFO}OpenSim User Erstellung${COLOR_RESET}" + + echo -n "Vorname: " + read -r VORNAME + + echo -n "Nachname: " + read -r NACHNAME + + echo -n "Passwort: " + read -r PASSWORT + + echo -n "E-Mail: " + read -r EMAIL + + # **Speicherung der Benutzerdaten in UserInfo.ini** NEU + ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" + log "${COLOR_INFO}Erstelle OpenSimUserInfo.ini neu${COLOR_RESET}" + sudo rm -f "$ini_file" + sudo touch "$ini_file" + + log "\n[UserData]" | sudo tee -a "$ini_file" >/dev/null + echo "System IP = ${system_ip}" | sudo tee -a "$ini_file" >/dev/null + echo "Vorname = ${VORNAME}" | sudo tee -a "$ini_file" >/dev/null + echo "Nachname = ${NACHNAME}" | sudo tee -a "$ini_file" >/dev/null + echo "Passwort = ${PASSWORT}" | sudo tee -a "$ini_file" >/dev/null + echo "E-Mail = ${EMAIL}" | sudo tee -a "$ini_file" >/dev/null + echo "UserID = ${user_uuid}" | sudo tee -a "$ini_file" >/dev/null + + log "${SYM_LOG} ${COLOR_LABEL}Benutzerdaten hinzugefügt in: ${COLOR_FILE}${ini_file}${COLOR_RESET}" + + blankline +} + +function createstandaloneuser() { + # 12.05.2025 OpenSim Avatar erstellen + + # opensim starten + echo "opensim starten, erster start..." + if [[ -d "opensim/bin" && -f "opensim/bin/OpenSim.dll" ]]; then + log "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}opensim ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}opensim/bin...${COLOR_RESET}" + cd opensim/bin || exit 1 + + screen -fa -S opensim -d -U -m dotnet OpenSim.dll + cd - >/dev/null 2>&1 || exit 1 + else + log "${SYM_BAD} ${COLOR_SERVER}opensim: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" + fi + + + # 1. INI-Datei auslesen mit angepasstem Parsing + ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" + return 1 + fi + + # Parsing-Funktion mit Trim und Leerzeichen im Pattern + ini_get() { + local section="$1" key="$2" + awk -F ' = ' ' + /^\[/ { current_section = substr($0, 2, length($0)-2) } + current_section == "'"$section"'" && $1 == "'"$key"'" { + sub(/^[ \t]+/, "", $2) # Trim leading whitespace + sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace + print $2 + exit + } + ' "$ini_file" + } + + # Werte auslesen + VORNAME=$(ini_get "UserData" "Vorname") + NACHNAME=$(ini_get "UserData" "Nachname") + PASSWORT=$(ini_get "UserData" "Passwort") + EMAIL=$(ini_get "UserData" "E-Mail") + user_uuid=$(ini_get "UserData" "UserID") + + # Überprüfe ob opensim läuft + if ! screen -list | grep -q "opensim"; then + log "${COLOR_BAD}CREATEUSER: opensim existiert nicht oder läuft nicht${COLOR_RESET}" + return 1 + fi + + # Benutzer in Robust erstellen + screen -S opensim -p 0 -X eval "stuff 'create user'^M" + screen -S opensim -p 0 -X eval "stuff '$VORNAME'^M" + screen -S opensim -p 0 -X eval "stuff '$NACHNAME'^M" + screen -S opensim -p 0 -X eval "stuff '$PASSWORT'^M" + screen -S opensim -p 0 -X eval "stuff '$EMAIL'^M" + screen -S opensim -p 0 -X eval "stuff '$user_uuid'^M" + screen -S opensim -p 0 -X eval "stuff ''^M" + + screen -S opensim -p 0 -X eval "stuff ''^M" + screen -S opensim -p 0 -X eval "stuff ''^M" + + log "${COLOR_OK}Masteruser $VORNAME $NACHNAME wurde erstellt${COLOR_RESET}" + log "${COLOR_INFO}UserID: $user_uuid${COLOR_RESET}" + blankline +} + +function createstandalonregion() { + # 12.05.2025 Standalone Region erstellen + local config_file="${PATH_OPENSIM_BIN}/Regions/opensim.ini" + local region_name="OpenSim" + local location="1000,1000" + local port="9015" + system_ip=$(hostname -I | awk '{print $1}') + region_uuid=$(command -v uuidgen >/dev/null 2>&1 && uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || echo "$RANDOM-$RANDOM-$RANDOM-$RANDOM") + SIZES=768 + + # 1. INI-Datei auslesen mit angepasstem Parsing + ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" + return 1 + fi + + # Parsing-Funktion mit Trim und Leerzeichen im Pattern + ini_get() { + local section="$1" key="$2" + awk -F ' = ' ' + /^\[/ { current_section = substr($0, 2, length($0)-2) } + current_section == "'"$section"'" && $1 == "'"$key"'" { + sub(/^[ \t]+/, "", $2) # Trim leading whitespace + sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace + print $2 + exit + } + ' "$ini_file" + } + + # Werte auslesen + VORNAME=$(ini_get "UserData" "Vorname") + NACHNAME=$(ini_get "UserData" "Nachname") + PASSWORT=$(ini_get "UserData" "Passwort") + + touch "$config_file" + { + echo "[${VORNAME}${NACHNAME}]" + echo "RegionUUID = ${region_uuid}" + echo "Location = ${location}" + echo "SizeX = ${SIZES}" + echo "SizeY = ${SIZES}" + echo "SizeZ = ${SIZES}" + echo "InternalPort = ${port}" + echo "ExternalHostName = ${system_ip}" + echo "MaxPrims = 45000" + echo "MaxAgents = 40" + echo "MaptileStaticUUID = 20000000-1000-1000-1000-200000000000" + echo "InternalAddress = 0.0.0.0" + echo "AllowAlternatePorts = False" + echo "NonPhysicalPrimMax = 512" + echo "PhysicalPrimMax = 128" + echo ";ClampPrimSize = false" + echo ";MaxPrimsPerUser = -1" + echo ";ScopeID = 30000000-1000-1000-1000-300000000000" + echo ";RegionType = Mainland" + echo ";RenderMinHeight = -1" + echo ";RenderMaxHeight = 100" + echo ";MapImageModule = Warp3DImageModule" + echo ";TextureOnMapTile = true" + echo ";DrawPrimOnMapTile = true" + echo ";GenerateMaptiles = true" + echo ";MaptileRefresh = 0" + echo ";MaptileStaticFile = path/to/SomeFile.png" + echo ";MasterAvatarFirstName = ${VORNAME}" + echo ";MasterAvatarLastName = ${NACHNAME}" + echo ";MasterAvatarSandboxPassword = ${PASSWORT}" + } > "$config_file" + + echo "Region '${region_name}' wurde erfolgreich erstellt in ${config_file} (Location: ${location}, Port: ${port})" + + # Datei Regions.ini löschen + rm -v "opensim/bin/Regions/Regions.ini" +} + +function createstandaloneconfig() { + system_ip=$(hostname -I | awk '{print $1}') + file="$SCRIPT_DIR/opensim/bin/OpenSim.ini" + standalonehg="ja" + + # 1. INI-Datei auslesen mit angepasstem Parsing + ini_file="${SCRIPT_DIR}/OpenSimUserInfo.ini" + if [[ ! -f "$ini_file" ]]; then + log "${COLOR_BAD}UserInfo.ini nicht gefunden unter: $ini_file${COLOR_RESET}" + return 1 + fi + + # Parsing-Funktion mit Trim und Leerzeichen im Pattern + ini_get() { + local section="$1" key="$2" + awk -F ' = ' ' + /^\[/ { current_section = substr($0, 2, length($0)-2) } + current_section == "'"$section"'" && $1 == "'"$key"'" { + sub(/^[ \t]+/, "", $2) # Trim leading whitespace + sub(/[ \t\r]+$/, "", $2) # Trim trailing whitespace + print $2 + exit + } + ' "$ini_file" + } + + # Werte auslesen + VORNAME=$(ini_get "UserData" "Vorname") + NACHNAME=$(ini_get "UserData" "Nachname") + PASSWORT=$(ini_get "UserData" "Passwort") + + if [[ -z "$standalonehg" ]]; then + log "${COLOR_BAD}FEHLER: Variable 'standalonehg' nicht definiert!${COLOR_RESET}" + return 1 + fi + + # [Const] + set_ini_key "$file" "Const" "BaseHostname" "\"${system_ip}\"" + set_ini_key "$file" "Const" "PublicPort" "\"9010\"" + # [Estates] + set_ini_key "$file" "Estates" "DefaultEstateName" "\"$VORNAME$NACHNAME Estate\"" + set_ini_key "$file" "Estates" "DefaultEstateOwnerName" "\"9010\"" + set_ini_key "$file" "Estates" "DefaultEstateOwnerUUID" "\"10000000-1000-1000-1000-100000000000\"" + set_ini_key "$file" "Estates" "DefaultEstateOwnerPassword" "\"${PASSWORT}\"" + # [Terrain] + set_ini_key "$file" "Terrain" "InitialTerrain" "\"flat\"" + + if [[ "$standalonehg" = "ja" ]]; then + # [Architecture] + set_ini_key "$file" "Architecture" "Include-Architecture" "\"config-include/StandaloneHypergrid.ini\"" + log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" + else + # [Architecture] + set_ini_key "$file" "Architecture" "Include-Architecture" "\"config-include/Standalone.ini\"" + log "${COLOR_FILE}Erstelle $file${COLOR_RESET}" + fi +} + +#* Standalone Installation +function buildstandalone() { + # OpenSimulator herunterladen und bauen + opensimgitcopy + # Skripte einfügen + osslscriptsgit + # Sourcecode Version vor dem kompilieren einstellen mit der Funktion versionrevision() + versionrevision + # OpenSimulator bauen + opensimbuild + # Standalone Setup + standalonesetup + # Create Standalone Config + createstandaloneconfig + # Create Startregion + createstandalonregion + # create user + createstandaloneuser + # Standalone neu starten + standalonerestart + + log "${COLOR_OK}Standalone OpenSimulator wurde erfolgreich installiert, die Daten stehen in der Datei OpenSimUserInfo.ini${COLOR_RESET}" + +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Hilfefunktionen +#?────────────────────────────────────────────────────────────────────────────────────────── + +function help() { + # Allgemeine Befehle + log "${COLOR_SECTION}${SYM_SERVER} OpenSim Grundbefehle:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_START}opensimstart${COLOR_RESET} \t\t # Startet OpenSimulator komplett" + log "${SYM_VOR} ${COLOR_STOP}opensimstop${COLOR_RESET} \t\t # Stoppt OpenSimulator komplett" + log "${SYM_VOR} ${COLOR_RESTART}opensimrestart${COLOR_RESET} \t # Startet den OpenSimulator komplett neu" + echo + log "${SYM_VOR} ${COLOR_START}simstart${COLOR_RESET} \t\t # simX angeben - startet einen Regionsserver" + log "${SYM_VOR} ${COLOR_STOP}simstop${COLOR_RESET} \t\t # simX angeben - stoppt einen Regionsserver" + log "${SYM_VOR} ${COLOR_RESTART}simrestart${COLOR_RESET} \t\t # simX angeben - startet einen Regionsserver neu" + echo "" + log "${SYM_VOR} ${COLOR_START}standalonestart${COLOR_RESET} \t # Standalone starten" + log "${SYM_VOR} ${COLOR_STOP}standalonestop${COLOR_RESET} \t # Standalone stoppen" + log "${SYM_VOR} ${COLOR_RESTART}standalonerestart${COLOR_RESET} \t # Standalone neu starten" + echo "" + log "${SYM_VOR} ${COLOR_RESTART}simkill${COLOR_RESET} \t\t # Wenn der Simulator nicht beendet werden kann" + echo "" + + # System-Checks + log "${COLOR_SECTION}${SYM_TOOLS} System-Checks:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}check_screens${COLOR_RESET} \t\t # Prüft laufende Prozesse und handelt entsprechend" + echo "" + + # Setup + log "${COLOR_SECTION}${SYM_TOOLS} Setup:${COLOR_RESET}" + #log "${SYM_VOR} ${COLOR_OK}servercheck${COLOR_RESET} \t\t # Installiert und Prüft den Server" + #log "${SYM_VOR} ${COLOR_OK}createdirectory${COLOR_RESET} \t\t # Erstellt alle benötigten Verzeichnisse" + log "${SYM_VOR} ${COLOR_OK}autoinstall${COLOR_RESET} \t\t # OpenSimulator Automatisiert installieren und einrichten" + log "${SYM_VOR} ${COLOR_OK}setcrontab${COLOR_RESET} \t\t # Richtet Crontab ein damit der Server wartungsfrei laeuft" + echo "" + + # Git-Operationen + #log "${COLOR_SECTION}${SYM_BOOK} Git-Operationen:${COLOR_RESET}" + #log "${SYM_VOR} ${COLOR_OK}opensimgitcopy${COLOR_RESET} \t\t # Klont den OpenSim Code" + #log "${SYM_VOR} ${COLOR_OK}moneygitcopy${COLOR_RESET} \t\t # Baut den MoneyServer in den OpenSimulator ein" + #log "${SYM_VOR} ${COLOR_OK}osslscriptsgit${COLOR_RESET} \t\t # Klont OSSL-Skripte" + #log "${SYM_VOR} ${COLOR_OK}versionrevision${COLOR_RESET} \t\t # Setzt Versionsrevision" + #echo "" + + # OpenSim Build & Deploy + #log "${COLOR_SECTION}${SYM_FOLDER} OpenSim Build & Deploy:${COLOR_RESET}" + #log "${SYM_VOR} ${COLOR_OK}opensimbuild${COLOR_RESET} \t\t # Kompiliert OpenSim zu ausführbaren Dateien" + #log "${SYM_VOR} ${COLOR_OK}opensimcopy${COLOR_RESET} \t\t # Kopiert OpenSim in alle Verzeichnisse" + #log "${SYM_VOR} ${COLOR_OK}opensimupgrade${COLOR_RESET} \t\t # Upgradet OpenSim" + #log "${SYM_VOR} ${COLOR_OK}database_setup${COLOR_RESET} \t\t # Erstellt alle Datenbanken" + #echo "" + + # Konfigurationsmanagement + #log "${COLOR_SECTION}${SYM_CONFIG} Konfigurationsmanagement:${COLOR_RESET}" + #log "${SYM_VOR} ${COLOR_WARNING}moneyserveriniconfig${COLOR_RESET}\t# Konfiguriert MoneyServer.ini (experimentell)" + #log "${SYM_VOR} ${COLOR_WARNING}opensiminiconfig${COLOR_RESET}\t# Konfiguriert OpenSim.ini (experimentell)" + #log "${SYM_VOR} ${COLOR_WARNING}regionsiniconfig${COLOR_RESET}\t# Konfiguriert Regionen (experimentell)" + #echo "" + + # Systembereinigung + log "${COLOR_SECTION}${SYM_CLEAN} Systembereinigung:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}cacheclean${COLOR_RESET} \t\t # Bereinigt OpenSimulator Cache" + log "${SYM_VOR} ${COLOR_OK}logclean${COLOR_RESET} \t\t # Bereinigt OpenSimulator Logs" + log "${SYM_VOR} ${COLOR_OK}mapclean${COLOR_RESET} \t\t # Bereinigt OpenSimulator Maptiles" + #log "${SYM_VOR} ${COLOR_OK}clean_linux_logs${COLOR_RESET}\t# Bereinigt Systemlogs" + echo "" + + # Hilfe + log "${COLOR_SECTION}${SYM_INFO} Hilfe:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}help${COLOR_RESET} \t\t\t # Zeigt diese Hilfe" + log "${SYM_VOR} ${COLOR_OK}prohelp${COLOR_RESET} \t\t # Zeigt die Pro Hilfe" + echo "" + log "${COLOR_SECTION}${SYM_INFO} Aufruf mit: bash osmtool.sh ${COLOR_RESET}" +} + +function prohelp() { + #* OpenSim Grundbefehle + log "${COLOR_SECTION}${SYM_SERVER} OpenSim Grundbefehle:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_START}opensimstart${COLOR_RESET} \t\t # OpenSim starten" + log "${SYM_VOR} ${COLOR_STOP}opensimstop${COLOR_RESET} \t\t # OpenSim stoppen" + log "${SYM_VOR} ${COLOR_RESTART}opensimrestart${COLOR_RESET} \t # OpenSim neu starten" + log "${SYM_VOR} ${COLOR_OK}check_screens${COLOR_RESET} \t\t # Laufende OpenSim-Prozesse prüfen und neu starten" + log "${SYM_VOR} ${COLOR_OK}autoupgrade${COLOR_RESET} \t\t # Automatisches OpenSim upgrade" + echo " " + log "${SYM_VOR} ${COLOR_START}opensimstartParallel${COLOR_RESET} \t # Startet alle Regionen parallel" + log "${SYM_VOR} ${COLOR_STOP}opensimstopParallel${COLOR_RESET} \t # Stoppt alle Regionen parallel" + log "${SYM_VOR} ${COLOR_RESTART}opensimrestartParallel${COLOR_RESET} # Startet alle Regionen neu (parallel)" + + log "${SYM_VOR} ${COLOR_START}simstart${COLOR_RESET} \t\t # Startet eine bestimmte Region" + log "${SYM_VOR} ${COLOR_STOP}simstop${COLOR_RESET} \t\t # Stoppt eine bestimmte Region" + log "${SYM_VOR} ${COLOR_RESTART}simrestart${COLOR_RESET} \t\t # Startet eine bestimmte Region neu" + echo " " + log "${SYM_VOR} ${COLOR_RESTART}simkill${COLOR_RESET} \t\t # Wenn der Simulator nicht beendet werden kann" + echo "" + + #* Standalone-Operationen + log "${COLOR_SECTION}${SYM_SCRIPT} Standalone-Operationen:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_START}standalonestart${COLOR_RESET} \t\t # Standalone starten" + log "${SYM_VOR} ${COLOR_STOP}standalonestop${COLOR_RESET} \t\t # Standalone stoppen" + log "${SYM_VOR} ${COLOR_RESTART}standalonerestart${COLOR_RESET} \t\t # Standalone neu starten" + log "${SYM_VOR} ${COLOR_OK}standalonestatus${COLOR_RESET} \t\t # Standalone Status anzeigen" + echo " " + log "${SYM_VOR} ${COLOR_OK}buildstandalone${COLOR_RESET} \t\t # Standalone erstellen" + log "${SYM_VOR} ${COLOR_OK}opensimgitcopy${COLOR_RESET} \t\t # OpenSimulator aus Git kopieren" + log "${SYM_VOR} ${COLOR_OK}osslscriptsgit${COLOR_RESET} \t\t # Skripte aus Repository einfügen" + log "${SYM_VOR} ${COLOR_OK}versionrevision${COLOR_RESET} \t\t # OpenSimulator-Version festlegen" + log "${SYM_VOR} ${COLOR_OK}opensimbuild${COLOR_RESET} \t\t\t # OpenSimulator bauen" + log "${SYM_VOR} ${COLOR_OK}standalonesetup${COLOR_RESET} \t\t # Standalone Setup durchführen" + log "${SYM_VOR} ${COLOR_OK}createmasteruser${COLOR_RESET} \t\t # Master-Benutzer erstellen" + echo " " + + #* System-Checks + log "${COLOR_SECTION}${SYM_TOOLS} System-Checks:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}servercheck${COLOR_RESET} \t\t # Serverbereitschaft prüfen und Abhängigkeiten installieren" + echo " " + + #* Setup + log "${COLOR_SECTION}${SYM_TOOLS} Setup:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}createdirectory${COLOR_RESET} \t # OpenSim-Verzeichnisse erstellen" + log "${SYM_VOR} ${COLOR_OK}setcrontab${COLOR_RESET} \t\t # Crontab Automatisierungen einrichten" + log "${SYM_VOR} ${COLOR_OK}setup_webserver${COLOR_RESET} \t # Webserver einrichten" + log "${SYM_VOR} ${COLOR_OK}webinstall${COLOR_RESET} \t\t # Webinterface installieren" + log "${SYM_VOR} ${COLOR_OK}osWebinterfacegit${COLOR_RESET} \t # Webinterface aus Git holen" + log "${SYM_VOR} ${COLOR_OK}autoinstall${COLOR_RESET} \t\t # OpenSimulator Automatisiert installieren und einrichten" + log "${SYM_VOR} ${COLOR_OK}firststart${COLOR_RESET} \t\t # Erststart-Konfiguration durchführen" + log "${SYM_VOR} ${COLOR_OK}setup_email_server${COLOR_RESET} \t # E-Mail-Server einrichten" + log "${SYM_VOR} ${COLOR_OK}remove_ubuntu_pro${COLOR_RESET} \t # Ubuntu Pro entfernen" + echo " " + + #* Git-Operationen + log "${COLOR_SECTION}${SYM_BOOK} Git-Operationen:${COLOR_RESET}" + + log "${SYM_VOR} ${COLOR_OK}opensimgitcopy${COLOR_RESET} \t # OpenSim aus Git herunterladen" + log "${SYM_VOR} ${COLOR_OK}moneygitcopy${COLOR_RESET} \t\t # MoneyServer aus Git holen" + log "${SYM_VOR} ${COLOR_WARNING}ruthrothgit${COLOR_RESET} \t\t # Ruth Roth IAR Dateien ${COLOR_BAD}(Vorsicht)${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_WARNING}avatarassetsgit${COLOR_RESET} \t # Avatar-Assets ${COLOR_BAD}(Vorsicht)${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}osslscriptsgit${COLOR_RESET} \t # OSSL Beispielskripte herunterladen" + log "${SYM_VOR} ${COLOR_WARNING}pbrtexturesgit${COLOR_RESET} \t # PBR-Texturen ${COLOR_BAD}(Vorsicht)${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}downloadallgit${COLOR_RESET} \t # Alle Git-Repos herunterladen" + log "${SYM_VOR} ${COLOR_OK}versionrevision${COLOR_RESET} \t # Versionsverwaltung aktivieren" + echo " " + + #* OpenSim Build & Deployment + log "${COLOR_SECTION}${SYM_FOLDER} OpenSim Build & Deploy:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}opensimbuild${COLOR_RESET} \t\t\t # OpenSim kompilieren" + log "${SYM_VOR} ${COLOR_OK}opensimcopy${COLOR_RESET} \t\t\t # OpenSim Dateien kopieren" + log "${SYM_VOR} ${COLOR_OK}opensimupgrade${COLOR_RESET} \t\t # OpenSim aktualisieren" + log "${SYM_VOR} ${COLOR_OK}database_setup${COLOR_RESET} \t\t # Datenbank für OpenSim einrichten" + log "${SYM_VOR} ${COLOR_OK}removeconfigfiles${COLOR_RESET} \t\t # Konfigurationsdateien entfernen" + log "${SYM_VOR} ${COLOR_OK}cleanconfig${COLOR_RESET} \t\t\t # Konfiguration bereinigen" + echo " " + log "${SYM_VOR} ${COLOR_OK}autoupgrade${COLOR_RESET} \t\t\t # Führt automatisches Update durch" + log "${SYM_VOR} ${COLOR_OK}autoupgradefast${COLOR_RESET} \t\t # Automatisches OpenSim Parallel upgraden" + log "${SYM_VOR} ${COLOR_OK}regionbackup${COLOR_RESET} \t\t\t # Sichert aktuelle Regionen-Daten" + log "${SYM_VOR} ${COLOR_OK}robustbackup${COLOR_RESET} \t\t\t # Backup der Robust-Datenbank (mit Zeitraumfilter)" + log "${SYM_VOR} ${COLOR_OK}robustrestore [teil]${COLOR_RESET} # Wiederherstellung aus robustbackup ${COLOR_BAD} experimentell${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}robustrepair [aktion]${COLOR_RESET} # Reparatur oder Bereinigung der Robust-DB ${COLOR_BAD} experimentell${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}restoreRobustDump ${COLOR_RESET} # Robust Wiederherstellung${COLOR_BAD} experimentell${COLOR_RESET}" + echo " " + + #* Konfigurationsmanagement + log "${COLOR_SECTION}${SYM_CONFIG} Konfigurationsmanagement:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_WARNING}moneyserveriniconfig${COLOR_RESET} \t\t # Konfiguriert MoneyServer.ini" + log "${SYM_VOR} ${COLOR_WARNING}opensiminiconfig${COLOR_RESET} \t\t # Konfiguriert OpenSim.ini" + log "${SYM_VOR} ${COLOR_WARNING}robusthginiconfig${COLOR_RESET} \t\t # Konfiguriert Robust.HG.ini" + log "${SYM_VOR} ${COLOR_WARNING}robustiniconfig${COLOR_RESET} \t\t # Konfiguriert Robust.local.ini" + log "${SYM_VOR} ${COLOR_WARNING}gridcommoniniconfig${COLOR_RESET} \t\t # Erstellt GridCommon.ini" + log "${SYM_VOR} ${COLOR_WARNING}standalonecommoniniconfig${COLOR_RESET} \t # Erstellt StandaloneCommon.ini" + log "${SYM_VOR} ${COLOR_WARNING}flotsaminiconfig${COLOR_RESET} \t\t # Erstellt FlotsamCache.ini" + log "${SYM_VOR} ${COLOR_WARNING}osslenableiniconfig${COLOR_RESET} \t\t # Konfiguriert osslEnable.ini" + log "${SYM_VOR} ${COLOR_WARNING}welcomeiniconfig${COLOR_RESET} \t\t # Konfiguriert Begrüßungsregion" + log "${SYM_VOR} ${COLOR_WARNING}regionsiniconfig${COLOR_RESET} \t\t # Startet neue Regionen-Konfigurationen" + log "${SYM_VOR} ${COLOR_WARNING}database_set_iniconfig${COLOR_RESET} \t # Datenbank-Konfiguration setzen" + log "${SYM_VOR} ${COLOR_WARNING}oswebinterfaceconfig${COLOR_RESET} \t\t # Webinterface konfigurieren" + log "${SYM_VOR} ${COLOR_WARNING}iniconfig${COLOR_RESET} \t\t\t # Startet ALLE Konfigurationen" + echo " " + + #* INI-Operationen + log "${COLOR_SECTION}${SYM_SCRIPT} INI-Operationen:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}verify_ini_section${COLOR_RESET} \t\t # INI-Abschnitt verifizieren" + log "${SYM_VOR} ${COLOR_OK}verify_ini_key${COLOR_RESET} \t\t # INI-Schlüssel verifizieren" + log "${SYM_VOR} ${COLOR_OK}add_ini_section${COLOR_RESET} \t\t # INI-Abschnitt hinzufügen" + log "${SYM_VOR} ${COLOR_OK}add_ini_before_section${COLOR_RESET} \t # INI-Abschnitt vor anderem einfügen" + log "${SYM_VOR} ${COLOR_OK}set_ini_key${COLOR_RESET} \t\t\t # INI-Schlüssel setzen" + log "${SYM_VOR} ${COLOR_OK}add_ini_key${COLOR_RESET} \t\t\t # INI-Schlüssel hinzufügen" + log "${SYM_VOR} ${COLOR_WARNING}del_ini_section${COLOR_RESET} \t\t # INI-Abschnitt löschen" + log "${SYM_VOR} ${COLOR_OK}uncomment_ini_line${COLOR_RESET} \t\t # INI-Zeile entkommentieren" + log "${SYM_VOR} ${COLOR_OK}uncomment_ini_section_line${COLOR_RESET} \t # INI-Zeile in Abschnitt entkommentieren" + log "${SYM_VOR} ${COLOR_OK}comment_ini_line${COLOR_RESET} \t\t # INI-Zeile auskommentieren" + echo " " + + #* XML-Operationen + log "${COLOR_SECTION}${SYM_SCRIPT} XML-Operationen:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}verify_xml_section${COLOR_RESET} \t\t # XML-Abschnitt verifizieren" + log "${SYM_VOR} ${COLOR_OK}add_xml_section${COLOR_RESET} \t\t # XML-Abschnitt hinzufügen" + log "${SYM_VOR} ${COLOR_WARNING}del_xml_section${COLOR_RESET} \t\t # XML-Abschnitt löschen" + echo " " + + #* Experimental + log "${COLOR_SECTION}${SYM_WARNING} Experimental:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_WARNING}configure_pbr_textures${COLOR_RESET} \t # PBR-Texturen konfigurieren" + log "${SYM_VOR} ${COLOR_OK}buildopensim${COLOR_RESET} \t\t\t # OpenSim Experimental Build" + log "${SYM_VOR} ${COLOR_OK}rootrights${COLOR_RESET} \t\t\t # Root-Rechte setzen" + echo " " + + #* System-Bereinigung + log "${COLOR_SECTION}${SYM_CLEAN} Systembereinigung:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}reboot${COLOR_RESET} \t\t # Linux Server neu starten" + log "${SYM_VOR} ${COLOR_OK}dataclean${COLOR_RESET} \t\t # OpenSimulator Daten bereinigen" + log "${SYM_VOR} ${COLOR_OK}pathclean${COLOR_RESET} \t\t # Pfade bereinigen" + log "${SYM_VOR} ${COLOR_OK}cacheclean${COLOR_RESET} \t\t # OpenSimulator Cache bereinigen" + log "${SYM_VOR} ${COLOR_OK}logclean${COLOR_RESET} \t\t # OpenSimulator Logs bereinigen" + log "${SYM_VOR} ${COLOR_OK}mapclean${COLOR_RESET} \t\t # OpenSimulator Maptiles bereinigen" + log "${SYM_VOR} ${COLOR_OK}autoallclean${COLOR_RESET} \t\t # Automatische Komplettbereinigung" + echo " " + log "${SYM_VOR} ${COLOR_OK}regionsclean${COLOR_RESET} \t\t # Alle Regionsdateien löschen" + log "${SYM_VOR} ${COLOR_OK}cleanall${COLOR_RESET} \t\t # Löscht OpenSim komplett" + log "${SYM_VOR} ${COLOR_OK}renamefiles${COLOR_RESET} \t\t # OpenSimulator Beispieldateien umbenennen" + log "${SYM_VOR} ${COLOR_OK}clean_linux_logs${COLOR_RESET} \t # Linux-Logs bereinigen" + log "${SYM_VOR} ${COLOR_OK}delete_opensim${COLOR_RESET} \t # OpenSimulator mit Verzeichnisse entfernen" + echo " " + + #* Hilfe + log "${COLOR_SECTION}${SYM_INFO} Hilfe:${COLOR_RESET}" + log "${SYM_VOR} ${COLOR_OK}help${COLOR_RESET} \t\t\t # Einfache Hilfeseite anzeigen" + log "${SYM_VOR} ${COLOR_OK}prohelp${COLOR_RESET} \t\t # Diese erweiterte Hilfe anzeigen" + #log "${SYM_VOR} ${COLOR_OK}generate_all_name${COLOR_RESET} \t\t # Namen generieren" + echo " " + log "${COLOR_SECTION}${SYM_INFO} Aufruf mit: bash osmtool.sh ${COLOR_RESET}" +} + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Eingabeauswertung +#?────────────────────────────────────────────────────────────────────────────────────────── + +case $KOMMANDO in + # Allgemeine Befehle # + check_screens) check_screens ;; + start|opensimstart) opensimstart ;; + stop|opensimstop) opensimstop ;; + osrestart|autorestart|restart|opensimrestart) opensimrestart ;; + simstart) simstart "$2" ;; + simstop) simstop "$2" ;; + simrestart) simrestart "$2" ;; + + # SYSTEM-CHECKS & SETUP # + servercheck) servercheck ;; + createdirectory) createdirectory ;; + setcrontab) setcrontab ;; + + # GIT-OPERATIONEN # + opensimgitcopy|opensimgit) opensimgitcopy ;; + moneygitcopy|moneygit) moneygitcopy ;; + ruthrothgit) ruthrothgit ;; + avatarassetsgit) avatarassetsgit ;; + osslscriptsgit) osslscriptsgit ;; + pbrtexturesgit) pbrtexturesgit ;; + downloadallgit) downloadallgit ;; + versionrevision) versionrevision ;; + osWebinterfacegit) osWebinterfacegit ;; + + # OPENSIM BUILD & DEPLOY # + opensimbuild) opensimbuild ;; + opensimcopy) opensimcopy ;; + opensimupgrade) opensimupgrade ;; + database_setup) database_setup ;; + setup_webserver) setup_webserver ;; + removeconfigfiles) removeconfigfiles ;; + webinstall) webinstall ;; + autoinstall) autoinstall ;; + + # KONFIGURATIONS-MGMT AUTOKONFIGURATION # + moneyserveriniconfig) moneyserveriniconfig "$2" "$3" ;; + opensiminiconfig) opensiminiconfig "$2" "$3" ;; + robusthginiconfig) robusthginiconfig "$2" "$3" ;; + robustiniconfig) robustiniconfig "$2" "$3" ;; + gridcommoniniconfig) gridcommoniniconfig "$2" "$3" ;; + standalonecommoniniconfig) standalonecommoniniconfig "$2" "$3" ;; + flotsaminiconfig) flotsaminiconfig "$2" "$3" ;; + osslenableiniconfig) osslenableiniconfig "$2" "$3" ;; + welcomeiniconfig) welcomeiniconfig "$2" "$3" ;; + database_set_iniconfig) database_set_iniconfig ;; + regionsiniconfig) regionsiniconfig ;; # Alle neuen Konfigurationen starten. + cleanconfig) clean_config "$2" ;; + createmasteruser) createmasteruser "$2" "$3" "$4" "$5" "$6" ;; + oswebinterfaceconfig) oswebinterfaceconfig ;; + firststart) firststart ;; + + # Experimental # + configure_pbr_textures) configure_pbr_textures ;; + + # INI-OPERATIONEN # + verify_ini_section) verify_ini_section "$2" "$3" "$4" ;; + verify_ini_key) verify_ini_key "$2" "$3" "$4" ;; + add_ini_section) add_ini_section "$2" "$3" ;; + add_ini_before_section) add_ini_before_section "$2" "$3" "$4" ;; + set_ini_key) set_ini_key "$2" "$3" "$4" "$5" ;; + add_ini_key) add_ini_key "$2" "$3" "$4" "$5" ;; + del_ini_section) del_ini_section "$2" "$3" ;; + uncomment_ini_line) uncomment_ini_line "$2" "$3" ;; + uncomment_ini_section_line) uncomment_ini_section_line "$2" "$3" "$4" ;; + comment_ini_line) comment_ini_line "$2" "$3" "$4" ;; + iniconfig) iniconfig ;; + + # XML-OPERATIONEN # + verify_xml_section) verify_xml_section "$2" "$3" ;; + add_xml_section) add_xml_section "$2" "$3" "$4" ;; + del_xml_section) del_xml_section "$2" "$3" ;; + + # STANDALONE-MODUS # + standalonesetup) standalonesetup ;; + standalonestart) standalonestart ;; + standalonestop) standalonestop ;; + standalonerestart) standalonerestart ;; + standalonestatus) standalonestatus ;; + + # SYSTEM-BEREINIGUNG # + reboot) reboot ;; + dataclean) dataclean ;; + pathclean) pathclean ;; + cacheclean) cacheclean ;; + logclean) logclean ;; + mapclean) mapclean ;; + autoallclean) autoallclean ;; + regionsclean) regionsclean ;; + cleanall) cleanall ;; + renamefiles) renamefiles ;; + clean_linux_logs) clean_linux_logs ;; + delete_opensim) delete_opensim ;; + + # Tests # + opensimstartParallel) opensimstartParallel ;; # Das Parallel verarbeiten kann bei großen Regionen den Server + faststop|opensimstopParallel) opensimstopParallel ;; # so belasten das er nicht mehr reagieren kann. + opensimrestartParallel) opensimrestartParallel ;; + autoupgrade) autoupgrade ;; + autoupgradefast) autoupgradefast ;; + regionbackup) regionbackup ;; + robustbackup) robustbackup ;; + robustrestore) robustrestore "$2" "$3" "$4" ;; + robustrepair) robustrepair "$2" "$3" "$4" ;; + restoreRobustDump) restoreRobustDump "$2" "$3" "$4" "$5" ;; + rootrights) rootrights ;; + buildopensim) buildopensim ;; + buildstandalone) buildstandalone ;; + setup_email_server) setup_email_server ;; + remove_ubuntu_pro) remove_ubuntu_pro ;; + simkill) simkill "$2" ;; + newservercheck) newservercheck ;; + + # Laden und Speichern von iar und oar + loadinventar) loadinventar "$2" "$3" "$4" "$5" ;; #loadinventar MyInventory mydirectory mypassword myinventory.iar + saveinventar) saveinventar "$2" "$3" "$4" "$5" ;; #saveinventar "MeinInventar" "/pfad/zum/verzeichnis" "geheimesPasswort" "inventar.iar" + loadoar) loadoar "$2" "$3" "$4" ;; #loadoar "RestoreScreen" "MyRegion" "/pfad/zum/verzeichnis" + saveoar) saveoar "$2" "$3" "$4" ;; #saveoar "RestoreScreen" "MyRegion" "/pfad/zum/verzeichnis" + autoregionbackup) autoregionbackup ;; + + # HILFE & SONSTIGES # + generate_all_name) generate_all_name ;; + prohelp) prohelp ;; + h|help|hilfe|*) help ;; +esac + +# Programm Ende mit Zeitstempel +blankline +log "\e[36m${SCRIPTNAME}\e[0m ${VERSION} wurde beendet $(date +'%Y-%m-%d %H:%M:%S')" >&2 +exit 0 + +# Ein Metaversum sind viele kleine Räume, die nahtlos aneinander passen, sowie direkt sichtbar und begehbar sind, als wäre es aus einem Guss. +# Ein Metaversum besteht aus vielen kleinen, nahtlos verbundenen Räumen, die direkt sichtbar und begehbar sind – als wäre alles aus einem Guss erschaffen. +# Das Metaversum setzt sich aus zahlreichen virtuellen Räumen zusammen, die ohne Ladezeiten oder Übergänge miteinander verbunden sind und sich wie eine zusammenhängende Welt erleben lassen. diff --git a/osmtool_backup.sh b/osmtool_backup.sh index fae6cb8..25bd5d4 100644 --- a/osmtool_backup.sh +++ b/osmtool_backup.sh @@ -1,719 +1,719 @@ -#!/bin/bash - -# Backup Version 1.0 - -STARTVERZEICHNIS="/opt" # Startverzeichnis -ROBUSTVERZEICHNIS="Robust" # Robust Verzeichnis -REGIONSDATEI="osmregionlist.ini" # Regionsdatei -SIMDATEI="osmsimlist.ini" # Simulationsdatei -BACKUPWARTEZEIT=60 # Wartezeit in Sekunden zwischen den Backups -DATUM=$(date '+%Y-%m-%d_%H-%M-%S') # Zeitstempel fuer Backupdateien - -KOMMANDO=$1 - -#────────────────────────────────────────────────────────────────────────────────────────── -#* Informationen -#────────────────────────────────────────────────────────────────────────────────────────── -# - -## * makeverzeichnisliste - # Eine Funktion zum Erstellen einer Liste von Verzeichnissen aus einer Datei. - #? Verwendung: makeverzeichnisliste - # Diese Funktion liest Zeilen aus der angegebenen SIMDATEI im STARTVERZEICHNIS und erstellt eine - # Liste von Verzeichnissen. Die Liste wird in der globalen Variable VERZEICHNISSLISTE gespeichert. - # Die Anzahl der Einträge in der Liste wird in der globalen Variable ANZAHLVERZEICHNISSLISTE gespeichert. - #? Argumente: - # STARTVERZEICHNIS - Das Verzeichnis, in dem sich die SIMDATEI befindet. - # SIMDATEI - Die Datei, aus der die Verzeichnisse gelesen werden sollen. - #? Beispielaufruf - # makeverzeichnisliste -## -function makeverzeichnisliste() { - # Letzte Bearbeitung 27.09.2023 - - # Initialisieren der Verzeichnisliste - VERZEICHNISSLISTE=() - - # Schleife zum Lesen der Zeilen aus der SIMDATEI und Hinzufügen zum Array - while IFS= read -r line; do - VERZEICHNISSLISTE+=("$line") - done >"/$STARTVERZEICHNIS/$INIVERZEICHNIS/bin/Regions/$RTREGIONSNAME.ini" - else - echo error "REGIONSINITEILEN: $INI_FILE wurde nicht gefunden" - fi - return 0 -} - -## * autoregionsiniteilen - # Diese Funktion ruft zuerst die Funktion `makeverzeichnisliste` auf, um eine Liste von Verzeichnissen zu erstellen, - # und iteriert dann über jedes Verzeichnis in der Liste. Für jedes Verzeichnis wird die Regions.ini-Datei in mehrere - # separate INI-Dateien aufgeteilt, eine für jede Region, und die einzelnen Regionsdateien werden umbenannt. Falls die - # Regions.ini-Datei in einem Verzeichnis nicht vorhanden ist, wird sie nicht umbenannt. - #? Parameter: - # - Keine - #? Rückgabewert: - # - 0: Erfolgreiche Ausführung der Funktion - #? Verwendungsbeispiel: - # autoregionsiniteilen -## -function autoregionsiniteilen() { - # Letzte Bearbeitung 01.10.2023 - makeverzeichnisliste - sleep 1 - for ((i = 0; i < "$ANZAHLVERZEICHNISSLISTE"; i++)); do - echo info "Region.ini ${VERZEICHNISSLISTE[$i]} zerlegen" - echo line - VERZEICHNIS="${VERZEICHNISSLISTE[$i]}" - # Regions.ini teilen: - echo "$VERZEICHNIS" # OK geht - INI_FILE="/$STARTVERZEICHNIS/$VERZEICHNIS/bin/Regions/Regions.ini" # Auszulesende Datei - # shellcheck disable=SC2155 - declare -a TARGETS="$(get_regionsarray "${INI_FILE}")" - # shellcheck disable=SC2068 - for MeineRegion in ${TARGETS[@]}; do - regionsiniteilen "$VERZEICHNIS" "$MeineRegion" - sleep 1 - echo rohtext "regionsiniteilen $VERZEICHNIS $MeineRegion" - done - # Dann umbenennen: - # Pruefung ob Datei vorhanden ist, wenn ja umbenennen. - if [ ! -d "$INI_FILE" ]; then - mv /$STARTVERZEICHNIS/"$INIVERZEICHNIS"/bin/Regions/Regions.ini /$STARTVERZEICHNIS/"$INIVERZEICHNIS"/bin/Regions/"$DATUM"-Regions.ini.old - fi - done - return 0 -} - -## * createregionlist - # Diese Funktion erstellt eine Liste von Regionsnamen aus den INI-Dateien in den angegebenen Verzeichnissen und speichert - # sie in der Datei osmregionlist.ini. Zuvor wird die vorhandene osmregionlist.ini-Datei (falls vorhanden) gesichert und in - # osmregionlist.ini.old umbenannt. - #? Parameter: - # - Keine - #? Rückgabewert: - # - 0: Erfolgreiche Ausführung der Funktion - #? Verwendungsbeispiel: - # createregionlist -## -function createregionlist() { - # Letzte Bearbeitung 01.10.2023 - # Alte osmregionlist.ini sichern und in osmregionlist.ini.old umbenennen. - if [ -f "/$STARTVERZEICHNIS/osmregionlist.ini" ]; then - if [ -f "/$STARTVERZEICHNIS/osmregionlist.ini.old" ]; then - rm -r /$STARTVERZEICHNIS/osmregionlist.ini.old - fi - mv /$STARTVERZEICHNIS/osmregionlist.ini /$STARTVERZEICHNIS/osmregionlist.ini.old - fi - # Die mit regionsconfigdateiliste erstellte Datei osmregionlist.ini nach sim Verzeichnis und Regionsnamen in die osmregionlist.ini speichern. - declare -A Dateien # Array erstellen - makeverzeichnisliste - sleep 1 - for ((i = 0; i < "$ANZAHLVERZEICHNISSLISTE"; i++)); do - echo info "Regionnamen ${VERZEICHNISSLISTE[$i]} schreiben" - VERZEICHNIS="${VERZEICHNISSLISTE[$i]}" - # shellcheck disable=SC2178 - Dateien=$(find /$STARTVERZEICHNIS/"$VERZEICHNIS"/bin/Regions/ -name "*.ini") - for i2 in "${Dateien[@]}"; do # Array abarbeiten - echo "$i2" >>osmregionlist.ini - done - done - # Ueberfluessige Zeichen entfernen - LOESCHEN=$(sed s/'\/'$STARTVERZEICHNIS'\/'//g /$STARTVERZEICHNIS/osmregionlist.ini) - echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung /$STARTVERZEICHNIS/ speichern. - LOESCHEN=$(sed s/'\/bin\/Regions\/'/' "'/g /$STARTVERZEICHNIS/osmregionlist.ini) # /bin/Regions/ entfernen. - echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung /bin/Regions/ speichern. - LOESCHEN=$(sed s/'.ini'/'"'/g /$STARTVERZEICHNIS/osmregionlist.ini) # Endung .ini entfernen. - echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung .ini entfernen speichern. - - LOESCHEN=$(sed s/'\"'/''/g /$STARTVERZEICHNIS/osmregionlist.ini) # " entfernen. - echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung " entfernen speichern. - - # Schauen ob da noch Regions.ini bei sind also Regionen mit dem Namen Regions, diese Zeilen loeschen. - LOESCHEN=$(sed '/Regions/d' /$STARTVERZEICHNIS/osmregionlist.ini) # Alle Zeilen mit dem Eintrag Regions entfernen . - echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung .ini entfernen speichern. - return 0 -} - -## * regionbackup - # Diese Funktion erstellt ein Backup für eine OpenSimulator-Region, indem sie OAR- und Terrain-Daten sowie Konfigurationsdateien speichert. - # Die Region wird in den Offline-Modus versetzt, wenn sie nicht bereits offline ist, bevor das Backup erstellt wird. - #? Parameter: - # 1. BACKUPVERZEICHNISSCREENNAME: Der Name des Bildschirms (Screen) für das Backup. - # 2. REGIONSNAME: Der Name der Region, die gesichert werden soll. - #? Rückgabewert: - # - 0: Erfolgreiche Ausführung der Funktion - #? Verwendungsbeispiel: - # regionbackup "BackupScreen" "MyRegion" -## -function regionbackup() { - # Letzte Bearbeitung 01.10.2023 - # regionbackup "$BACKUPSCREEN" "$BACKUPREGION" - echo "Erstelle Backup von: $BACKUPSCREEN $BACKUPREGION" - - sleep 1 - BACKUPVERZEICHNISSCREENNAME=$1 - REGIONSNAME=$2 - - echo - echo "Backup $BACKUPVERZEICHNISSCREENNAME der Region $REGIONSNAME" - cd /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin || return 1 # Test ob Verzeichnis vorhanden. - mkdir -p /$STARTVERZEICHNIS/backup # Backup Verzeichnis anlegen falls nicht vorhanden. - echo "Ich kann nicht pruefen ob die Region im OpenSimulator vorhanden ist." - echo "Sollte sie nicht vorhanden sein wird root also alle Regionen gespeichert" - # Ist die Region Online oder Offline? - if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini.offline ]; then - echo "$REGIONSNAME ist heruntergefahren." - else - screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'change region ${REGIONSNAME//\"/}'^M" - echo "$BACKUPVERZEICHNISSCREENNAME $REGIONSNAME" - screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'save oar /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.oar'^M" - echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.oar" - - # Neu xml backup - screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'save xml2 /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.xml2'^M" - echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.xml2" - # Neu xml backup ende - - screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'terrain save /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.png'^M" - echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.png" - screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'terrain save /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.raw'^M" - echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.raw" - echo "$BACKUPVERZEICHNISSCREENNAME Region $DATUM-$REGIONSNAME RAW und PNG Terrain werden gespeichert" - fi - - sleep 10 - if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini.offline ]; then - cp /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini.offline /$STARTVERZEICHNIS/backup/"$DATUM"-"$REGIONSNAME".ini.offline - echo "$BACKUPVERZEICHNISSCREENNAME Die Regions $DATUM-$REGIONSNAME.ini.offline wird gespeichert" - fi - if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini ]; then - cp /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini /$STARTVERZEICHNIS/backup/"$DATUM"-"$REGIONSNAME".ini - echo "$BACKUPVERZEICHNISSCREENNAME Die Regions $DATUM-$REGIONSNAME.ini wird gespeichert" - fi - if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"${REGIONSNAME//\"/}" ]; then - cp /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"${REGIONSNAME//\"/}" /$STARTVERZEICHNIS/backup/"$DATUM"-"$REGIONSNAME".ini - echo "$BACKUPVERZEICHNISSCREENNAME Die Regions $DATUM-$REGIONSNAME.ini wird gespeichert" - fi - - echo "Backup der Region $REGIONSNAME wird fertiggestellt." - return 0 -} - - -## * autoallclean. - # loescht Log, dll, so, exe, aot Dateien fuer einen saubere neue installation, mit Robust. - # Hierbei werden keine Datenbanken oder Konfigurationen geloescht aber opensim ist anschliessend nicht mehr startbereit. - # Um opensim wieder Funktionsbereit zu machen muss ein Upgrade oder ein oscopy vorgang ausgefuehrt werden. - #? @param keine. - #? @return nichts wird zurueckgegeben. - # todo: nichts. -## -function autoallclean() { - # Letzte Bearbeitung 01.10.2023 - makeverzeichnisliste - sleep 1 - for ((i = 0; i < "$ANZAHLVERZEICHNISSLISTE"; i++)); do - # Dateien - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.log - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.dll - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.exe - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.so - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.xml - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.dylib - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.example - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.sample - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.txt - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.config - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.py - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.old - rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.pdb - - # Verzeichnisse leeren - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/assetcache/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/maptiles/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/MeshCache/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/j2kDecodeCache/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/ScriptEngines/* - - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addin-db-002/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addon-modules/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/assets/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/bakes/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/data/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Estates/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/inventory/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib32/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib64/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Library/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/openmetaverse_data/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/robust-include/* - - echo "autoallclean: ${VERZEICHNISSLISTE[$i]} geloescht" - sleep 1 - done - # nochmal das gleiche mit Robust - echo "autoallclean: $ROBUSTVERZEICHNIS geloescht" - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.log - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.dll - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.exe - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.so - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.xml - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.dylib - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.example - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.sample - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.txt - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.config - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.py - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.old - rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.pdb - - rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/assetcache/* - rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/maptiles/* - rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/MeshCache/* - rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/j2kDecodeCache/* - rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/ScriptEngines/* - - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addin-db-002/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addon-modules/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/assets/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/bakes/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/data/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Estates/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/inventory/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib32/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib64/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Library/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/openmetaverse_data/* - rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/robust-include/* - - return 0 -} - -## * autoregionbackup - # Diese Funktion durchläuft die Regionen in Ihrem OpenSimulator-Grid und erstellt automatische Backups. - #? Parameter: - # Keine Parameter erforderlich. - #? Rückgabewert: - # - Kein expliziter Rückgabewert - #? Verwendungsbeispiel: - # autoregionbackup - # todo: Uebergabe Parameter Fehler. Bug Modus mit extra ausgaben. Ist keine osmregionlist.ini vorhanden muss sie erstellt werden. -## -function autoregionbackup() { - # Letzte Bearbeitung 01.10.2023 - echo "Automatisches Backup wird gestartet." - - # Ist die osmregionlist.ini vorhanden? - if [ ! -f "/$STARTVERZEICHNIS/osmregionlist.ini" ]; then - echo "Die osmregionlist.ini Datei ist noch nicht vorhanden und wird erstellt." - createregionlist - else - echo "Die osmregionlist.ini Datei ist bereits vorhanden." - fi - - makeregionsliste - sleep 1 - for ((i = 0; i < "$ANZAHLREGIONSLISTE"; i++)); do - BACKUPSCREEN=$(echo "${REGIONSLISTE[$i]}" | cut -d ' ' -f 1) - BACKUPREGION=$(echo "${REGIONSLISTE[$i]}" | cut -d ' ' -f 2) - echo "Starte Backup von: $BACKUPSCREEN $BACKUPREGION" # Testausgabe - regionbackup "$BACKUPSCREEN" "$BACKUPREGION" - if [ -f /$STARTVERZEICHNIS/"$BACKUPSCREEN"/bin/Regions/"$BACKUPREGION".ini.offline ]; then - echo "$BACKUPREGION Region ist Offline und wird uebersprungen." - else - sleep $BACKUPWARTEZEIT - echo "BACKUPWARTEZEIT $BACKUPWARTEZEIT Sekunden." # Testausgabe - fi - done - return 0 -} - -# Zähle die Tabellen in der Datenbank und die Asset-Typen in der Tabelle 'assets'. -# bash osmtool_backup.sh datenbanktabellen "mein_benutzer" "geheim123" "meine_datenbank" -function datenbanktabellen() { - username=$1 - password=$2 - databasename=$3 - logfile="/$STARTVERZEICHNIS/backup/${databasename}/status_report.txt" - - mkdir -p "/$STARTVERZEICHNIS/backup/${databasename}" || exit - - echo "📊 Statusbericht für Datenbank: $databasename" | tee "$logfile" - echo "📅 Datum: $(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$logfile" - - # Tabellen zählen - tabellenanzahl=$(mysql -u"$username" -p"$password" -D"$databasename" -e "SHOW TABLES;" | tail -n +2 | wc -l) - echo "📦 Tabellen gefunden: $tabellenanzahl" | tee -a "$logfile" - - # Asset-Typen zählen (wenn Tabelle vorhanden) - if mysql -u"$username" -p"$password" -D"$databasename" -e "SHOW TABLES LIKE 'assets';" | grep -q "assets"; then - assettypen_anzahl=$(mysql -u"$username" -p"$password" -D"$databasename" -e "SELECT COUNT(DISTINCT assetType) FROM assets;" | tail -n 1) - echo "🎨 Asset-Typen in 'assets': $assettypen_anzahl" | tee -a "$logfile" - else - echo "⚠️ Tabelle 'assets' nicht gefunden." | tee -a "$logfile" - fi - - echo "✅ Bericht gespeichert unter: $logfile" -} - - -# beispiel: screen -fa -S BACKUPNOASSETS -d -U -m bash osmtool.sh backuptabelle_noassets "mein_benutzer" "geheim123" "meine_datenbank" -function backuptabelle_noassets() { - username=$1 - password=$2 - databasename=$3 - - mkdir -p /$STARTVERZEICHNIS/backup/"$databasename" || exit - logfile="/$STARTVERZEICHNIS/backup/${databasename}/backup_log.txt" - - # Tabellennamen holen und speichern - mysql -u"$username" -p"$password" -D"$databasename" -e "SHOW TABLES;" | tail -n +2 > /$STARTVERZEICHNIS/backup/"$databasename"/liste.txt - - # Anzahl der Tabellen zählen - tabellenanzahl=$(wc -l < /$STARTVERZEICHNIS/backup/"$databasename"/liste.txt) - echo "📦 Tabellen gefunden: $tabellenanzahl" | tee -a "$logfile" - - # Tabellen sichern (außer 'assets') - gesichert=0 - while IFS= read -r tabellenname; do - sleep 1 - if [[ "$tabellenname" != "assets" ]]; then - mysqldump -u"$username" -p"$password" "$databasename" "$tabellenname" | zip > /$STARTVERZEICHNIS/backup/"$databasename"/"$tabellenname".sql.zip - echo "✅ Gesichert: $tabellenname" | tee -a "$logfile" - ((gesichert++)) - fi - done < /$STARTVERZEICHNIS/backup/"$databasename"/liste.txt - - echo "🔒 Tabellen gesichert (ohne 'assets'): $gesichert" | tee -a "$logfile" - return 0 -} - -# screen -fa -S ASSETBACKUP -d -U -m bash osmtool.sh asset_backup "mein_benutzer" "geheim123" "meine_datenbank" -function asset_backup() { - username=$1 - password=$2 - databasename=$3 - fromtable="assets" - fromtypes="assetType" - - mkdir -p /$STARTVERZEICHNIS/backup/"$databasename"/assets || exit - cd /$STARTVERZEICHNIS/backup/"$databasename"/assets || exit - logfile="./asset_backup_log.txt" - - # Assettypen holen - mysql -u"$username" -p"$password" -D"$databasename" -e "SELECT DISTINCT $fromtypes FROM $fromtable;" | tail -n +2 > typen.txt - assettypen_anzahl=$(wc -l < typen.txt) - echo "📦 Assettypen gefunden: $assettypen_anzahl" | tee -a "$logfile" - - gesichert=0 - while IFS= read -r assettype; do - filename="assetType_${assettype}" - echo "✅ Sichere Asset-Typ: $assettype → $filename.sql.zip" | tee -a "$logfile" - mysqldump -u"$username" -p"$password" "$databasename" --tables "$fromtable" --where="$fromtypes = '$assettype'" | zip > "$filename.sql.zip" - ((gesichert++)) - done < typen.txt - - echo "🔒 Assettypen gesichert: $gesichert" | tee -a "$logfile" -} - -Unterschiedliche assettypen der Tabelle assets zählen - -# screen -fa -S DBRESTORE -d -U -m bash osmtool.sh db_restoretabelle_noassets "mein_benutzer" "geheim123" "meine_datenbank" -function db_restoretabelle_noassets() { - username=$1 - password=$2 - databasename=$3 - restorepath="/$STARTVERZEICHNIS/backup/${databasename}" - logfile="${restorepath}/restore_log.txt" - - cd "$restorepath" || exit - - if [[ ! -f liste.txt ]]; then - echo "❌ Keine 'liste.txt' gefunden. Backup-Datei fehlt oder ungültig." | tee -a "$logfile" - return 1 - fi - - echo "📦 Starte Wiederherstellung aus: $restorepath" | tee -a "$logfile" - - restored=0 - total=$(grep -cv "^assets$" liste.txt) - echo "🔍 Tabellen zur Wiederherstellung (ohne 'assets'): $total" | tee -a "$logfile" - - while IFS= read -r tabellenname; do - if [[ "$tabellenname" != "assets" ]]; then - zipfile="${tabellenname}.sql.zip" - if [[ -f "$zipfile" ]]; then - echo "🔄 Wiederherstellung: $tabellenname" | tee -a "$logfile" - unzip -p "$zipfile" | mysql -u"$username" -p"$password" "$databasename" - ((restored++)) - else - echo "⚠️ Datei fehlt: $zipfile" | tee -a "$logfile" - fi - fi - done < liste.txt - - echo "✅ Tabellen erfolgreich wiederhergestellt: $restored von $total" | tee -a "$logfile" - return 0 -} - -# Wiederherstellung der Asset-Typen -function asset_restore() { - username=$1 - password=$2 - databasename=$3 - restorepath="/$STARTVERZEICHNIS/backup/${databasename}/assets" - logfile="${restorepath}/asset_restore_log.txt" - - cd "$restorepath" || exit - - zipfiles=(assetType_*.sql.zip) - anzahl=${#zipfiles[@]} - echo "📦 Asset-Backups gefunden: $anzahl" | tee -a "$logfile" - - restored=0 - for zipfile in "${zipfiles[@]}"; do - echo "🔄 Wiederherstellung: $zipfile" | tee -a "$logfile" - unzip -p "$zipfile" | mysql -u"$username" -p"$password" "$databasename" - ((restored++)) - done - - echo "✅ Assettypen wiederhergestellt: $restored" | tee -a "$logfile" -} - -# Sichere die Datenbanken 'wordweb' und 'money' in ZIP-Dateien. -# bash osmtool_backup.sh sichere_wordweb_und_money "mein_benutzer" "geheim123" - -function sichere_wordweb_und_money() { - username=$1 - password=$2 - logfile="/$STARTVERZEICHNIS/backup/db_sicherung_log.txt" - datum=$(date '+%Y-%m-%d_%H-%M-%S') - - mkdir -p /$STARTVERZEICHNIS/backup/wordweb - mkdir -p /$STARTVERZEICHNIS/backup/money - - echo "📅 Sicherung gestartet: $datum" | tee -a "$logfile" - - # WORDWEB sichern - echo "💾 Sichere Datenbank: wordweb" | tee -a "$logfile" - mysqldump -u"$username" -p"$password" wordweb | zip > "/$STARTVERZEICHNIS/backup/wordweb/wordweb_${datum}.sql.zip" - size_wordweb=$(du -sh "/$STARTVERZEICHNIS/backup/wordweb/wordweb_${datum}.sql.zip" | cut -f1) - echo "✅ wordweb gesichert → Größe: $size_wordweb" | tee -a "$logfile" - - # MONEY sichern - echo "💾 Sichere Datenbank: money" | tee -a "$logfile" - mysqldump -u"$username" -p"$password" money | zip > "/$STARTVERZEICHNIS/backup/money/money_${datum}.sql.zip" - size_money=$(du -sh "/$STARTVERZEICHNIS/backup/money/money_${datum}.sql.zip" | cut -f1) - echo "✅ money gesichert → Größe: $size_money" | tee -a "$logfile" - - echo "📦 Sicherung abgeschlossen: $(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$logfile" -} - -function restore_wordweb_und_money() { - username=$1 - password=$2 - for dbname in wordweb money; do - restorepath="/$STARTVERZEICHNIS/backup/${dbname}" - latestfile=$(find "$restorepath" -maxdepth 1 -type f -name "*.sql.zip" -printf '%T@ %p\n' | sort -nr | head -n 1 | cut -d' ' -f2-) - if [[ -f "$latestfile" ]]; then - echo "🔄 Wiederherstellung: $dbname aus $latestfile" - unzip -p "$latestfile" | mysql -u"$username" -p"$password" "$dbname" - else - echo "⚠️ Keine Backup-Datei gefunden für $dbname" - fi - done -} - -# Backup-Konfigurationsdateien aus robust/bin und sim-Verzeichnissen -# bash osmtool_backup.sh backup_config -function backup_config() { - echo "${SYM_WAIT} ${COLOR_START}Sichere Konfigurationsdateien...${COLOR_RESET}" - - # Zielverzeichnis für Backups - backup_root="/opt/backup/config" - - # Backup aus robust/bin - if [[ -d "robust/bin" ]]; then - src_dir="robust/bin" - dest_dir="${backup_root}/${src_dir}" - echo "${SYM_OK} ${COLOR_START}Sichere ${COLOR_DIR}${src_dir}${COLOR_RESET} nach ${COLOR_DIR}${dest_dir}${COLOR_RESET}" - find "$src_dir" -type f -name "*.ini" | while read -r file; do - rel_path="${file#"$src_dir"/}" # relativer Pfad - mkdir -p "${dest_dir}/$(dirname "$rel_path")" - cp "$file" "${dest_dir}/$rel_path" - done - else - echo "${SYM_BAD} ${COLOR_DIR}robust/bin${COLOR_RESET} nicht gefunden. Überspringe." - fi - - # Backup aus sim-Verzeichnissen - for ((i=1; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" ]]; then - dest_dir="${backup_root}/${sim_dir}" - echo "${SYM_OK} ${COLOR_START}Sichere ${COLOR_DIR}${sim_dir}${COLOR_RESET} nach ${COLOR_DIR}${dest_dir}${COLOR_RESET}" - find "$sim_dir" -type f -name "*.ini" | while read -r file; do - rel_path="${file#"$sim_dir"/}" - mkdir -p "${dest_dir}/$(dirname "$rel_path")" - cp "$file" "${dest_dir}/$rel_path" - done - fi - done - - echo "${SYM_OK} ${COLOR_START}Backup abgeschlossen.${COLOR_RESET}" - echo . -} - -# Restore-Konfigurationsdateien aus dem backup Verzeichnis nach robust/bin und sim-Verzeichnissen -# bash osmtool_backup.sh restore_config -function restore_config() { - echo "${SYM_WAIT} ${COLOR_START}Stelle Konfigurationsdateien aus Backup wieder her...${COLOR_RESET}" - - # Quellverzeichnis für Backups - backup_root="/opt/backup/config" - - # Restore für robust/bin - src_dir="${backup_root}/robust/bin" - dest_dir="robust/bin" - if [[ -d "$src_dir" ]]; then - echo "${SYM_OK} ${COLOR_START}Stelle ${COLOR_DIR}${dest_dir}${COLOR_RESET} aus ${COLOR_DIR}${src_dir}${COLOR_RESET} wieder her" - find "$src_dir" -type f -name "*.ini" | while read -r file; do - rel_path="${file#"$src_dir"/}" - mkdir -p "${dest_dir}/$(dirname "$rel_path")" - cp "$file" "${dest_dir}/$rel_path" - done - else - echo "${SYM_BAD} ${COLOR_DIR}${src_dir}${COLOR_RESET} nicht gefunden. Überspringe." - fi - - # Restore für sim-Verzeichnisse - for ((i=1; i<=999; i++)); do - src_dir="${backup_root}/sim$i/bin" - dest_dir="sim$i/bin" - if [[ -d "$src_dir" ]]; then - echo "${SYM_OK} ${COLOR_START}Stelle ${COLOR_DIR}${dest_dir}${COLOR_RESET} aus ${COLOR_DIR}${src_dir}${COLOR_RESET} wieder her" - find "$src_dir" -type f -name "*.ini" | while read -r file; do - rel_path="${file#"$src_dir"/}" - mkdir -p "${dest_dir}/$(dirname "$rel_path")" - cp "$file" "${dest_dir}/$rel_path" - done - fi - done - - echo "${SYM_OK} ${COLOR_START}Wiederherstellung abgeschlossen.${COLOR_RESET}" - echo . -} - - - -case $KOMMANDO in - "regionsiniteilen") regionsiniteilen "$2" "$3" "$4" ;; - "autoregionsiniteilen") autoregionsiniteilen ;; - "createregionlist") createregionlist ;; - "regionbackup") regionbackup "$2" "$3" ;; - "backup_config") backup_config ;; - "restore_config") restore_config ;; - "autoallclean") autoallclean ;; - "autoregionbackup") autoregionbackup ;; - "datenbanktabellen") datenbanktabellen "$2" "$3" "$4" ;; - "backuptabelle_noassets") backuptabelle_noassets "$2" "$3" "$4" ;; - "asset_backup") asset_backup "$2" "$3" "$4" ;; - "db_restoretabelle_noassets") db_restoretabelle_noassets "$2" "$3" "$4" ;; - "asset_restore") asset_restore "$2" "$3" "$4" ;; - "sichere_wordweb_und_money") sichere_wordweb_und_money "$2" "$3" ;; - "restore_wordweb_und_money") restore_wordweb_und_money "$2" "$3" ;; - *) echo "Unbekanntes Kommando: $KOMMANDO" ;; -esac -# Ende des Skripts +#!/bin/bash + +# Backup Version 1.0 + +STARTVERZEICHNIS="/opt" # Startverzeichnis +ROBUSTVERZEICHNIS="Robust" # Robust Verzeichnis +REGIONSDATEI="osmregionlist.ini" # Regionsdatei +SIMDATEI="osmsimlist.ini" # Simulationsdatei +BACKUPWARTEZEIT=60 # Wartezeit in Sekunden zwischen den Backups +DATUM=$(date '+%Y-%m-%d_%H-%M-%S') # Zeitstempel fuer Backupdateien + +KOMMANDO=$1 + +#────────────────────────────────────────────────────────────────────────────────────────── +#* Informationen +#────────────────────────────────────────────────────────────────────────────────────────── +# + +## * makeverzeichnisliste + # Eine Funktion zum Erstellen einer Liste von Verzeichnissen aus einer Datei. + #? Verwendung: makeverzeichnisliste + # Diese Funktion liest Zeilen aus der angegebenen SIMDATEI im STARTVERZEICHNIS und erstellt eine + # Liste von Verzeichnissen. Die Liste wird in der globalen Variable VERZEICHNISSLISTE gespeichert. + # Die Anzahl der Einträge in der Liste wird in der globalen Variable ANZAHLVERZEICHNISSLISTE gespeichert. + #? Argumente: + # STARTVERZEICHNIS - Das Verzeichnis, in dem sich die SIMDATEI befindet. + # SIMDATEI - Die Datei, aus der die Verzeichnisse gelesen werden sollen. + #? Beispielaufruf + # makeverzeichnisliste +## +function makeverzeichnisliste() { + # Letzte Bearbeitung 27.09.2023 + + # Initialisieren der Verzeichnisliste + VERZEICHNISSLISTE=() + + # Schleife zum Lesen der Zeilen aus der SIMDATEI und Hinzufügen zum Array + while IFS= read -r line; do + VERZEICHNISSLISTE+=("$line") + done >"/$STARTVERZEICHNIS/$INIVERZEICHNIS/bin/Regions/$RTREGIONSNAME.ini" + else + echo error "REGIONSINITEILEN: $INI_FILE wurde nicht gefunden" + fi + return 0 +} + +## * autoregionsiniteilen + # Diese Funktion ruft zuerst die Funktion `makeverzeichnisliste` auf, um eine Liste von Verzeichnissen zu erstellen, + # und iteriert dann über jedes Verzeichnis in der Liste. Für jedes Verzeichnis wird die Regions.ini-Datei in mehrere + # separate INI-Dateien aufgeteilt, eine für jede Region, und die einzelnen Regionsdateien werden umbenannt. Falls die + # Regions.ini-Datei in einem Verzeichnis nicht vorhanden ist, wird sie nicht umbenannt. + #? Parameter: + # - Keine + #? Rückgabewert: + # - 0: Erfolgreiche Ausführung der Funktion + #? Verwendungsbeispiel: + # autoregionsiniteilen +## +function autoregionsiniteilen() { + # Letzte Bearbeitung 01.10.2023 + makeverzeichnisliste + sleep 1 + for ((i = 0; i < "$ANZAHLVERZEICHNISSLISTE"; i++)); do + echo info "Region.ini ${VERZEICHNISSLISTE[$i]} zerlegen" + echo line + VERZEICHNIS="${VERZEICHNISSLISTE[$i]}" + # Regions.ini teilen: + echo "$VERZEICHNIS" # OK geht + INI_FILE="/$STARTVERZEICHNIS/$VERZEICHNIS/bin/Regions/Regions.ini" # Auszulesende Datei + # shellcheck disable=SC2155 + declare -a TARGETS="$(get_regionsarray "${INI_FILE}")" + # shellcheck disable=SC2068 + for MeineRegion in ${TARGETS[@]}; do + regionsiniteilen "$VERZEICHNIS" "$MeineRegion" + sleep 1 + echo rohtext "regionsiniteilen $VERZEICHNIS $MeineRegion" + done + # Dann umbenennen: + # Pruefung ob Datei vorhanden ist, wenn ja umbenennen. + if [ ! -d "$INI_FILE" ]; then + mv /$STARTVERZEICHNIS/"$INIVERZEICHNIS"/bin/Regions/Regions.ini /$STARTVERZEICHNIS/"$INIVERZEICHNIS"/bin/Regions/"$DATUM"-Regions.ini.old + fi + done + return 0 +} + +## * createregionlist + # Diese Funktion erstellt eine Liste von Regionsnamen aus den INI-Dateien in den angegebenen Verzeichnissen und speichert + # sie in der Datei osmregionlist.ini. Zuvor wird die vorhandene osmregionlist.ini-Datei (falls vorhanden) gesichert und in + # osmregionlist.ini.old umbenannt. + #? Parameter: + # - Keine + #? Rückgabewert: + # - 0: Erfolgreiche Ausführung der Funktion + #? Verwendungsbeispiel: + # createregionlist +## +function createregionlist() { + # Letzte Bearbeitung 01.10.2023 + # Alte osmregionlist.ini sichern und in osmregionlist.ini.old umbenennen. + if [ -f "/$STARTVERZEICHNIS/osmregionlist.ini" ]; then + if [ -f "/$STARTVERZEICHNIS/osmregionlist.ini.old" ]; then + rm -r /$STARTVERZEICHNIS/osmregionlist.ini.old + fi + mv /$STARTVERZEICHNIS/osmregionlist.ini /$STARTVERZEICHNIS/osmregionlist.ini.old + fi + # Die mit regionsconfigdateiliste erstellte Datei osmregionlist.ini nach sim Verzeichnis und Regionsnamen in die osmregionlist.ini speichern. + declare -A Dateien # Array erstellen + makeverzeichnisliste + sleep 1 + for ((i = 0; i < "$ANZAHLVERZEICHNISSLISTE"; i++)); do + echo info "Regionnamen ${VERZEICHNISSLISTE[$i]} schreiben" + VERZEICHNIS="${VERZEICHNISSLISTE[$i]}" + # shellcheck disable=SC2178 + Dateien=$(find /$STARTVERZEICHNIS/"$VERZEICHNIS"/bin/Regions/ -name "*.ini") + for i2 in "${Dateien[@]}"; do # Array abarbeiten + echo "$i2" >>osmregionlist.ini + done + done + # Ueberfluessige Zeichen entfernen + LOESCHEN=$(sed s/'\/'$STARTVERZEICHNIS'\/'//g /$STARTVERZEICHNIS/osmregionlist.ini) + echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung /$STARTVERZEICHNIS/ speichern. + LOESCHEN=$(sed s/'\/bin\/Regions\/'/' "'/g /$STARTVERZEICHNIS/osmregionlist.ini) # /bin/Regions/ entfernen. + echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung /bin/Regions/ speichern. + LOESCHEN=$(sed s/'.ini'/'"'/g /$STARTVERZEICHNIS/osmregionlist.ini) # Endung .ini entfernen. + echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung .ini entfernen speichern. + + LOESCHEN=$(sed s/'\"'/''/g /$STARTVERZEICHNIS/osmregionlist.ini) # " entfernen. + echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung " entfernen speichern. + + # Schauen ob da noch Regions.ini bei sind also Regionen mit dem Namen Regions, diese Zeilen loeschen. + LOESCHEN=$(sed '/Regions/d' /$STARTVERZEICHNIS/osmregionlist.ini) # Alle Zeilen mit dem Eintrag Regions entfernen . + echo "$LOESCHEN" >/$STARTVERZEICHNIS/osmregionlist.ini # Aenderung .ini entfernen speichern. + return 0 +} + +## * regionbackup + # Diese Funktion erstellt ein Backup für eine OpenSimulator-Region, indem sie OAR- und Terrain-Daten sowie Konfigurationsdateien speichert. + # Die Region wird in den Offline-Modus versetzt, wenn sie nicht bereits offline ist, bevor das Backup erstellt wird. + #? Parameter: + # 1. BACKUPVERZEICHNISSCREENNAME: Der Name des Bildschirms (Screen) für das Backup. + # 2. REGIONSNAME: Der Name der Region, die gesichert werden soll. + #? Rückgabewert: + # - 0: Erfolgreiche Ausführung der Funktion + #? Verwendungsbeispiel: + # regionbackup "BackupScreen" "MyRegion" +## +function regionbackup() { + # Letzte Bearbeitung 01.10.2023 + # regionbackup "$BACKUPSCREEN" "$BACKUPREGION" + echo "Erstelle Backup von: $BACKUPSCREEN $BACKUPREGION" + + sleep 1 + BACKUPVERZEICHNISSCREENNAME=$1 + REGIONSNAME=$2 + + echo + echo "Backup $BACKUPVERZEICHNISSCREENNAME der Region $REGIONSNAME" + cd /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin || return 1 # Test ob Verzeichnis vorhanden. + mkdir -p /$STARTVERZEICHNIS/backup # Backup Verzeichnis anlegen falls nicht vorhanden. + echo "Ich kann nicht pruefen ob die Region im OpenSimulator vorhanden ist." + echo "Sollte sie nicht vorhanden sein wird root also alle Regionen gespeichert" + # Ist die Region Online oder Offline? + if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini.offline ]; then + echo "$REGIONSNAME ist heruntergefahren." + else + screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'change region ${REGIONSNAME//\"/}'^M" + echo "$BACKUPVERZEICHNISSCREENNAME $REGIONSNAME" + screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'save oar /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.oar'^M" + echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.oar" + + # Neu xml backup + screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'save xml2 /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.xml2'^M" + echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.xml2" + # Neu xml backup ende + + screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'terrain save /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.png'^M" + echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.png" + screen -S "$BACKUPVERZEICHNISSCREENNAME" -p 0 -X eval "stuff 'terrain save /$STARTVERZEICHNIS/backup/'$DATUM'-$REGIONSNAME.raw'^M" + echo "$BACKUPVERZEICHNISSCREENNAME $DATUM-$REGIONSNAME.raw" + echo "$BACKUPVERZEICHNISSCREENNAME Region $DATUM-$REGIONSNAME RAW und PNG Terrain werden gespeichert" + fi + + sleep 10 + if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini.offline ]; then + cp /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini.offline /$STARTVERZEICHNIS/backup/"$DATUM"-"$REGIONSNAME".ini.offline + echo "$BACKUPVERZEICHNISSCREENNAME Die Regions $DATUM-$REGIONSNAME.ini.offline wird gespeichert" + fi + if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini ]; then + cp /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"$REGIONSNAME".ini /$STARTVERZEICHNIS/backup/"$DATUM"-"$REGIONSNAME".ini + echo "$BACKUPVERZEICHNISSCREENNAME Die Regions $DATUM-$REGIONSNAME.ini wird gespeichert" + fi + if [ -f /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"${REGIONSNAME//\"/}" ]; then + cp /$STARTVERZEICHNIS/"$BACKUPVERZEICHNISSCREENNAME"/bin/Regions/"${REGIONSNAME//\"/}" /$STARTVERZEICHNIS/backup/"$DATUM"-"$REGIONSNAME".ini + echo "$BACKUPVERZEICHNISSCREENNAME Die Regions $DATUM-$REGIONSNAME.ini wird gespeichert" + fi + + echo "Backup der Region $REGIONSNAME wird fertiggestellt." + return 0 +} + + +## * autoallclean. + # loescht Log, dll, so, exe, aot Dateien fuer einen saubere neue installation, mit Robust. + # Hierbei werden keine Datenbanken oder Konfigurationen geloescht aber opensim ist anschliessend nicht mehr startbereit. + # Um opensim wieder Funktionsbereit zu machen muss ein Upgrade oder ein oscopy vorgang ausgefuehrt werden. + #? @param keine. + #? @return nichts wird zurueckgegeben. + # todo: nichts. +## +function autoallclean() { + # Letzte Bearbeitung 01.10.2023 + makeverzeichnisliste + sleep 1 + for ((i = 0; i < "$ANZAHLVERZEICHNISSLISTE"; i++)); do + # Dateien + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.log + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.dll + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.exe + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.so + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.xml + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.dylib + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.example + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.sample + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.txt + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.config + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.py + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.old + rm /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/*.pdb + + # Verzeichnisse leeren + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/assetcache/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/maptiles/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/MeshCache/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/j2kDecodeCache/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/ScriptEngines/* + + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addin-db-002/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addon-modules/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/assets/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/bakes/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/data/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Estates/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/inventory/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib32/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib64/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Library/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/openmetaverse_data/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/robust-include/* + + echo "autoallclean: ${VERZEICHNISSLISTE[$i]} geloescht" + sleep 1 + done + # nochmal das gleiche mit Robust + echo "autoallclean: $ROBUSTVERZEICHNIS geloescht" + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.log + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.dll + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.exe + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.so + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.xml + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.dylib + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.example + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.sample + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.txt + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.config + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.py + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.old + rm /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/*.pdb + + rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/assetcache/* + rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/maptiles/* + rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/MeshCache/* + rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/j2kDecodeCache/* + rm -r /$STARTVERZEICHNIS/$ROBUSTVERZEICHNIS/bin/ScriptEngines/* + + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addin-db-002/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/addon-modules/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/assets/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/bakes/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/data/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Estates/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/inventory/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib32/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/lib64/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/Library/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/openmetaverse_data/* + rm -r /$STARTVERZEICHNIS/"${VERZEICHNISSLISTE[$i]}"/bin/robust-include/* + + return 0 +} + +## * autoregionbackup + # Diese Funktion durchläuft die Regionen in Ihrem OpenSimulator-Grid und erstellt automatische Backups. + #? Parameter: + # Keine Parameter erforderlich. + #? Rückgabewert: + # - Kein expliziter Rückgabewert + #? Verwendungsbeispiel: + # autoregionbackup + # todo: Uebergabe Parameter Fehler. Bug Modus mit extra ausgaben. Ist keine osmregionlist.ini vorhanden muss sie erstellt werden. +## +function autoregionbackup() { + # Letzte Bearbeitung 01.10.2023 + echo "Automatisches Backup wird gestartet." + + # Ist die osmregionlist.ini vorhanden? + if [ ! -f "/$STARTVERZEICHNIS/osmregionlist.ini" ]; then + echo "Die osmregionlist.ini Datei ist noch nicht vorhanden und wird erstellt." + createregionlist + else + echo "Die osmregionlist.ini Datei ist bereits vorhanden." + fi + + makeregionsliste + sleep 1 + for ((i = 0; i < "$ANZAHLREGIONSLISTE"; i++)); do + BACKUPSCREEN=$(echo "${REGIONSLISTE[$i]}" | cut -d ' ' -f 1) + BACKUPREGION=$(echo "${REGIONSLISTE[$i]}" | cut -d ' ' -f 2) + echo "Starte Backup von: $BACKUPSCREEN $BACKUPREGION" # Testausgabe + regionbackup "$BACKUPSCREEN" "$BACKUPREGION" + if [ -f /$STARTVERZEICHNIS/"$BACKUPSCREEN"/bin/Regions/"$BACKUPREGION".ini.offline ]; then + echo "$BACKUPREGION Region ist Offline und wird uebersprungen." + else + sleep $BACKUPWARTEZEIT + echo "BACKUPWARTEZEIT $BACKUPWARTEZEIT Sekunden." # Testausgabe + fi + done + return 0 +} + +# Zähle die Tabellen in der Datenbank und die Asset-Typen in der Tabelle 'assets'. +# bash osmtool_backup.sh datenbanktabellen "mein_benutzer" "geheim123" "meine_datenbank" +function datenbanktabellen() { + username=$1 + password=$2 + databasename=$3 + logfile="/$STARTVERZEICHNIS/backup/${databasename}/status_report.txt" + + mkdir -p "/$STARTVERZEICHNIS/backup/${databasename}" || exit + + echo "📊 Statusbericht für Datenbank: $databasename" | tee "$logfile" + echo "📅 Datum: $(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$logfile" + + # Tabellen zählen + tabellenanzahl=$(mysql -u"$username" -p"$password" -D"$databasename" -e "SHOW TABLES;" | tail -n +2 | wc -l) + echo "📦 Tabellen gefunden: $tabellenanzahl" | tee -a "$logfile" + + # Asset-Typen zählen (wenn Tabelle vorhanden) + if mysql -u"$username" -p"$password" -D"$databasename" -e "SHOW TABLES LIKE 'assets';" | grep -q "assets"; then + assettypen_anzahl=$(mysql -u"$username" -p"$password" -D"$databasename" -e "SELECT COUNT(DISTINCT assetType) FROM assets;" | tail -n 1) + echo "🎨 Asset-Typen in 'assets': $assettypen_anzahl" | tee -a "$logfile" + else + echo "⚠️ Tabelle 'assets' nicht gefunden." | tee -a "$logfile" + fi + + echo "✅ Bericht gespeichert unter: $logfile" +} + + +# beispiel: screen -fa -S BACKUPNOASSETS -d -U -m bash osmtool.sh backuptabelle_noassets "mein_benutzer" "geheim123" "meine_datenbank" +function backuptabelle_noassets() { + username=$1 + password=$2 + databasename=$3 + + mkdir -p /$STARTVERZEICHNIS/backup/"$databasename" || exit + logfile="/$STARTVERZEICHNIS/backup/${databasename}/backup_log.txt" + + # Tabellennamen holen und speichern + mysql -u"$username" -p"$password" -D"$databasename" -e "SHOW TABLES;" | tail -n +2 > /$STARTVERZEICHNIS/backup/"$databasename"/liste.txt + + # Anzahl der Tabellen zählen + tabellenanzahl=$(wc -l < /$STARTVERZEICHNIS/backup/"$databasename"/liste.txt) + echo "📦 Tabellen gefunden: $tabellenanzahl" | tee -a "$logfile" + + # Tabellen sichern (außer 'assets') + gesichert=0 + while IFS= read -r tabellenname; do + sleep 1 + if [[ "$tabellenname" != "assets" ]]; then + mysqldump -u"$username" -p"$password" "$databasename" "$tabellenname" | zip > /$STARTVERZEICHNIS/backup/"$databasename"/"$tabellenname".sql.zip + echo "✅ Gesichert: $tabellenname" | tee -a "$logfile" + ((gesichert++)) + fi + done < /$STARTVERZEICHNIS/backup/"$databasename"/liste.txt + + echo "🔒 Tabellen gesichert (ohne 'assets'): $gesichert" | tee -a "$logfile" + return 0 +} + +# screen -fa -S ASSETBACKUP -d -U -m bash osmtool.sh asset_backup "mein_benutzer" "geheim123" "meine_datenbank" +function asset_backup() { + username=$1 + password=$2 + databasename=$3 + fromtable="assets" + fromtypes="assetType" + + mkdir -p /$STARTVERZEICHNIS/backup/"$databasename"/assets || exit + cd /$STARTVERZEICHNIS/backup/"$databasename"/assets || exit + logfile="./asset_backup_log.txt" + + # Assettypen holen + mysql -u"$username" -p"$password" -D"$databasename" -e "SELECT DISTINCT $fromtypes FROM $fromtable;" | tail -n +2 > typen.txt + assettypen_anzahl=$(wc -l < typen.txt) + echo "📦 Assettypen gefunden: $assettypen_anzahl" | tee -a "$logfile" + + gesichert=0 + while IFS= read -r assettype; do + filename="assetType_${assettype}" + echo "✅ Sichere Asset-Typ: $assettype → $filename.sql.zip" | tee -a "$logfile" + mysqldump -u"$username" -p"$password" "$databasename" --tables "$fromtable" --where="$fromtypes = '$assettype'" | zip > "$filename.sql.zip" + ((gesichert++)) + done < typen.txt + + echo "🔒 Assettypen gesichert: $gesichert" | tee -a "$logfile" +} + +Unterschiedliche assettypen der Tabelle assets zählen + +# screen -fa -S DBRESTORE -d -U -m bash osmtool.sh db_restoretabelle_noassets "mein_benutzer" "geheim123" "meine_datenbank" +function db_restoretabelle_noassets() { + username=$1 + password=$2 + databasename=$3 + restorepath="/$STARTVERZEICHNIS/backup/${databasename}" + logfile="${restorepath}/restore_log.txt" + + cd "$restorepath" || exit + + if [[ ! -f liste.txt ]]; then + echo "❌ Keine 'liste.txt' gefunden. Backup-Datei fehlt oder ungültig." | tee -a "$logfile" + return 1 + fi + + echo "📦 Starte Wiederherstellung aus: $restorepath" | tee -a "$logfile" + + restored=0 + total=$(grep -cv "^assets$" liste.txt) + echo "🔍 Tabellen zur Wiederherstellung (ohne 'assets'): $total" | tee -a "$logfile" + + while IFS= read -r tabellenname; do + if [[ "$tabellenname" != "assets" ]]; then + zipfile="${tabellenname}.sql.zip" + if [[ -f "$zipfile" ]]; then + echo "🔄 Wiederherstellung: $tabellenname" | tee -a "$logfile" + unzip -p "$zipfile" | mysql -u"$username" -p"$password" "$databasename" + ((restored++)) + else + echo "⚠️ Datei fehlt: $zipfile" | tee -a "$logfile" + fi + fi + done < liste.txt + + echo "✅ Tabellen erfolgreich wiederhergestellt: $restored von $total" | tee -a "$logfile" + return 0 +} + +# Wiederherstellung der Asset-Typen +function asset_restore() { + username=$1 + password=$2 + databasename=$3 + restorepath="/$STARTVERZEICHNIS/backup/${databasename}/assets" + logfile="${restorepath}/asset_restore_log.txt" + + cd "$restorepath" || exit + + zipfiles=(assetType_*.sql.zip) + anzahl=${#zipfiles[@]} + echo "📦 Asset-Backups gefunden: $anzahl" | tee -a "$logfile" + + restored=0 + for zipfile in "${zipfiles[@]}"; do + echo "🔄 Wiederherstellung: $zipfile" | tee -a "$logfile" + unzip -p "$zipfile" | mysql -u"$username" -p"$password" "$databasename" + ((restored++)) + done + + echo "✅ Assettypen wiederhergestellt: $restored" | tee -a "$logfile" +} + +# Sichere die Datenbanken 'wordweb' und 'money' in ZIP-Dateien. +# bash osmtool_backup.sh sichere_wordweb_und_money "mein_benutzer" "geheim123" + +function sichere_wordweb_und_money() { + username=$1 + password=$2 + logfile="/$STARTVERZEICHNIS/backup/db_sicherung_log.txt" + datum=$(date '+%Y-%m-%d_%H-%M-%S') + + mkdir -p /$STARTVERZEICHNIS/backup/wordweb + mkdir -p /$STARTVERZEICHNIS/backup/money + + echo "📅 Sicherung gestartet: $datum" | tee -a "$logfile" + + # WORDWEB sichern + echo "💾 Sichere Datenbank: wordweb" | tee -a "$logfile" + mysqldump -u"$username" -p"$password" wordweb | zip > "/$STARTVERZEICHNIS/backup/wordweb/wordweb_${datum}.sql.zip" + size_wordweb=$(du -sh "/$STARTVERZEICHNIS/backup/wordweb/wordweb_${datum}.sql.zip" | cut -f1) + echo "✅ wordweb gesichert → Größe: $size_wordweb" | tee -a "$logfile" + + # MONEY sichern + echo "💾 Sichere Datenbank: money" | tee -a "$logfile" + mysqldump -u"$username" -p"$password" money | zip > "/$STARTVERZEICHNIS/backup/money/money_${datum}.sql.zip" + size_money=$(du -sh "/$STARTVERZEICHNIS/backup/money/money_${datum}.sql.zip" | cut -f1) + echo "✅ money gesichert → Größe: $size_money" | tee -a "$logfile" + + echo "📦 Sicherung abgeschlossen: $(date '+%Y-%m-%d %H:%M:%S')" | tee -a "$logfile" +} + +function restore_wordweb_und_money() { + username=$1 + password=$2 + for dbname in wordweb money; do + restorepath="/$STARTVERZEICHNIS/backup/${dbname}" + latestfile=$(find "$restorepath" -maxdepth 1 -type f -name "*.sql.zip" -printf '%T@ %p\n' | sort -nr | head -n 1 | cut -d' ' -f2-) + if [[ -f "$latestfile" ]]; then + echo "🔄 Wiederherstellung: $dbname aus $latestfile" + unzip -p "$latestfile" | mysql -u"$username" -p"$password" "$dbname" + else + echo "⚠️ Keine Backup-Datei gefunden für $dbname" + fi + done +} + +# Backup-Konfigurationsdateien aus robust/bin und sim-Verzeichnissen +# bash osmtool_backup.sh backup_config +function backup_config() { + echo "${SYM_WAIT} ${COLOR_START}Sichere Konfigurationsdateien...${COLOR_RESET}" + + # Zielverzeichnis für Backups + backup_root="/opt/backup/config" + + # Backup aus robust/bin + if [[ -d "robust/bin" ]]; then + src_dir="robust/bin" + dest_dir="${backup_root}/${src_dir}" + echo "${SYM_OK} ${COLOR_START}Sichere ${COLOR_DIR}${src_dir}${COLOR_RESET} nach ${COLOR_DIR}${dest_dir}${COLOR_RESET}" + find "$src_dir" -type f -name "*.ini" | while read -r file; do + rel_path="${file#"$src_dir"/}" # relativer Pfad + mkdir -p "${dest_dir}/$(dirname "$rel_path")" + cp "$file" "${dest_dir}/$rel_path" + done + else + echo "${SYM_BAD} ${COLOR_DIR}robust/bin${COLOR_RESET} nicht gefunden. Überspringe." + fi + + # Backup aus sim-Verzeichnissen + for ((i=1; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" ]]; then + dest_dir="${backup_root}/${sim_dir}" + echo "${SYM_OK} ${COLOR_START}Sichere ${COLOR_DIR}${sim_dir}${COLOR_RESET} nach ${COLOR_DIR}${dest_dir}${COLOR_RESET}" + find "$sim_dir" -type f -name "*.ini" | while read -r file; do + rel_path="${file#"$sim_dir"/}" + mkdir -p "${dest_dir}/$(dirname "$rel_path")" + cp "$file" "${dest_dir}/$rel_path" + done + fi + done + + echo "${SYM_OK} ${COLOR_START}Backup abgeschlossen.${COLOR_RESET}" + echo . +} + +# Restore-Konfigurationsdateien aus dem backup Verzeichnis nach robust/bin und sim-Verzeichnissen +# bash osmtool_backup.sh restore_config +function restore_config() { + echo "${SYM_WAIT} ${COLOR_START}Stelle Konfigurationsdateien aus Backup wieder her...${COLOR_RESET}" + + # Quellverzeichnis für Backups + backup_root="/opt/backup/config" + + # Restore für robust/bin + src_dir="${backup_root}/robust/bin" + dest_dir="robust/bin" + if [[ -d "$src_dir" ]]; then + echo "${SYM_OK} ${COLOR_START}Stelle ${COLOR_DIR}${dest_dir}${COLOR_RESET} aus ${COLOR_DIR}${src_dir}${COLOR_RESET} wieder her" + find "$src_dir" -type f -name "*.ini" | while read -r file; do + rel_path="${file#"$src_dir"/}" + mkdir -p "${dest_dir}/$(dirname "$rel_path")" + cp "$file" "${dest_dir}/$rel_path" + done + else + echo "${SYM_BAD} ${COLOR_DIR}${src_dir}${COLOR_RESET} nicht gefunden. Überspringe." + fi + + # Restore für sim-Verzeichnisse + for ((i=1; i<=999; i++)); do + src_dir="${backup_root}/sim$i/bin" + dest_dir="sim$i/bin" + if [[ -d "$src_dir" ]]; then + echo "${SYM_OK} ${COLOR_START}Stelle ${COLOR_DIR}${dest_dir}${COLOR_RESET} aus ${COLOR_DIR}${src_dir}${COLOR_RESET} wieder her" + find "$src_dir" -type f -name "*.ini" | while read -r file; do + rel_path="${file#"$src_dir"/}" + mkdir -p "${dest_dir}/$(dirname "$rel_path")" + cp "$file" "${dest_dir}/$rel_path" + done + fi + done + + echo "${SYM_OK} ${COLOR_START}Wiederherstellung abgeschlossen.${COLOR_RESET}" + echo . +} + + + +case $KOMMANDO in + "regionsiniteilen") regionsiniteilen "$2" "$3" "$4" ;; + "autoregionsiniteilen") autoregionsiniteilen ;; + "createregionlist") createregionlist ;; + "regionbackup") regionbackup "$2" "$3" ;; + "backup_config") backup_config ;; + "restore_config") restore_config ;; + "autoallclean") autoallclean ;; + "autoregionbackup") autoregionbackup ;; + "datenbanktabellen") datenbanktabellen "$2" "$3" "$4" ;; + "backuptabelle_noassets") backuptabelle_noassets "$2" "$3" "$4" ;; + "asset_backup") asset_backup "$2" "$3" "$4" ;; + "db_restoretabelle_noassets") db_restoretabelle_noassets "$2" "$3" "$4" ;; + "asset_restore") asset_restore "$2" "$3" "$4" ;; + "sichere_wordweb_und_money") sichere_wordweb_und_money "$2" "$3" ;; + "restore_wordweb_und_money") restore_wordweb_und_money "$2" "$3" ;; + *) echo "Unbekanntes Kommando: $KOMMANDO" ;; +esac +# Ende des Skripts exit 0 \ No newline at end of file diff --git a/osmtool_main.sh b/osmtool_main.sh index 52150cd..7a6b6a1 100644 --- a/osmtool_main.sh +++ b/osmtool_main.sh @@ -1,430 +1,430 @@ -#!/usr/bin/env bash -set -euo pipefail - -BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -MOD_DIR="$BASE_DIR/modular" - -# shellcheck source=/dev/null -source "$MOD_DIR/osmtool_core.sh" -init_i18n - -usage() { - cat <<'EOF' -Usage: - osmtool_main.sh [--mode ] [--lang ] [--profile ] --module [module-options] - osmtool_main.sh server_install - osmtool_main.sh - -Examples: - osmtool_main.sh install-grid-sim - osmtool_main.sh server_install - osmtool_main.sh opensimstart - osmtool_main.sh opensimrestart - osmtool_main.sh croninstall - osmtool_main.sh dbbackup - osmtool_main.sh --module install --action prepare-ubuntu - osmtool_main.sh --module startstop --target grid --action restart --workdir /opt - osmtool_main.sh --module cleanup --action log-clean --workdir /opt - osmtool_main.sh --module health --action run --workdir /opt - osmtool_main.sh --module backup --action db-backup --db-user root --db-pass secret --db-name opensim - osmtool_main.sh --module update --action create-rollback --workdir /opt - osmtool_main.sh --module config --action validate-runtime --workdir /opt - osmtool_main.sh --module report --action generate --workdir /opt - osmtool_main.sh --module smoke --action run --profile grid-sim --workdir /opt - osmtool_main.sh --module cron --action list - osmtool_main.sh --mode ui -EOF - print_usage_common -} - -dispatch_module() { - local module="$1" - shift - - case "$module" in - install) - bash "$MOD_DIR/osmtool_install.sh" --profile "$PROFILE" "$@" - ;; - startstop) - bash "$MOD_DIR/osmtool_startstop.sh" --profile "$PROFILE" "$@" - ;; - cleanup) - bash "$MOD_DIR/osmtool_cleanup.sh" --profile "$PROFILE" "$@" - ;; - health) - bash "$MOD_DIR/osmtool_health.sh" --profile "$PROFILE" "$@" - ;; - backup) - bash "$MOD_DIR/osmtool_data.sh" --profile "$PROFILE" "$@" - ;; - update) - bash "$MOD_DIR/osmtool_update.sh" --profile "$PROFILE" "$@" - ;; - config) - bash "$MOD_DIR/osmtool_config.sh" --profile "$PROFILE" "$@" - ;; - report) - bash "$MOD_DIR/osmtool_report.sh" --profile "$PROFILE" "$@" - ;; - smoke) - bash "$MOD_DIR/osmtool_smoke.sh" --profile "$PROFILE" "$@" - ;; - cron) - bash "$MOD_DIR/osmtool_cron.sh" --profile "$PROFILE" "$@" - ;; - restore) - bash "$MOD_DIR/osmtool_restore.sh" --profile "$PROFILE" "$@" - ;; - *) - die "$(msg ERR_UNKNOWN_MODULE): $module" - ;; - esac -} - -default_target_for_profile() { - case "$1" in - grid-sim) echo "grid" ;; - robust) echo "robust" ;; - standalone) echo "standalone" ;; - esac -} - -args_have_target() { - local prev="" - local token - for token in "$@"; do - if [[ "$prev" == "--target" ]]; then - return 0 - fi - prev="$token" - done - return 1 -} - -ui_flow() { - local module action target - - PROFILE="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_PROFILE)" \ - "grid-sim" "$(msg PROFILE_GRID_SIM)" \ - "robust" "$(msg PROFILE_ROBUST)" \ - "standalone" "$(msg PROFILE_STANDALONE)")" - validate_profile "$PROFILE" - - module="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_MODULE)" \ - "install" "$(msg MENU_INSTALL)" \ - "startstop" "$(msg MENU_STARTSTOP)" \ - "cleanup" "$(msg MENU_CLEANUP)" \ - "health" "$(msg MENU_HEALTH)" \ - "backup" "$(msg MENU_BACKUP)" \ - "restore" "$(msg MENU_RESTORE)" \ - "update" "$(msg MENU_UPDATE)" \ - "config" "$(msg MENU_CONFIG)" \ - "report" "$(msg MENU_REPORT)" \ - "smoke" "$(msg MENU_SMOKE)" \ - "cron" "$(msg MENU_CRON)")" - - case "$module" in - install) - action="$(show_menu "$(msg MENU_INSTALL)" "$(msg MENU_CHOOSE_ACTION)" \ - "server-check" "server-check" \ - "prepare-ubuntu" "prepare-ubuntu" \ - "install-opensim-deps" "install-opensim-deps" \ - "install-dotnet8" "install-dotnet8" \ - "install-opensim" "install-opensim" \ - "configure-opensim" "configure-opensim" \ - "configure-database" "configure-database" \ - "compile-janus" "compile-janus" \ - "configure-janus" "configure-janus" \ - "install-janus" "install-janus")" - dispatch_module install --action "$action" - ;; - startstop) - if [[ "$PROFILE" == "grid-sim" ]]; then - target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \ - "grid" "$(msg TARGET_GRID)" \ - "robust" "$(msg TARGET_ROBUST)" \ - "sim1" "$(msg TARGET_SIM1)" \ - "janus" "$(msg TARGET_JANUS)")" - elif [[ "$PROFILE" == "robust" ]]; then - target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \ - "robust" "$(msg TARGET_ROBUST)" \ - "janus" "$(msg TARGET_JANUS)")" - else - target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \ - "standalone" "$(msg TARGET_STANDALONE)" \ - "janus" "$(msg TARGET_JANUS)")" - fi - - action="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_ACTION)" \ - "start" "$(msg ACTION_START)" \ - "stop" "$(msg ACTION_STOP)" \ - "restart" "$(msg ACTION_RESTART)")" - dispatch_module startstop --target "$target" --action "$action" - ;; - cleanup) - action="$(show_menu "$(msg MENU_CLEANUP)" "$(msg MENU_CHOOSE_ACTION)" \ - "cache-clean" "$(msg ACTION_CACHE_CLEAN)" \ - "log-clean" "$(msg ACTION_LOG_CLEAN)" \ - "tmp-clean" "$(msg ACTION_TMP_CLEAN)" \ - "reboot" "$(msg ACTION_REBOOT)")" - dispatch_module cleanup --action "$action" - ;; - health) - action="$(show_menu "$(msg MENU_HEALTH)" "$(msg MENU_CHOOSE_ACTION)" \ - "run" "$(msg ACTION_HEALTH_RUN)")" - dispatch_module health --action "$action" - ;; - backup) - action="$(show_menu "$(msg MENU_BACKUP)" "$(msg MENU_CHOOSE_ACTION)" \ - "db-backup" "$(msg ACTION_DB_BACKUP)" \ - "oar-backup" "$(msg ACTION_OAR_BACKUP)" \ - "full-backup" "$(msg ACTION_FULL_BACKUP)")" - dispatch_module backup --action "$action" - ;; - restore) - action="$(show_menu "$(msg MENU_RESTORE)" "$(msg MENU_CHOOSE_ACTION)" \ - "list-backups" "$(msg ACTION_RESTORE_LIST)" \ - "db-restore" "$(msg ACTION_RESTORE_DB)" \ - "oar-restore" "$(msg ACTION_RESTORE_OAR)" \ - "full-restore" "$(msg ACTION_RESTORE_FULL)")" - dispatch_module restore --action "$action" - ;; - update) - action="$(show_menu "$(msg MENU_UPDATE)" "$(msg MENU_CHOOSE_ACTION)" \ - "create-rollback" "$(msg ACTION_UPDATE_ROLLBACK)" \ - "list-rollbacks" "$(msg ACTION_UPDATE_LIST)" \ - "update-opensim" "$(msg ACTION_UPDATE_OPENSIM)" \ - "update-janus" "$(msg ACTION_UPDATE_JANUS)" \ - "full-update" "$(msg ACTION_UPDATE_FULL)")" - dispatch_module update --action "$action" - ;; - config) - action="$(show_menu "$(msg MENU_CONFIG)" "$(msg MENU_CHOOSE_ACTION)" \ - "validate-file" "$(msg ACTION_CONFIG_FILE)" \ - "validate-runtime" "$(msg ACTION_CONFIG_RUNTIME)")" - dispatch_module config --action "$action" - ;; - report) - action="$(show_menu "$(msg MENU_REPORT)" "$(msg MENU_CHOOSE_ACTION)" \ - "generate" "$(msg ACTION_REPORT_GENERATE)")" - dispatch_module report --action "$action" - ;; - smoke) - action="$(show_menu "$(msg MENU_SMOKE)" "$(msg MENU_CHOOSE_ACTION)" \ - "run" "$(msg ACTION_SMOKE_RUN)")" - dispatch_module smoke --action "$action" - ;; - cron) - action="$(show_menu "$(msg MENU_CRON)" "$(msg MENU_CHOOSE_ACTION)" \ - "install" "$(msg ACTION_CRON_INSTALL)" \ - "list" "$(msg ACTION_CRON_LIST)" \ - "remove" "$(msg ACTION_CRON_REMOVE)")" - dispatch_module cron --action "$action" - ;; - *) - die "$(msg ERR_UNKNOWN_UI_MODULE): $module" - ;; - esac -} - -MODE="cli" -MODULE="" -LANG_OVERRIDE="${OSM_LANG:-$APP_LANG}" -PROFILE="grid-sim" - -if [[ $# -eq 0 ]]; then - MODE="ui" - ui_flow - exit 0 -fi - -if [[ "${1:-}" == "h" || "${1:-}" == "help" ]]; then - usage - exit 0 -fi - -if [[ "${1:-}" == "server_install" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - - log INFO "Running server_install shortcut (prepare-ubuntu -> install-opensim-deps -> install-dotnet8 -> server-check -> install-opensim -> configure-opensim)" - dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "configinit" ]]; then - set_language "$LANG_OVERRIDE" - dispatch_module config --action init-config --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "install-grid-sim" ]]; then - PROFILE="grid-sim" - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - - # Pflichtparameter: Datenbank-Credentials und Anzahl Simulatoren - _db_user="${OSM_DB_USER:-}" - _db_pass="${OSM_DB_PASS:-}" - _sim_count="${OSM_SIM_COUNT:-1}" - _hostname="${OSM_HOST:-}" - _gridname="${OSM_GRIDNAME:-}" - - if [[ -z "$_db_user" || -z "$_db_pass" ]]; then - log ERROR "Datenbankzugangsdaten fehlen. Vor dem Aufruf setzen:" - log ERROR " export OSM_DB_USER=opensim" - log ERROR " export OSM_DB_PASS='MeinSicheresPasswort'" - log ERROR " export OSM_SIM_COUNT=3 # Anzahl sim-Instanzen" - log ERROR " export OSM_HOST=1.2.3.4 # Öffentliche IP oder Hostname" - log ERROR " export OSM_GRIDNAME='Mein Grid'" - exit 1 - fi - - log INFO "Starte install-grid-sim (prepare-ubuntu → deps → dotnet8 → server-check → install-opensim → configure-database → configure-opensim)" - - dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR" - dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR" - # Datenbanken vor configure-opensim anlegen (ConnectionStrings werden danach geschrieben) - dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" \ - --db-user "$_db_user" --db-pass "$_db_pass" --sim-count "$_sim_count" - # Ini-Dateien mit Credentials, Hostname und Gridname befüllen - dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR" \ - --db-user "$_db_user" --db-pass "$_db_pass" \ - ${_hostname:+--public-host "$_hostname"} \ - ${_gridname:+--gridname "$_gridname"} - exit 0 -fi - -if [[ "${1:-}" == "opensimstart" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action start --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "opensimstop" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action stop --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "opensimrestart" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action restart --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "healthcheck" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module health --action run --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "smoketest" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module smoke --action run --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "dailyreport" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module report --action generate --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "croninstall" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module cron --action install --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "cronlist" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module cron --action list --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "janusinstall" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module install --action install-janus --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "janusrestart" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - dispatch_module startstop --target janus --action restart --workdir "$DEFAULT_WORKDIR" - exit 0 -fi - -if [[ "${1:-}" == "dbsetup" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - - DB_USER_SHORT="${OSM_DB_USER:-opensim}" - DB_PASS_SHORT="${OSM_DB_PASS:-}" - DB_ROOT_USER_SHORT="${OSM_DB_ROOT_USER:-root}" - DB_ROOT_PASS_SHORT="${OSM_DB_ROOT_PASS:-}" - - [[ -n "$DB_PASS_SHORT" ]] || die "dbsetup requires OSM_DB_PASS environment variable" - - dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-root-user "$DB_ROOT_USER_SHORT" --db-root-pass "$DB_ROOT_PASS_SHORT" - exit 0 -fi - -if [[ "${1:-}" == "dbbackup" ]]; then - set_language "$LANG_OVERRIDE" - validate_profile "$PROFILE" - - DB_USER_SHORT="${OSM_DB_USER:-root}" - DB_PASS_SHORT="${OSM_DB_PASS:-}" - DB_NAME_SHORT="${OSM_DB_NAME:-opensim}" - - [[ -n "$DB_PASS_SHORT" ]] || die "dbbackup requires OSM_DB_PASS environment variable" - - dispatch_module backup --action db-backup --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-name "$DB_NAME_SHORT" - exit 0 -fi - -while [[ $# -gt 0 ]]; do - case "$1" in - --mode) MODE="$2"; shift 2 ;; - --lang) LANG_OVERRIDE="$2"; shift 2 ;; - --profile) PROFILE="$2"; shift 2 ;; - --module) MODULE="$2"; shift 2 ;; - --help|-h) usage; exit 0 ;; - *) break ;; - esac -done - -set_language "$LANG_OVERRIDE" -validate_profile "$PROFILE" - -if [[ "$MODE" == "ui" ]]; then - ui_flow - exit 0 -fi - -[[ -n "$MODULE" ]] || die "$(msg ERR_MISSING_MODULE)" - -if [[ "$MODULE" == "startstop" ]] && ! args_have_target "$@"; then - dispatch_module "$MODULE" --target "$(default_target_for_profile "$PROFILE")" "$@" -else - dispatch_module "$MODULE" "$@" -fi +#!/usr/bin/env bash +set -euo pipefail + +BASE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +MOD_DIR="$BASE_DIR/modular" + +# shellcheck source=/dev/null +source "$MOD_DIR/osmtool_core.sh" +init_i18n + +usage() { + cat <<'EOF' +Usage: + osmtool_main.sh [--mode ] [--lang ] [--profile ] --module [module-options] + osmtool_main.sh server_install + osmtool_main.sh + +Examples: + osmtool_main.sh install-grid-sim + osmtool_main.sh server_install + osmtool_main.sh opensimstart + osmtool_main.sh opensimrestart + osmtool_main.sh croninstall + osmtool_main.sh dbbackup + osmtool_main.sh --module install --action prepare-ubuntu + osmtool_main.sh --module startstop --target grid --action restart --workdir /opt + osmtool_main.sh --module cleanup --action log-clean --workdir /opt + osmtool_main.sh --module health --action run --workdir /opt + osmtool_main.sh --module backup --action db-backup --db-user root --db-pass secret --db-name opensim + osmtool_main.sh --module update --action create-rollback --workdir /opt + osmtool_main.sh --module config --action validate-runtime --workdir /opt + osmtool_main.sh --module report --action generate --workdir /opt + osmtool_main.sh --module smoke --action run --profile grid-sim --workdir /opt + osmtool_main.sh --module cron --action list + osmtool_main.sh --mode ui +EOF + print_usage_common +} + +dispatch_module() { + local module="$1" + shift + + case "$module" in + install) + bash "$MOD_DIR/osmtool_install.sh" --profile "$PROFILE" "$@" + ;; + startstop) + bash "$MOD_DIR/osmtool_startstop.sh" --profile "$PROFILE" "$@" + ;; + cleanup) + bash "$MOD_DIR/osmtool_cleanup.sh" --profile "$PROFILE" "$@" + ;; + health) + bash "$MOD_DIR/osmtool_health.sh" --profile "$PROFILE" "$@" + ;; + backup) + bash "$MOD_DIR/osmtool_data.sh" --profile "$PROFILE" "$@" + ;; + update) + bash "$MOD_DIR/osmtool_update.sh" --profile "$PROFILE" "$@" + ;; + config) + bash "$MOD_DIR/osmtool_config.sh" --profile "$PROFILE" "$@" + ;; + report) + bash "$MOD_DIR/osmtool_report.sh" --profile "$PROFILE" "$@" + ;; + smoke) + bash "$MOD_DIR/osmtool_smoke.sh" --profile "$PROFILE" "$@" + ;; + cron) + bash "$MOD_DIR/osmtool_cron.sh" --profile "$PROFILE" "$@" + ;; + restore) + bash "$MOD_DIR/osmtool_restore.sh" --profile "$PROFILE" "$@" + ;; + *) + die "$(msg ERR_UNKNOWN_MODULE): $module" + ;; + esac +} + +default_target_for_profile() { + case "$1" in + grid-sim) echo "grid" ;; + robust) echo "robust" ;; + standalone) echo "standalone" ;; + esac +} + +args_have_target() { + local prev="" + local token + for token in "$@"; do + if [[ "$prev" == "--target" ]]; then + return 0 + fi + prev="$token" + done + return 1 +} + +ui_flow() { + local module action target + + PROFILE="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_PROFILE)" \ + "grid-sim" "$(msg PROFILE_GRID_SIM)" \ + "robust" "$(msg PROFILE_ROBUST)" \ + "standalone" "$(msg PROFILE_STANDALONE)")" + validate_profile "$PROFILE" + + module="$(show_menu "$(msg APP_TITLE)" "$(msg MENU_CHOOSE_MODULE)" \ + "install" "$(msg MENU_INSTALL)" \ + "startstop" "$(msg MENU_STARTSTOP)" \ + "cleanup" "$(msg MENU_CLEANUP)" \ + "health" "$(msg MENU_HEALTH)" \ + "backup" "$(msg MENU_BACKUP)" \ + "restore" "$(msg MENU_RESTORE)" \ + "update" "$(msg MENU_UPDATE)" \ + "config" "$(msg MENU_CONFIG)" \ + "report" "$(msg MENU_REPORT)" \ + "smoke" "$(msg MENU_SMOKE)" \ + "cron" "$(msg MENU_CRON)")" + + case "$module" in + install) + action="$(show_menu "$(msg MENU_INSTALL)" "$(msg MENU_CHOOSE_ACTION)" \ + "server-check" "server-check" \ + "prepare-ubuntu" "prepare-ubuntu" \ + "install-opensim-deps" "install-opensim-deps" \ + "install-dotnet8" "install-dotnet8" \ + "install-opensim" "install-opensim" \ + "configure-opensim" "configure-opensim" \ + "configure-database" "configure-database" \ + "compile-janus" "compile-janus" \ + "configure-janus" "configure-janus" \ + "install-janus" "install-janus")" + dispatch_module install --action "$action" + ;; + startstop) + if [[ "$PROFILE" == "grid-sim" ]]; then + target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \ + "grid" "$(msg TARGET_GRID)" \ + "robust" "$(msg TARGET_ROBUST)" \ + "sim1" "$(msg TARGET_SIM1)" \ + "janus" "$(msg TARGET_JANUS)")" + elif [[ "$PROFILE" == "robust" ]]; then + target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \ + "robust" "$(msg TARGET_ROBUST)" \ + "janus" "$(msg TARGET_JANUS)")" + else + target="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_TARGET)" \ + "standalone" "$(msg TARGET_STANDALONE)" \ + "janus" "$(msg TARGET_JANUS)")" + fi + + action="$(show_menu "$(msg MENU_STARTSTOP)" "$(msg MENU_CHOOSE_ACTION)" \ + "start" "$(msg ACTION_START)" \ + "stop" "$(msg ACTION_STOP)" \ + "restart" "$(msg ACTION_RESTART)")" + dispatch_module startstop --target "$target" --action "$action" + ;; + cleanup) + action="$(show_menu "$(msg MENU_CLEANUP)" "$(msg MENU_CHOOSE_ACTION)" \ + "cache-clean" "$(msg ACTION_CACHE_CLEAN)" \ + "log-clean" "$(msg ACTION_LOG_CLEAN)" \ + "tmp-clean" "$(msg ACTION_TMP_CLEAN)" \ + "reboot" "$(msg ACTION_REBOOT)")" + dispatch_module cleanup --action "$action" + ;; + health) + action="$(show_menu "$(msg MENU_HEALTH)" "$(msg MENU_CHOOSE_ACTION)" \ + "run" "$(msg ACTION_HEALTH_RUN)")" + dispatch_module health --action "$action" + ;; + backup) + action="$(show_menu "$(msg MENU_BACKUP)" "$(msg MENU_CHOOSE_ACTION)" \ + "db-backup" "$(msg ACTION_DB_BACKUP)" \ + "oar-backup" "$(msg ACTION_OAR_BACKUP)" \ + "full-backup" "$(msg ACTION_FULL_BACKUP)")" + dispatch_module backup --action "$action" + ;; + restore) + action="$(show_menu "$(msg MENU_RESTORE)" "$(msg MENU_CHOOSE_ACTION)" \ + "list-backups" "$(msg ACTION_RESTORE_LIST)" \ + "db-restore" "$(msg ACTION_RESTORE_DB)" \ + "oar-restore" "$(msg ACTION_RESTORE_OAR)" \ + "full-restore" "$(msg ACTION_RESTORE_FULL)")" + dispatch_module restore --action "$action" + ;; + update) + action="$(show_menu "$(msg MENU_UPDATE)" "$(msg MENU_CHOOSE_ACTION)" \ + "create-rollback" "$(msg ACTION_UPDATE_ROLLBACK)" \ + "list-rollbacks" "$(msg ACTION_UPDATE_LIST)" \ + "update-opensim" "$(msg ACTION_UPDATE_OPENSIM)" \ + "update-janus" "$(msg ACTION_UPDATE_JANUS)" \ + "full-update" "$(msg ACTION_UPDATE_FULL)")" + dispatch_module update --action "$action" + ;; + config) + action="$(show_menu "$(msg MENU_CONFIG)" "$(msg MENU_CHOOSE_ACTION)" \ + "validate-file" "$(msg ACTION_CONFIG_FILE)" \ + "validate-runtime" "$(msg ACTION_CONFIG_RUNTIME)")" + dispatch_module config --action "$action" + ;; + report) + action="$(show_menu "$(msg MENU_REPORT)" "$(msg MENU_CHOOSE_ACTION)" \ + "generate" "$(msg ACTION_REPORT_GENERATE)")" + dispatch_module report --action "$action" + ;; + smoke) + action="$(show_menu "$(msg MENU_SMOKE)" "$(msg MENU_CHOOSE_ACTION)" \ + "run" "$(msg ACTION_SMOKE_RUN)")" + dispatch_module smoke --action "$action" + ;; + cron) + action="$(show_menu "$(msg MENU_CRON)" "$(msg MENU_CHOOSE_ACTION)" \ + "install" "$(msg ACTION_CRON_INSTALL)" \ + "list" "$(msg ACTION_CRON_LIST)" \ + "remove" "$(msg ACTION_CRON_REMOVE)")" + dispatch_module cron --action "$action" + ;; + *) + die "$(msg ERR_UNKNOWN_UI_MODULE): $module" + ;; + esac +} + +MODE="cli" +MODULE="" +LANG_OVERRIDE="${OSM_LANG:-$APP_LANG}" +PROFILE="grid-sim" + +if [[ $# -eq 0 ]]; then + MODE="ui" + ui_flow + exit 0 +fi + +if [[ "${1:-}" == "h" || "${1:-}" == "help" ]]; then + usage + exit 0 +fi + +if [[ "${1:-}" == "server_install" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + + log INFO "Running server_install shortcut (prepare-ubuntu -> install-opensim-deps -> install-dotnet8 -> server-check -> install-opensim -> configure-opensim)" + dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "configinit" ]]; then + set_language "$LANG_OVERRIDE" + dispatch_module config --action init-config --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "install-grid-sim" ]]; then + PROFILE="grid-sim" + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + + # Pflichtparameter: Datenbank-Credentials und Anzahl Simulatoren + _db_user="${OSM_DB_USER:-}" + _db_pass="${OSM_DB_PASS:-}" + _sim_count="${OSM_SIM_COUNT:-1}" + _hostname="${OSM_HOST:-}" + _gridname="${OSM_GRIDNAME:-}" + + if [[ -z "$_db_user" || -z "$_db_pass" ]]; then + log ERROR "Datenbankzugangsdaten fehlen. Vor dem Aufruf setzen:" + log ERROR " export OSM_DB_USER=opensim" + log ERROR " export OSM_DB_PASS='MeinSicheresPasswort'" + log ERROR " export OSM_SIM_COUNT=3 # Anzahl sim-Instanzen" + log ERROR " export OSM_HOST=1.2.3.4 # Öffentliche IP oder Hostname" + log ERROR " export OSM_GRIDNAME='Mein Grid'" + exit 1 + fi + + log INFO "Starte install-grid-sim (prepare-ubuntu → deps → dotnet8 → server-check → install-opensim → configure-database → configure-opensim)" + + dispatch_module install --action prepare-ubuntu --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action install-opensim-deps --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action install-dotnet8 --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action server-check --workdir "$DEFAULT_WORKDIR" + dispatch_module install --action install-opensim --workdir "$DEFAULT_WORKDIR" + # Datenbanken vor configure-opensim anlegen (ConnectionStrings werden danach geschrieben) + dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" \ + --db-user "$_db_user" --db-pass "$_db_pass" --sim-count "$_sim_count" + # Ini-Dateien mit Credentials, Hostname und Gridname befüllen + dispatch_module install --action configure-opensim --workdir "$DEFAULT_WORKDIR" \ + --db-user "$_db_user" --db-pass "$_db_pass" \ + ${_hostname:+--public-host "$_hostname"} \ + ${_gridname:+--gridname "$_gridname"} + exit 0 +fi + +if [[ "${1:-}" == "opensimstart" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action start --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "opensimstop" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action stop --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "opensimrestart" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module startstop --target "$(default_target_for_profile "$PROFILE")" --action restart --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "healthcheck" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module health --action run --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "smoketest" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module smoke --action run --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "dailyreport" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module report --action generate --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "croninstall" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module cron --action install --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "cronlist" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module cron --action list --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "janusinstall" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module install --action install-janus --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "janusrestart" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + dispatch_module startstop --target janus --action restart --workdir "$DEFAULT_WORKDIR" + exit 0 +fi + +if [[ "${1:-}" == "dbsetup" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + + DB_USER_SHORT="${OSM_DB_USER:-opensim}" + DB_PASS_SHORT="${OSM_DB_PASS:-}" + DB_ROOT_USER_SHORT="${OSM_DB_ROOT_USER:-root}" + DB_ROOT_PASS_SHORT="${OSM_DB_ROOT_PASS:-}" + + [[ -n "$DB_PASS_SHORT" ]] || die "dbsetup requires OSM_DB_PASS environment variable" + + dispatch_module install --action configure-database --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-root-user "$DB_ROOT_USER_SHORT" --db-root-pass "$DB_ROOT_PASS_SHORT" + exit 0 +fi + +if [[ "${1:-}" == "dbbackup" ]]; then + set_language "$LANG_OVERRIDE" + validate_profile "$PROFILE" + + DB_USER_SHORT="${OSM_DB_USER:-root}" + DB_PASS_SHORT="${OSM_DB_PASS:-}" + DB_NAME_SHORT="${OSM_DB_NAME:-opensim}" + + [[ -n "$DB_PASS_SHORT" ]] || die "dbbackup requires OSM_DB_PASS environment variable" + + dispatch_module backup --action db-backup --workdir "$DEFAULT_WORKDIR" --db-user "$DB_USER_SHORT" --db-pass "$DB_PASS_SHORT" --db-name "$DB_NAME_SHORT" + exit 0 +fi + +while [[ $# -gt 0 ]]; do + case "$1" in + --mode) MODE="$2"; shift 2 ;; + --lang) LANG_OVERRIDE="$2"; shift 2 ;; + --profile) PROFILE="$2"; shift 2 ;; + --module) MODULE="$2"; shift 2 ;; + --help|-h) usage; exit 0 ;; + *) break ;; + esac +done + +set_language "$LANG_OVERRIDE" +validate_profile "$PROFILE" + +if [[ "$MODE" == "ui" ]]; then + ui_flow + exit 0 +fi + +[[ -n "$MODULE" ]] || die "$(msg ERR_MISSING_MODULE)" + +if [[ "$MODULE" == "startstop" ]] && ! args_have_target "$@"; then + dispatch_module "$MODULE" --target "$(default_target_for_profile "$PROFILE")" "$@" +else + dispatch_module "$MODULE" "$@" +fi diff --git a/osmtool_restart.sh b/osmtool_restart.sh index c26808d..9cb6685 100644 --- a/osmtool_restart.sh +++ b/osmtool_restart.sh @@ -1,270 +1,270 @@ -#!/bin/bash - -#* WARTEZEITEN muessen leider sein damit der Server nicht überfordert wird. -Simulator_Start_wait=15 # Sekunden -MoneyServer_Start_wait=30 # Sekunden -RobustServer_Start_wait=30 # Sekunden -Simulator_Stop_wait=15 # Sekunden -MoneyServer_Stop_wait=30 # Sekunden -RobustServer_Stop_wait=30 # Sekunden - -#?────────────────────────────────────────────────────────────────────────────────────────── -#* Start Stop Grid -#?────────────────────────────────────────────────────────────────────────────────────────── - -function opensimstart() { - echo "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}" - - # 1. RobustServer (muss zuerst laufen) - if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then - echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" - (cd robust/bin && screen -fa -S robustserver -d -U -m dotnet Robust.dll) - sleep "$RobustServer_Start_wait" - else - echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" - fi - - # 2. MoneyServer (optional) - if [[ -f "robust/bin/MoneyServer.dll" ]]; then - echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" - (cd robust/bin && screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll) - sleep "$MoneyServer_Start_wait" - fi - - # 3. SIM1 ZUERST (sequentiell) - if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then - echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_START}(primäre Region)...${COLOR_RESET}" - (cd sim1/bin && screen -fa -S sim1 -d -U -m dotnet OpenSim.dll) - sleep "$Simulator_Start_wait" - else - echo "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET}" - fi - - # 4. SIM2-SIM99 PARALLEL - echo "${SYM_INFO} ${COLOR_START}Starte sekundäre Simulatoren parallel...${COLOR_RESET}" - - # Maximal 10 parallele Jobs - MAX_JOBS=10 - for ((i=2; i<=99; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then - - # Warten falls zu viele Jobs laufen - while (( $(jobs -p | wc -l) >= MAX_JOBS )); do - sleep 1 - done - - echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}" - (cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll) & - fi - done - - wait # Warte auf alle Hintergrundjobs - echo "${SYM_OK} ${COLOR_START}Alle Simulatoren gestartet.${COLOR_RESET}" - echo . -} - -function opensimstop() { - echo "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}" - local MAX_PARALLEL=10 # Maximale parallele Stopp-Vorgänge - - # 1. Paralleles Stoppen von sim999 bis sim2 - echo "${SYM_INFO} ${COLOR_STOP}Stoppe sekundäre Simulatoren parallel...${COLOR_RESET}" - for ((i=999; i>=2; i--)); do - sim_name="sim$i" - - # Warten falls zu viele parallele Jobs laufen - #while [ $(jobs -p | wc -l) -ge $MAX_PARALLEL ]; do - while [ "$(jobs -p | wc -l)" -ge $MAX_PARALLEL ]; do - sleep 0.5 - done - - if screen -list | grep -q "$sim_name"; then - echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}$sim_name${COLOR_RESET}" - ( - screen -S "$sim_name" -p 0 -X stuff "shutdown^M" - sleep $Simulator_Stop_wait - ) & - fi - done - wait # Warte auf alle parallelen Stopp-Vorgänge - - # 2. Sim1 sequentiell stoppen - if screen -list | grep -q "sim1"; then - echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_STOP}(primäre Region)...${COLOR_RESET}" - screen -S "sim1" -p 0 -X stuff "shutdown^M" - sleep $Simulator_Stop_wait - fi - - # 3. MoneyServer stoppen - if screen -list | grep -q "moneyserver"; then - echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" - screen -S moneyserver -p 0 -X stuff "shutdown^M" - sleep $MoneyServer_Stop_wait - else - echo "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" - fi - - # 4. RobustServer stoppen (zuletzt) - if screen -list | grep -q "robustserver"; then - echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" - screen -S robustserver -p 0 -X stuff "shutdown^M" - sleep $RobustServer_Stop_wait - else - echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" - fi - - echo "${SYM_OK} ${COLOR_STOP}Alle Dienste gestoppt.${COLOR_RESET}" - echo . -} - -# check_screens ist eine Grid Funktion und funktioniert nicht im Standalone. -# bash osmtool_backup.sh check_screens -function check_screens() { - # echo "Überprüfung der laufenden OpenSim-Prozesse..." - - restart_all=false - - # Überprüfen, ob RobustServer läuft - if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then - screenRO=$(screen -ls | grep -w "robustserver") - if [[ -z "$screenRO" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log - restart_all=true - fi - fi - - # Überprüfen, ob MoneyServer läuft - if [[ -d "robust/bin" && -f "robust/bin/MoneyServer.dll" ]];then - screenMoney=$(screen -ls | grep -w "moneyserver") - if [[ -z "$screenMoney" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log - restart_all=true - fi - fi - - # Überprüfen, ob sim1 läuft - if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then - screenSim1=$(screen -ls | grep -w "sim1") - if [[ -z "$screenSim1" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log - restart_all=true - fi - fi - - # Falls eines der kritischen Systeme ausgefallen ist, alles neu starten - if [[ "$restart_all" == true ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - Kritische Prozesse sind ausgefallen! OpenSim wird komplett neu gestartet." >> ProblemRestarts.log - # opensimstart - opensimrestart - return 0 - fi - - # Überprüfen, ob andere Regionen (sim2 bis sim999) einzeln neu gestartet werden müssen - for ((i=2; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then - screenSim=$(screen -ls | grep -w "sim$i") - if [[ -z "$screenSim" ]]; then - echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft nicht und wird einzeln neu gestartet." >> ProblemRestarts.log - cd "$sim_dir" || continue - screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll - cd - >/dev/null 2>&1 || continue - sleep $Simulator_Start_wait - fi - fi - done - echo . -} - -# Neu Test -function check_screens_neu() { - echo "${SYM_WAIT} ${COLOR_START}Überprüfe laufende OpenSim-Prozesse...${COLOR_RESET}" - restart_all=false - log_file="ProblemRestarts.log" - - timestamp="$(date '+%Y-%m-%d %H:%M:%S')" - - # Funktion zum Screen-Check - function screen_running() { - screen -ls | grep -qw "$1" - } - - # RobustServer prüfen - if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then - if ! screen_running "robustserver"; then - echo "$timestamp - RobustServer läuft nicht." >> "$log_file" - restart_all=true - fi - fi - - # MoneyServer prüfen - if [[ -f "robust/bin/MoneyServer.dll" ]]; then - if ! screen_running "moneyserver"; then - echo "$timestamp - MoneyServer läuft nicht." >> "$log_file" - restart_all=true - fi - fi - - # sim1 prüfen - if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then - if ! screen_running "sim1"; then - echo "$timestamp - sim1 läuft nicht." >> "$log_file" - restart_all=true - fi - fi - - # Falls kritische Komponenten fehlen → kompletten Neustart - if [[ "$restart_all" == true ]]; then - echo "$timestamp - Kritische Komponenten fehlen. Starte das gesamte Grid neu." >> "$log_file" - opensimrestart - return 0 - fi - - # sim2 bis sim999 einzeln prüfen und ggf. neu starten - for ((i=2; i<=999; i++)); do - sim_dir="sim$i/bin" - if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then - if ! screen_running "sim$i"; then - echo "$timestamp - sim$i läuft nicht. Starte Region neu." >> "$log_file" - cd "$sim_dir" || continue - screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll - cd - >/dev/null 2>&1 || continue - sleep $Simulator_Start_wait - fi - fi - done - - echo "${SYM_OK} ${COLOR_START}Überprüfung abgeschlossen.${COLOR_RESET}" - screen -ls || echo "Keine Screen-Sessions gefunden" -} - - -function opensimrestart() { - opensimstop - sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp - opensimstart - screen -ls || echo "Keine Screen-Sessions gefunden" -} - - -KOMMANDO="$1" - -case $KOMMANDO in - "start") - opensimstart - ;; - "stop") - opensimstop - ;; - "restart") - opensimrestart - ;; - "check_screens") - check_screens_neu - ;; - *) - opensimrestart - ;; -esac +#!/bin/bash + +#* WARTEZEITEN muessen leider sein damit der Server nicht überfordert wird. +Simulator_Start_wait=15 # Sekunden +MoneyServer_Start_wait=30 # Sekunden +RobustServer_Start_wait=30 # Sekunden +Simulator_Stop_wait=15 # Sekunden +MoneyServer_Stop_wait=30 # Sekunden +RobustServer_Stop_wait=30 # Sekunden + +#?────────────────────────────────────────────────────────────────────────────────────────── +#* Start Stop Grid +#?────────────────────────────────────────────────────────────────────────────────────────── + +function opensimstart() { + echo "${SYM_WAIT} ${COLOR_START}Starte das Grid!${COLOR_RESET}" + + # 1. RobustServer (muss zuerst laufen) + if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then + echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}RobustServer ${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" + (cd robust/bin && screen -fa -S robustserver -d -U -m dotnet Robust.dll) + sleep "$RobustServer_Start_wait" + else + echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Robust.dll nicht gefunden.${COLOR_RESET} ${COLOR_START}Überspringe Start.${COLOR_RESET}" + fi + + # 2. MoneyServer (optional) + if [[ -f "robust/bin/MoneyServer.dll" ]]; then + echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}robust/bin...${COLOR_RESET}" + (cd robust/bin && screen -fa -S moneyserver -d -U -m dotnet MoneyServer.dll) + sleep "$MoneyServer_Start_wait" + fi + + # 3. SIM1 ZUERST (sequentiell) + if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then + echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_START}(primäre Region)...${COLOR_RESET}" + (cd sim1/bin && screen -fa -S sim1 -d -U -m dotnet OpenSim.dll) + sleep "$Simulator_Start_wait" + else + echo "${SYM_BAD} ${COLOR_SERVER}sim1: ${COLOR_BAD}OpenSim.dll nicht gefunden.${COLOR_RESET}" + fi + + # 4. SIM2-SIM99 PARALLEL + echo "${SYM_INFO} ${COLOR_START}Starte sekundäre Simulatoren parallel...${COLOR_RESET}" + + # Maximal 10 parallele Jobs + MAX_JOBS=10 + for ((i=2; i<=99; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then + + # Warten falls zu viele Jobs laufen + while (( $(jobs -p | wc -l) >= MAX_JOBS )); do + sleep 1 + done + + echo "${SYM_OK} ${COLOR_START}Starte ${COLOR_SERVER}sim$i${COLOR_RESET} ${COLOR_START}aus ${COLOR_DIR}$sim_dir...${COLOR_RESET}" + (cd "$sim_dir" && screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll) & + fi + done + + wait # Warte auf alle Hintergrundjobs + echo "${SYM_OK} ${COLOR_START}Alle Simulatoren gestartet.${COLOR_RESET}" + echo . +} + +function opensimstop() { + echo "${SYM_WAIT} ${COLOR_STOP}Stoppe das Grid!${COLOR_RESET}" + local MAX_PARALLEL=10 # Maximale parallele Stopp-Vorgänge + + # 1. Paralleles Stoppen von sim999 bis sim2 + echo "${SYM_INFO} ${COLOR_STOP}Stoppe sekundäre Simulatoren parallel...${COLOR_RESET}" + for ((i=999; i>=2; i--)); do + sim_name="sim$i" + + # Warten falls zu viele parallele Jobs laufen + #while [ $(jobs -p | wc -l) -ge $MAX_PARALLEL ]; do + while [ "$(jobs -p | wc -l)" -ge $MAX_PARALLEL ]; do + sleep 0.5 + done + + if screen -list | grep -q "$sim_name"; then + echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}$sim_name${COLOR_RESET}" + ( + screen -S "$sim_name" -p 0 -X stuff "shutdown^M" + sleep $Simulator_Stop_wait + ) & + fi + done + wait # Warte auf alle parallelen Stopp-Vorgänge + + # 2. Sim1 sequentiell stoppen + if screen -list | grep -q "sim1"; then + echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}sim1${COLOR_RESET} ${COLOR_STOP}(primäre Region)...${COLOR_RESET}" + screen -S "sim1" -p 0 -X stuff "shutdown^M" + sleep $Simulator_Stop_wait + fi + + # 3. MoneyServer stoppen + if screen -list | grep -q "moneyserver"; then + echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}MoneyServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" + screen -S moneyserver -p 0 -X stuff "shutdown^M" + sleep $MoneyServer_Stop_wait + else + echo "${SYM_BAD} ${COLOR_SERVER}MoneyServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" + fi + + # 4. RobustServer stoppen (zuletzt) + if screen -list | grep -q "robustserver"; then + echo "${SYM_OK} ${COLOR_STOP}Stoppe ${COLOR_SERVER}RobustServer${COLOR_RESET} ${COLOR_STOP}...${COLOR_RESET}" + screen -S robustserver -p 0 -X stuff "shutdown^M" + sleep $RobustServer_Stop_wait + else + echo "${SYM_BAD} ${COLOR_SERVER}RobustServer: ${COLOR_BAD}Läuft nicht.${COLOR_RESET}" + fi + + echo "${SYM_OK} ${COLOR_STOP}Alle Dienste gestoppt.${COLOR_RESET}" + echo . +} + +# check_screens ist eine Grid Funktion und funktioniert nicht im Standalone. +# bash osmtool_backup.sh check_screens +function check_screens() { + # echo "Überprüfung der laufenden OpenSim-Prozesse..." + + restart_all=false + + # Überprüfen, ob RobustServer läuft + if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then + screenRO=$(screen -ls | grep -w "robustserver") + if [[ -z "$screenRO" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - RobustServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log + restart_all=true + fi + fi + + # Überprüfen, ob MoneyServer läuft + if [[ -d "robust/bin" && -f "robust/bin/MoneyServer.dll" ]];then + screenMoney=$(screen -ls | grep -w "moneyserver") + if [[ -z "$screenMoney" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - MoneyServer läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log + restart_all=true + fi + fi + + # Überprüfen, ob sim1 läuft + if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then + screenSim1=$(screen -ls | grep -w "sim1") + if [[ -z "$screenSim1" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim1 läuft nicht und muss neu gestartet werden." >> ProblemRestarts.log + restart_all=true + fi + fi + + # Falls eines der kritischen Systeme ausgefallen ist, alles neu starten + if [[ "$restart_all" == true ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - Kritische Prozesse sind ausgefallen! OpenSim wird komplett neu gestartet." >> ProblemRestarts.log + # opensimstart + opensimrestart + return 0 + fi + + # Überprüfen, ob andere Regionen (sim2 bis sim999) einzeln neu gestartet werden müssen + for ((i=2; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then + screenSim=$(screen -ls | grep -w "sim$i") + if [[ -z "$screenSim" ]]; then + echo "$(date '+%Y-%m-%d %H:%M:%S') - Sim$i läuft nicht und wird einzeln neu gestartet." >> ProblemRestarts.log + cd "$sim_dir" || continue + screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll + cd - >/dev/null 2>&1 || continue + sleep $Simulator_Start_wait + fi + fi + done + echo . +} + +# Neu Test +function check_screens_neu() { + echo "${SYM_WAIT} ${COLOR_START}Überprüfe laufende OpenSim-Prozesse...${COLOR_RESET}" + restart_all=false + log_file="ProblemRestarts.log" + + timestamp="$(date '+%Y-%m-%d %H:%M:%S')" + + # Funktion zum Screen-Check + function screen_running() { + screen -ls | grep -qw "$1" + } + + # RobustServer prüfen + if [[ -d "robust/bin" && -f "robust/bin/Robust.dll" ]]; then + if ! screen_running "robustserver"; then + echo "$timestamp - RobustServer läuft nicht." >> "$log_file" + restart_all=true + fi + fi + + # MoneyServer prüfen + if [[ -f "robust/bin/MoneyServer.dll" ]]; then + if ! screen_running "moneyserver"; then + echo "$timestamp - MoneyServer läuft nicht." >> "$log_file" + restart_all=true + fi + fi + + # sim1 prüfen + if [[ -d "sim1/bin" && -f "sim1/bin/OpenSim.dll" ]]; then + if ! screen_running "sim1"; then + echo "$timestamp - sim1 läuft nicht." >> "$log_file" + restart_all=true + fi + fi + + # Falls kritische Komponenten fehlen → kompletten Neustart + if [[ "$restart_all" == true ]]; then + echo "$timestamp - Kritische Komponenten fehlen. Starte das gesamte Grid neu." >> "$log_file" + opensimrestart + return 0 + fi + + # sim2 bis sim999 einzeln prüfen und ggf. neu starten + for ((i=2; i<=999; i++)); do + sim_dir="sim$i/bin" + if [[ -d "$sim_dir" && -f "$sim_dir/OpenSim.dll" ]]; then + if ! screen_running "sim$i"; then + echo "$timestamp - sim$i läuft nicht. Starte Region neu." >> "$log_file" + cd "$sim_dir" || continue + screen -fa -S "sim$i" -d -U -m dotnet OpenSim.dll + cd - >/dev/null 2>&1 || continue + sleep $Simulator_Start_wait + fi + fi + done + + echo "${SYM_OK} ${COLOR_START}Überprüfung abgeschlossen.${COLOR_RESET}" + screen -ls || echo "Keine Screen-Sessions gefunden" +} + + +function opensimrestart() { + opensimstop + sleep $Simulator_Stop_wait # Wartezeit für Dienst-Stopp + opensimstart + screen -ls || echo "Keine Screen-Sessions gefunden" +} + + +KOMMANDO="$1" + +case $KOMMANDO in + "start") + opensimstart + ;; + "stop") + opensimstop + ;; + "restart") + opensimrestart + ;; + "check_screens") + check_screens_neu + ;; + *) + opensimrestart + ;; +esac # Ende des Skripts \ No newline at end of file diff --git a/webphp/bin/osmtool_web_runner.sh b/webphp/bin/osmtool_web_runner.sh index 975ecbd..5ae5f65 100644 --- a/webphp/bin/osmtool_web_runner.sh +++ b/webphp/bin/osmtool_web_runner.sh @@ -1,42 +1,42 @@ -#!/usr/bin/env bash -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" -MAIN_SCRIPT="$PROJECT_ROOT/osmtool_main.sh" - -if [[ ! -x "$MAIN_SCRIPT" ]]; then - echo "ERROR: osmtool_main.sh not executable: $MAIN_SCRIPT" >&2 - exit 1 -fi - -MODULE="${1:-}" -ACTION="${2:-}" -PROFILE="${3:-grid-sim}" -LANG="${4:-de}" -WORKDIR="${5:-/opt}" - -shift $(( $# >= 5 ? 5 : $# )) - -EXTRA_ARGS=("$@") - -case "$MODULE" in - install|startstop|cleanup|health|backup|restore|update|config|report|smoke|cron) ;; - *) echo "ERROR: unsupported module" >&2; exit 2 ;; -esac - -case "$PROFILE" in - grid-sim|robust|standalone) ;; - *) echo "ERROR: invalid profile" >&2; exit 2 ;; -esac - -case "$LANG" in - de|en|fr|es) ;; - *) echo "ERROR: invalid language" >&2; exit 2 ;; -esac - -run_main() { - bash "$MAIN_SCRIPT" --mode cli --profile "$PROFILE" --lang "$LANG" --workdir "$WORKDIR" --module "$MODULE" --action "$ACTION" "${EXTRA_ARGS[@]}" -} - -run_main +#!/usr/bin/env bash +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +MAIN_SCRIPT="$PROJECT_ROOT/osmtool_main.sh" + +if [[ ! -x "$MAIN_SCRIPT" ]]; then + echo "ERROR: osmtool_main.sh not executable: $MAIN_SCRIPT" >&2 + exit 1 +fi + +MODULE="${1:-}" +ACTION="${2:-}" +PROFILE="${3:-grid-sim}" +LANG="${4:-de}" +WORKDIR="${5:-/opt}" + +shift $(( $# >= 5 ? 5 : $# )) + +EXTRA_ARGS=("$@") + +case "$MODULE" in + install|startstop|cleanup|health|backup|restore|update|config|report|smoke|cron) ;; + *) echo "ERROR: unsupported module" >&2; exit 2 ;; +esac + +case "$PROFILE" in + grid-sim|robust|standalone) ;; + *) echo "ERROR: invalid profile" >&2; exit 2 ;; +esac + +case "$LANG" in + de|en|fr|es) ;; + *) echo "ERROR: invalid language" >&2; exit 2 ;; +esac + +run_main() { + bash "$MAIN_SCRIPT" --mode cli --profile "$PROFILE" --lang "$LANG" --workdir "$WORKDIR" --module "$MODULE" --action "$ACTION" "${EXTRA_ARGS[@]}" +} + +run_main