#!/usr/bin/env bash set -u set -o pipefail readonly DEFAULT_DURATION_SECONDS="8" readonly TEST_OVERRIDE_ACK_VALUE="YES" CAPTURE="" STATUS_DIR="" LAUNCH_ACTIVE="NO" INTERRUPT_PENDING="NO" SELECTED_SCENARIO="" DISPLAY_SCENARIO="" SELECTED_PROFILE="N/A" SELECTED_DURATION="" LAST_LAUNCHER_RC="NOT_AVAILABLE" LAST_RUN_DIR="NOT_AVAILABLE" LAST_RUN_DIR_STATUS="NOT_AVAILABLE" cleanup_temporary_files() { if [ -n "$CAPTURE" ]; then rm -f -- "$CAPTURE" CAPTURE="" fi if [ -n "$STATUS_DIR" ]; then rm -f -- \ "$STATUS_DIR/launcher_rc" \ "$STATUS_DIR/tee_rc" rmdir -- "$STATUS_DIR" 2>/dev/null || true STATUS_DIR="" fi } fatal_wrapper_error() { local exit_code="$1" local status="$2" local message="$3" printf 'ERRORE S03-H3: %s\n' "$message" >&2 if [ "$exit_code" -eq 70 ]; then printf 'S03_H3_STARTUP_STATUS=%s\n' "$status" >&2 else printf 'S03_H3_MENU_LIFECYCLE_STATUS=%s\n' "$status" >&2 fi exit "$exit_code" } handle_int() { if [ "$LAUNCH_ACTIVE" = "YES" ]; then INTERRUPT_PENDING="YES" return 0 fi printf '\nInterruzione richiesta: nessun nuovo benchmark verra avviato.\n' >&2 printf 'LAUNCHER_EXECUTED=NO\n' >&2 exit 130 } handle_hup() { printf '\nS03-H3 terminato da SIGHUP.\n' >&2 exit 129 } handle_term() { printf '\nS03-H3 terminato da SIGTERM.\n' >&2 exit 143 } trap cleanup_temporary_files EXIT trap handle_hup HUP trap handle_int INT trap handle_term TERM SCRIPT_DIR="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd -P)" if [ -z "$SCRIPT_DIR" ]; then fatal_wrapper_error 70 "FAIL_SUITE_ROOT" \ "impossibile determinare la directory del menu" fi INSTALLED_SUITE="$(cd -- "$SCRIPT_DIR/.." && pwd -P)" if [ -z "$INSTALLED_SUITE" ]; then fatal_wrapper_error 70 "FAIL_SUITE_ROOT" \ "impossibile determinare la radice della suite" fi readonly -a COMPLETE_OVERRIDE_PATHS=( "launcher/marte_benchmark_launcher.sh" "configurations/generated/S00/smoke_s0_core.marte" "configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte" "configurations/generated/S02/from_patcher/smoke_s2_binary_recording_from_s01.marte" "configurations/generated/S03/from_patcher/smoke_s3_semantic_sentinels_from_s02.marte" "patchers/configuration/build_s01_from_s00.sh" "patchers/configuration/build_s02_from_s01.sh" "patchers/configuration/build_s03_from_s02.sh" "scenarios/S02_binary_recording/validate.sh" "scenarios/S03_semantic_sentinels/validate.sh" "scenarios/S03_semantic_sentinels/parse_s03_binary.py" "common/marte_runner.sh" "common/paths.sh" "common/environment.sh" "launcher/marte_benchmark_launcher_s03h1.sh" "patchers/configuration/build_s03h1_from_s02.sh" "scenarios/S03H1_execution_profiles/validate.sh" "scenarios/S03H1_execution_profiles/verify_s03h1_config.py" "scenarios/S03H1_execution_profiles/export_s03_csv.py" "configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_test_from_s02.marte" "configurations/generated/S03H1/from_patcher/smoke_s03h1_execution_profiles_diagnostic_from_s02.marte" "launcher/marte_benchmark_launcher_s03h3.sh" "patchers/configuration/build_s03h3_minimal_from_s03h1_test.sh" "scenarios/S03H3_execution_profiles/validate.sh" "scenarios/S03H3_execution_profiles/verify_s03h3_minimal_structure.py" "configurations/generated/S03H3/from_patcher/smoke_s03h3_execution_profiles_minimal_from_s03h1_test.marte" "launcher/marte_benchmark_menu.sh" ) verify_complete_override_root() { local relative_path local missing_count=0 for relative_path in "${COMPLETE_OVERRIDE_PATHS[@]}"; do if [ ! -f "$SUITE/$relative_path" ]; then printf 'ERRORE S03-H3: fixture incompleta, manca %s\n' \ "$relative_path" >&2 missing_count=$((missing_count + 1)) fi done [ "$missing_count" -eq 0 ] } OVERRIDE_ACTIVE="NO" if [ -n "${MARTE_BENCHMARK_SUITE_ROOT:-}" ]; then if [ "${S03H3_TEST_ONLY_OVERRIDE:-NO}" != "$TEST_OVERRIDE_ACK_VALUE" ]; then fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_NOT_ACKNOWLEDGED" \ "MARTE_BENCHMARK_SUITE_ROOT richiede S03H3_TEST_ONLY_OVERRIDE=YES" fi if [[ "$MARTE_BENCHMARK_SUITE_ROOT" != /* ]]; then fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_NOT_ABSOLUTE" \ "la radice di override deve essere un percorso assoluto" fi if [ ! -d "$MARTE_BENCHMARK_SUITE_ROOT" ]; then fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_ROOT" \ "la radice di override non esiste" fi SUITE="$(cd -- "$MARTE_BENCHMARK_SUITE_ROOT" && pwd -P)" if [ -z "$SUITE" ] || [ "$SUITE" = "/" ]; then fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_ROOT" \ "la radice di override non e sicura" fi OVERRIDE_ACTIVE="YES" if ! verify_complete_override_root; then fatal_wrapper_error 70 "FAIL_INCOMPLETE_TEST_SUITE" \ "l'override e ammesso soltanto per una suite completa di 27 elementi" fi elif [ "${S03H3_TEST_ONLY_OVERRIDE:-NO}" = "$TEST_OVERRIDE_ACK_VALUE" ]; then fatal_wrapper_error 70 "FAIL_TEST_OVERRIDE_ROOT_MISSING" \ "S03H3_TEST_ONLY_OVERRIDE=YES richiede MARTE_BENCHMARK_SUITE_ROOT" else SUITE="$INSTALLED_SUITE" fi readonly SUITE readonly OVERRIDE_ACTIVE STANDARD_LAUNCHER="$SUITE/launcher/marte_benchmark_launcher.sh" S03H3_LAUNCHER="$SUITE/launcher/marte_benchmark_launcher_s03h3.sh" readonly STANDARD_LAUNCHER readonly S03H3_LAUNCHER if [ ! -x "$STANDARD_LAUNCHER" ]; then fatal_wrapper_error 70 "FAIL_REQUIRED_LAUNCHER" \ "launcher standard assente o non eseguibile: $STANDARD_LAUNCHER" fi if [ ! -x "$S03H3_LAUNCHER" ]; then fatal_wrapper_error 70 "FAIL_REQUIRED_LAUNCHER" \ "launcher S03-H3 assente o non eseguibile: $S03H3_LAUNCHER" fi export MARTE_BENCHMARK_SUITE_ROOT="$SUITE" is_positive_decimal() { local value="$1" [[ "$value" =~ ^[0-9]+$ ]] && [[ "$value" =~ [1-9] ]] } normalize_decimal() { local value="$1" while [ "${#value}" -gt 1 ] && [ "${value:0:1}" = "0" ]; do value="${value#0}" done printf '%s' "$value" } print_main_menu() { printf '\n============================================================\n' printf 'MARTe2 Benchmark Suite — menu S03-H3\n' printf '============================================================\n' printf '1) S01\n' printf '2) S02\n' printf '3) S03\n' printf '4) S03-H3\n' printf '0) Exit\n' printf 'Selection: ' } read_duration() { local value printf 'Simulation duration [seconds] (default: %s): ' \ "$DEFAULT_DURATION_SECONDS" if ! IFS= read -r value; then return 1 fi if [ -z "$value" ]; then SELECTED_DURATION="$DEFAULT_DURATION_SECONDS" return 0 fi if ! is_positive_decimal "$value"; then printf 'Durata non valida: usare solo un intero decimale positivo.\n' >&2 printf 'LAUNCHER_EXECUTED=NO\n' return 2 fi SELECTED_DURATION="$(normalize_decimal "$value")" return 0 } read_s03h3_profile() { local value printf '1) MINIMAL\n' printf '2) TEST\n' printf '3) DIAGNOSTIC\n' printf 'Profile: ' if ! IFS= read -r value; then return 1 fi case "$value" in 1) SELECTED_PROFILE="MINIMAL" ;; 2) SELECTED_PROFILE="TEST" ;; 3) SELECTED_PROFILE="DIAGNOSTIC" ;; *) printf 'Profilo non valido. Nessun launcher eseguito.\n' >&2 printf 'LAUNCHER_EXECUTED=NO\n' return 2 ;; esac return 0 } confirm_execution() { local answer printf '\nScenario: %s\n' "$DISPLAY_SCENARIO" printf 'Profile: %s\n' "$SELECTED_PROFILE" printf 'Duration: %s s\n\n' "$SELECTED_DURATION" printf 'Start execution? [y/N]: ' if ! IFS= read -r answer; then return 1 fi case "$answer" in y|Y) return 0 ;; *) printf 'Esecuzione annullata.\n' printf 'LAUNCHER_EXECUTED=NO\n' return 2 ;; esac } delegate_launcher() { case "$SELECTED_SCENARIO" in S01) "$STANDARD_LAUNCHER" S01 "$SELECTED_DURATION" ;; S02) "$STANDARD_LAUNCHER" S02 "$SELECTED_DURATION" ;; S03) "$STANDARD_LAUNCHER" S03 "$SELECTED_DURATION" ;; S03H3) "$S03H3_LAUNCHER" S03H3 "$SELECTED_DURATION" "$SELECTED_PROFILE" ;; *) return 125 ;; esac } read_recorded_status() { local status_file="$1" local fallback="$2" local value="" if [ -s "$status_file" ]; then IFS= read -r value <"$status_file" || value="" fi if [[ "$value" =~ ^[0-9]+$ ]]; then printf '%s' "$value" else printf '%s' "$fallback" fi } observe_run_dir() { local observed="" local observed_resolved="" local observed_parent="" local observed_name="" observed="$(sed -n 's/^RUN_DIR=//p' "$CAPTURE" | tail -n 1)" if [ -z "$observed" ]; then LAST_RUN_DIR="NOT_AVAILABLE" LAST_RUN_DIR_STATUS="NOT_AVAILABLE" elif [[ "$observed" != /* ]]; then LAST_RUN_DIR="$observed" LAST_RUN_DIR_STATUS="REPORTED_BUT_INVALID" elif [ ! -d "$observed" ]; then LAST_RUN_DIR="$observed" LAST_RUN_DIR_STATUS="REPORTED_BUT_NOT_FOUND" elif [ "$SELECTED_SCENARIO" = "S03H3" ]; then observed_resolved="$(cd -- "$observed" && pwd -P)" || observed_resolved="" observed_parent="$(dirname -- "$observed_resolved")" observed_name="$(basename -- "$observed_resolved")" if [ "$observed_parent" = "$SUITE/runs" ] && [[ "$observed_name" = *_S03H3_${SELECTED_PROFILE}_launcher ]]; then LAST_RUN_DIR="$observed_resolved" LAST_RUN_DIR_STATUS="FOUND" else LAST_RUN_DIR="$observed" LAST_RUN_DIR_STATUS="REPORTED_BUT_INVALID" fi else LAST_RUN_DIR="$observed" LAST_RUN_DIR_STATUS="FOUND" fi } print_execution_summary() { printf '\n============================================================\n' printf 'Riepilogo esecuzione S03-H3\n' printf '============================================================\n' printf 'Scenario: %s\n' "$DISPLAY_SCENARIO" printf 'Profile: %s\n' "$SELECTED_PROFILE" printf 'Duration: %s s\n' "$SELECTED_DURATION" printf 'Launcher RC: %s\n' "$LAST_LAUNCHER_RC" printf 'RUN_DIR: %s\n' "$LAST_RUN_DIR" printf 'RUN_DIR status: %s\n' "$LAST_RUN_DIR_STATUS" printf 'LAST_LAUNCHER_RC=%s\n' "$LAST_LAUNCHER_RC" printf 'RUN_DIR_STATUS=%s\n' "$LAST_RUN_DIR_STATUS" printf 'RUN_DIR=%s\n' "$LAST_RUN_DIR" printf 'MENU_RECLASSIFIES_LAUNCHER_RESULT=NO\n' } invoke_selected_launcher() { local -a pipeline_status local launcher_rc local tee_rc cleanup_temporary_files CAPTURE="$(mktemp "${TMPDIR:-/tmp}/marte_benchmark_menu.capture.XXXXXX")" || fatal_wrapper_error 71 "FAIL_CAPTURE_CREATION" \ "impossibile creare il file temporaneo di cattura" STATUS_DIR="$(mktemp -d "${TMPDIR:-/tmp}/marte_benchmark_menu.status.XXXXXX")" || { cleanup_temporary_files fatal_wrapper_error 71 "FAIL_CAPTURE_CREATION" \ "impossibile creare lo stato temporaneo della cattura" } INTERRUPT_PENDING="NO" LAUNCH_ACTIVE="YES" ( delegate_launcher launcher_rc=$? printf '%s\n' "$launcher_rc" >"$STATUS_DIR/launcher_rc" exit "$launcher_rc" ) 2>&1 | ( tee "$CAPTURE" tee_rc=$? printf '%s\n' "$tee_rc" >"$STATUS_DIR/tee_rc" exit "$tee_rc" ) pipeline_status=("${PIPESTATUS[@]}") LAUNCH_ACTIVE="NO" launcher_rc="$(read_recorded_status \ "$STATUS_DIR/launcher_rc" "${pipeline_status[0]:-125}")" tee_rc="$(read_recorded_status \ "$STATUS_DIR/tee_rc" "${pipeline_status[1]:-125}")" LAST_LAUNCHER_RC="$launcher_rc" observe_run_dir print_execution_summary if [ "$INTERRUPT_PENDING" = "YES" ]; then printf 'S03_H3_MENU_LIFECYCLE_STATUS=INTERRUPTED\n' >&2 printf 'LAUNCHER_RC_RECLASSIFIED=NO\n' >&2 cleanup_temporary_files exit 130 fi if [ "$tee_rc" -ne 0 ]; then printf 'CAPTURE_TEE_STATUS=FAIL\n' >&2 printf 'CAPTURE_TEE_RC=%s\n' "$tee_rc" >&2 printf 'S03_H3_MENU_LIFECYCLE_STATUS=FAIL_CAPTURE_TEE\n' >&2 cleanup_temporary_files exit 72 fi printf 'CAPTURE_TEE_STATUS=PASS\n' printf 'S03_H3_MENU_LIFECYCLE_STATUS=CONTINUE\n' cleanup_temporary_files } printf 'S03_H3_STARTUP_STATUS=PASS\n' printf 'S03_H3_SUITE_ROOT=%s\n' "$SUITE" printf 'S03_H3_TEST_OVERRIDE_ACTIVE=%s\n' "$OVERRIDE_ACTIVE" while true; do print_main_menu if ! IFS= read -r menu_choice; then printf '\nEOF: uscita pulita dal menu.\n' printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n' exit 0 fi SELECTED_PROFILE="N/A" case "$menu_choice" in 0) printf 'Uscita dal menu S03-H3.\n' printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_USER\n' exit 0 ;; 1) SELECTED_SCENARIO="S01" DISPLAY_SCENARIO="S01" ;; 2) SELECTED_SCENARIO="S02" DISPLAY_SCENARIO="S02" ;; 3) SELECTED_SCENARIO="S03" DISPLAY_SCENARIO="S03" ;; 4) SELECTED_SCENARIO="S03H3" DISPLAY_SCENARIO="S03-H3" ;; *) printf 'Selezione non valida. Nessun launcher eseguito.\n' >&2 printf 'LAUNCHER_EXECUTED=NO\n' continue ;; esac read_duration duration_status=$? if [ "$duration_status" -eq 1 ]; then printf '\nEOF prima dell esecuzione: azione annullata.\n' printf 'LAUNCHER_EXECUTED=NO\n' printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n' exit 0 elif [ "$duration_status" -ne 0 ]; then continue fi if [ "$SELECTED_SCENARIO" = "S03H3" ]; then read_s03h3_profile profile_status=$? if [ "$profile_status" -eq 1 ]; then printf '\nEOF prima dell esecuzione: azione annullata.\n' printf 'LAUNCHER_EXECUTED=NO\n' printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n' exit 0 elif [ "$profile_status" -ne 0 ]; then continue fi fi confirm_execution confirmation_status=$? if [ "$confirmation_status" -eq 1 ]; then printf '\nEOF prima della conferma: azione annullata.\n' printf 'LAUNCHER_EXECUTED=NO\n' printf 'S03_H3_MENU_LIFECYCLE_STATUS=EXIT_EOF\n' exit 0 elif [ "$confirmation_status" -ne 0 ]; then continue fi printf 'LAUNCHER_EXECUTED=YES\n' invoke_selected_launcher done