#!/usr/bin/env bash set -u LAUNCHER_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")" && pwd )" if [ -n "${MARTE_BENCHMARK_SUITE_ROOT:-}" ]; then SUITE="$(cd "$MARTE_BENCHMARK_SUITE_ROOT" && pwd)" else SUITE="$(cd "$LAUNCHER_DIR/.." && pwd)" fi PATCHER_S01="$SUITE/patchers/configuration/build_s01_from_s00.sh" PATCHER_S02="$SUITE/patchers/configuration/build_s02_from_s01.sh" PATCHER_S03="${MARTE_S03_PATCHER_OVERRIDE:-$SUITE/patchers/configuration/build_s03_from_s02.sh}" RUNNER="$SUITE/common/marte_runner.sh" VALIDATOR_S01="$SUITE/scenarios/S01_timing_display/validate.sh" VALIDATOR_S02="$SUITE/scenarios/S02_binary_recording/validate.sh" VALIDATOR_S03="${MARTE_S03_VALIDATOR_OVERRIDE:-$SUITE/scenarios/S03_semantic_sentinels/validate.sh}" S00_CONFIG="$SUITE/configurations/generated/S00/smoke_s0_core.marte" S01_PATCHED_CONFIG="$SUITE/configurations/generated/S01/from_patcher/smoke_s1_timing_from_s00.marte" S02_PATCHED_CONFIG="$SUITE/configurations/generated/S02/from_patcher/smoke_s2_binary_recording_from_s01.marte" S03_PATCHED_CONFIG="${MARTE_S03_CONFIG_OVERRIDE:-$SUITE/configurations/generated/S03/from_patcher/smoke_s3_semantic_sentinels_from_s02.marte}" CONSTANT_GAM_LIB_DIR="$SUITE/../MARTe2-components/Build/x86-linux/Components/GAMs/ConstantGAM" if [ -f "$SUITE/common/paths.sh" ]; then # Il file espone i percorsi canonici usati dalla suite. Il sourcing non # modifica file e permette di rispettare target e root non standard. source "$SUITE/common/paths.sh" CONSTANT_GAM_LIB_DIR="$MARTE2_COMPONENTS_ROOT/Build/$MARTE_TARGET/Components/GAMs/ConstantGAM" fi CONSTANT_GAM_LIB="$CONSTANT_GAM_LIB_DIR/ConstantGAM.so" EXPECTED_S00_SHA256="49a9b48595aab88cd8fd11d1e58ace4ab11d7d0a649e9b143bdc25c8866253d5" EXPECTED_S01_SHA256="1513e1ca72eba56d53079ac7328908f12ddc72772456e2d75bcbacb6465d2427" EXPECTED_S02_SHA256="8ecc8ba55e46e9f6fb8f304404d4070ff4c2ea5b9c783a69113bc08b457859d1" EXPECTED_S03_SHA256="0f8916735ff67a9be2b167b52f147687fe131a063f410a81bfbf3bf9ff65f1e4" DEFAULT_DURATION_SECONDS="8" S00_STATUS="NOT_CHECKED" S01_STATUS="NOT_CHECKED" S02_STATUS="NOT_CHECKED" S03_STATUS="NOT_CHECKED" S01_PATCHER_RC="NOT_RUN" S02_PATCHER_RC="NOT_RUN" S03_PATCHER_RC="NOT_RUN" print_usage() { printf "Uso:\n" printf " %s\n" "$0" printf " %s S01 [durata-secondi]\n" "$0" printf " %s S02 [durata-secondi]\n" "$0" printf " %s S03 [durata-secondi]\n" "$0" printf "\n" printf "Dipendenze automatiche:\n" printf " S01: catena S00 -> S01; esegue e valida S01.\n" printf " S02: catena S00 -> S01 -> S02; esegue e valida S02.\n" printf " S03: catena S00 -> S01 -> S02 -> S03; valida le sentinelle.\n" } fail() { code="$1" shift printf "ERRORE: %s\n" "$*" >&2 exit "$code" } check_executable() { file="$1" description="$2" if [ ! -x "$file" ]; then fail 30 "$description assente o non eseguibile: $file" fi } validate_duration() { duration="$1" case "$duration" in *[!0-9]*|"") printf "ERRORE: durata non valida: %s\n" "$duration" >&2 return 1 ;; esac if [ "$duration" -le 0 ]; then printf "ERRORE: la durata deve essere maggiore di zero.\n" >&2 return 1 fi return 0 } verify_file_hash() { file="$1" expected_hash="$2" description="$3" if [ ! -f "$file" ]; then printf "ERRORE: %s assente: %s\n" "$description" "$file" >&2 return 1 fi actual_hash="$(sha256sum -- "$file" | awk '{print $1}')" if [ "$actual_hash" != "$expected_hash" ]; then printf "ERRORE: hash inatteso per %s.\n" "$description" >&2 printf "Atteso: %s\n" "$expected_hash" >&2 printf "Reale: %s\n" "$actual_hash" >&2 printf "File: %s\n" "$file" >&2 return 1 fi printf "%s pronta: %s\n" "$description" "$file" printf "SHA-256: %s\n" "$actual_hash" return 0 } ensure_s00() { printf "\n============================================================\n" printf "DIPENDENZA S00 — CONFIGURAZIONE BASE\n" printf "============================================================\n" if ! verify_file_hash \ "$S00_CONFIG" \ "$EXPECTED_S00_SHA256" \ "Configurazione S00" then S00_STATUS="FAILED" return 50 fi S00_STATUS="READY" return 0 } ensure_s01() { ensure_s00 dependency_rc=$? if [ "$dependency_rc" -ne 0 ]; then return "$dependency_rc" fi printf "\n============================================================\n" printf "DIPENDENZA S01 — PATCH S00 -> S01\n" printf "============================================================\n" check_executable "$PATCHER_S01" "Patcher S01" timeout 10s "$PATCHER_S01" S01_PATCHER_RC=$? printf "Codice patcher S01: %s\n" "$S01_PATCHER_RC" if [ "$S01_PATCHER_RC" -ne 0 ]; then S01_STATUS="FAILED" return 51 fi if ! verify_file_hash \ "$S01_PATCHED_CONFIG" \ "$EXPECTED_S01_SHA256" \ "Configurazione S01" then S01_STATUS="FAILED" return 52 fi S01_STATUS="READY" return 0 } ensure_s02() { ensure_s01 dependency_rc=$? if [ "$dependency_rc" -ne 0 ]; then return "$dependency_rc" fi printf "\n============================================================\n" printf "DIPENDENZA S02 — PATCH S01 -> S02\n" printf "============================================================\n" check_executable "$PATCHER_S02" "Patcher S02" timeout 10s "$PATCHER_S02" S02_PATCHER_RC=$? printf "Codice patcher S02: %s\n" "$S02_PATCHER_RC" if [ "$S02_PATCHER_RC" -ne 0 ]; then S02_STATUS="FAILED" return 53 fi if ! verify_file_hash \ "$S02_PATCHED_CONFIG" \ "$EXPECTED_S02_SHA256" \ "Configurazione S02" then S02_STATUS="FAILED" return 54 fi S02_STATUS="READY" return 0 } ensure_s03() { ensure_s02 dependency_rc=$? if [ "$dependency_rc" -ne 0 ]; then return "$dependency_rc" fi printf "\n============================================================\n" printf "DIPENDENZA S03 — PATCH S02 -> S03\n" printf "============================================================\n" check_executable "$PATCHER_S03" "Patcher S03" check_executable "$VALIDATOR_S03" "Validatore S03" if [ ! -f "$CONSTANT_GAM_LIB" ]; then printf "ERRORE: libreria ConstantGAM assente: %s\n" "$CONSTANT_GAM_LIB" >&2 S03_STATUS="FAILED" return 55 fi case ":${LD_LIBRARY_PATH-}:" in *":${CONSTANT_GAM_LIB_DIR}:"*) ;; *) if [ -n "${LD_LIBRARY_PATH-}" ]; then LD_LIBRARY_PATH="${CONSTANT_GAM_LIB_DIR}:${LD_LIBRARY_PATH}" else LD_LIBRARY_PATH="$CONSTANT_GAM_LIB_DIR" fi ;; esac export LD_LIBRARY_PATH timeout 10s "$PATCHER_S03" "$S02_PATCHED_CONFIG" "$S03_PATCHED_CONFIG" S03_PATCHER_RC=$? printf "Codice patcher S03: %s\n" "$S03_PATCHER_RC" if [ "$S03_PATCHER_RC" -ne 0 ]; then S03_STATUS="FAILED" return 56 fi if ! verify_file_hash \ "$S03_PATCHED_CONFIG" \ "$EXPECTED_S03_SHA256" \ "Configurazione S03" then S03_STATUS="FAILED" return 57 fi S03_STATUS="READY" return 0 } # ------------------------------------------------------------------ # S02-H2 — lettura contrattuale di validation.txt # ------------------------------------------------------------------ # # parse_validation_field # # Richiede ESATTAMENTE una riga "NOME=VALORE" nel file indicato. # Il valore ammesso e' un token maiuscolo [A-Z][A-Z0-9_]*. # # Imposta: # PARSED_FIELD_VALUE valore letto, oppure stringa vuota # PARSED_FIELD_ERROR MISSING | DUPLICATED | MALFORMED | NO_FILE, oppure vuoto # # Ritorna 0 se e solo se il campo e' presente una sola volta e ben formato. parse_validation_field() { field_name="$1" field_file="$2" PARSED_FIELD_VALUE="" PARSED_FIELD_ERROR="" if [ ! -f "$field_file" ]; then PARSED_FIELD_ERROR="NO_FILE" return 1 fi field_occurrences="$(grep -c -- "^${field_name}=" "$field_file" || true)" if [ -z "$field_occurrences" ]; then field_occurrences=0 fi if [ "$field_occurrences" -eq 0 ]; then PARSED_FIELD_ERROR="MISSING" return 1 fi if [ "$field_occurrences" -gt 1 ]; then PARSED_FIELD_ERROR="DUPLICATED" return 1 fi field_value="$( grep -- "^${field_name}=" "$field_file" | head -n 1 | cut -d '=' -f 2- | tr -d '\r' )" case "$field_value" in ""|*[!A-Z0-9_]*) PARSED_FIELD_ERROR="MALFORMED" return 1 ;; esac case "$field_value" in [A-Z]*) ;; *) PARSED_FIELD_ERROR="MALFORMED" return 1 ;; esac PARSED_FIELD_VALUE="$field_value" return 0 } # ------------------------------------------------------------------ # classify_run # # timing_contract: # required lo scenario DEVE esporre FUNCTIONAL_STATUS e TIMING_STATUS # not_applicable lo scenario non espone stato temporale (comportamento S01) # # Imposta: # FUNCTIONAL_RESULT esito storico basato sull'exit code del validatore # PARSED_FUNCTIONAL_STATUS # PARSED_TIMING_STATUS # MEASUREMENT_ELIGIBILITY YES | NO | UNKNOWN | NOT_APPLICABLE # BLOCK_REASON NONE oppure motivo del blocco # FINAL_RESULT # FINAL_RC # ------------------------------------------------------------------ classify_run() { classify_validator_rc="$1" classify_tee_rc="$2" classify_validation_file="$3" classify_timing_contract="$4" PARSED_FUNCTIONAL_STATUS="NOT_APPLICABLE" PARSED_TIMING_STATUS="NOT_APPLICABLE" MEASUREMENT_ELIGIBILITY="NOT_APPLICABLE" BLOCK_REASON="NONE" # --- Contratto temporale: fail-closed su token sconosciuti (H2-04) --- case "$classify_timing_contract" in required|not_applicable) ;; *) FUNCTIONAL_RESULT="NOT_EVALUATED" PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED" PARSED_TIMING_STATUS="NOT_EVALUATED" MEASUREMENT_ELIGIBILITY="NO" BLOCK_REASON="TIMING_CONTRACT_UNRECOGNISED_$classify_timing_contract" FINAL_RESULT="INVALID_TIMING_CONTRACT" FINAL_RC=24 return 0 ;; esac # --- validation.txt non scritto: nessun parsing possibile --- if [ "$classify_tee_rc" -ne 0 ]; then FUNCTIONAL_RESULT="FAIL_VALIDATION_LOG" FINAL_RESULT="FAIL_VALIDATION_LOG" PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED" PARSED_TIMING_STATUS="NOT_EVALUATED" MEASUREMENT_ELIGIBILITY="NO" BLOCK_REASON="VALIDATION_LOG_NOT_WRITTEN" FINAL_RC=67 return 0 fi # --- Esito funzionale storico, dall'exit code del validatore --- case "$classify_validator_rc" in 0) FUNCTIONAL_RESULT="PASS" FINAL_RC=0 FUNCTIONAL_ESTABLISHED=1 ;; 10) FUNCTIONAL_RESULT="PASS_WITH_KNOWN_SHUTDOWN_ANOMALY" FINAL_RC=10 FUNCTIONAL_ESTABLISHED=1 ;; 11) FUNCTIONAL_RESULT="PASS_WITH_UNCLASSIFIED_SHUTDOWN_ANOMALY" FINAL_RC=11 FUNCTIONAL_ESTABLISHED=1 ;; 20|21) FUNCTIONAL_RESULT="INCONCLUSIVE" FINAL_RC=20 FUNCTIONAL_ESTABLISHED=0 ;; *) FUNCTIONAL_RESULT="FAIL_VALIDATOR" FINAL_RC=68 FUNCTIONAL_ESTABLISHED=0 ;; esac FINAL_RESULT="$FUNCTIONAL_RESULT" if [ "$classify_timing_contract" = "not_applicable" ]; then return 0 fi # ------------------------------------------------------------------ # Contratto temporale richiesto. # # H2-01: il parsing e' SEMPRE tentato quando il tee della validazione # e' riuscito, indipendentemente dall'exit code del validatore. Il # validatore H1 stampa FUNCTIONAL_STATUS e TIMING_STATUS anche prima # di uscire con 20; nasconderli sarebbe una propagazione falsa. # # La precedenza numerica resta invece all'exit code del validatore: # 20 rimane 20, 68 rimane 68. Il parsing arricchisce il riepilogo, # non riscrive un verdetto funzionale gia' emesso. # ------------------------------------------------------------------ CLASSIFY_PARSE_ERROR="NONE" if parse_validation_field "FUNCTIONAL_STATUS" "$classify_validation_file"; then PARSED_FUNCTIONAL_STATUS="$PARSED_FIELD_VALUE" else PARSED_FUNCTIONAL_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR" CLASSIFY_PARSE_ERROR="FUNCTIONAL_STATUS_$PARSED_FIELD_ERROR" fi if parse_validation_field "TIMING_STATUS" "$classify_validation_file"; then PARSED_TIMING_STATUS="$PARSED_FIELD_VALUE" else PARSED_TIMING_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR" if [ "$CLASSIFY_PARSE_ERROR" = "NONE" ]; then CLASSIFY_PARSE_ERROR="TIMING_STATUS_$PARSED_FIELD_ERROR" fi fi # --- Nessuna run puo' essere idonea a una misura prestazionale --- MEASUREMENT_ELIGIBILITY="NO" if [ "$CLASSIFY_PARSE_ERROR" != "NONE" ]; then BLOCK_REASON="$CLASSIFY_PARSE_ERROR" if [ "$FUNCTIONAL_ESTABLISHED" -eq 1 ]; then FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT" FINAL_RC=22 fi return 0 fi if [ "$FUNCTIONAL_ESTABLISHED" -eq 0 ]; then # Exit 20/21/altro: il verdetto funzionale prevale, ma i campi # realmente presenti sono comunque riportati. if [ "$PARSED_FUNCTIONAL_STATUS" = "PASS" ]; then BLOCK_REASON="FUNCTIONAL_STATUS_CONFLICT_WITH_EXIT_CODE" else BLOCK_REASON="FUNCTIONAL_STATUS_NOT_PASS" fi return 0 fi if [ "$PARSED_FUNCTIONAL_STATUS" != "PASS" ]; then BLOCK_REASON="FUNCTIONAL_STATUS_NOT_PASS" FINAL_RESULT="FUNCTIONAL_STATUS_CONFLICT" FINAL_RC=23 return 0 fi case "$PARSED_TIMING_STATUS" in NOT_VALID_*) BLOCK_REASON="$PARSED_TIMING_STATUS" FINAL_RESULT="FUNCTIONAL_PASS_TIMING_NOT_VALID" FINAL_RC=12 ;; UNASSESSED_*) MEASUREMENT_ELIGIBILITY="UNKNOWN" BLOCK_REASON="$PARSED_TIMING_STATUS" FINAL_RESULT="FUNCTIONAL_PASS_TIMING_UNASSESSED" FINAL_RC=13 ;; VALID) # H2-05: il vocabolario H1 installato non emette VALID e il # PERFORMANCE MEASUREMENT GATE completo non esiste ancora. # H2 non autorizza mai da solo l'idoneita' prestazionale. BLOCK_REASON="TIMING_STATUS_VALID_NOT_YET_CONTRACTED" FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT" FINAL_RC=22 ;; *) BLOCK_REASON="TIMING_STATUS_UNRECOGNISED_$PARSED_TIMING_STATUS" FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT" FINAL_RC=22 ;; esac return 0 } # ------------------------------------------------------------------ # S03 — contratto funzionale, semantico e temporale separato. # # Exit code candidati (non installati): # 14 funzionalita' e semantica PASS, timing non valido # 15 funzionalita' e semantica PASS, timing non valutato # 20 validatore inconcludente o input mancante # 22 contratto S03 non interpretabile / timing VALID non autorizzato # 23 conflitto FUNCTIONAL_STATUS # 25 conflitto SEMANTIC_STATUS # 67 validation.txt non scritto # 68 exit code validatore non riconosciuto # 69 launcher_summary.txt non scritto # ------------------------------------------------------------------ classify_s03_run() { classify_validator_rc="$1" classify_tee_rc="$2" classify_validation_file="$3" PARSED_FUNCTIONAL_STATUS="NOT_EVALUATED" PARSED_SEMANTIC_STATUS="NOT_EVALUATED" PARSED_TIMING_STATUS="NOT_EVALUATED" PARSED_VALIDATOR_ELIGIBILITY="NOT_EVALUATED" MEASUREMENT_ELIGIBILITY="NO" BLOCK_REASON="NONE" if [ "$classify_tee_rc" -ne 0 ]; then FUNCTIONAL_RESULT="FAIL_VALIDATION_LOG" FINAL_RESULT="FAIL_VALIDATION_LOG" BLOCK_REASON="VALIDATION_LOG_NOT_WRITTEN" FINAL_RC=67 return 0 fi case "$classify_validator_rc" in 0) FUNCTIONAL_RESULT="PASS" FUNCTIONAL_ESTABLISHED=1 FINAL_RC=0 ;; 10) FUNCTIONAL_RESULT="PASS_WITH_KNOWN_SHUTDOWN_ANOMALY" FUNCTIONAL_ESTABLISHED=1 FINAL_RC=10 ;; 11) FUNCTIONAL_RESULT="PASS_WITH_UNCLASSIFIED_SHUTDOWN_ANOMALY" FUNCTIONAL_ESTABLISHED=1 FINAL_RC=11 ;; 20|21) FUNCTIONAL_RESULT="INCONCLUSIVE" FUNCTIONAL_ESTABLISHED=0 FINAL_RC=20 ;; *) FUNCTIONAL_RESULT="FAIL_VALIDATOR" FUNCTIONAL_ESTABLISHED=0 FINAL_RC=68 ;; esac FINAL_RESULT="$FUNCTIONAL_RESULT" S03_PARSE_ERROR="NONE" for field_name in \ FUNCTIONAL_STATUS \ SEMANTIC_STATUS \ TIMING_STATUS \ MEASUREMENT_ELIGIBILITY do if parse_validation_field "$field_name" "$classify_validation_file"; then case "$field_name" in FUNCTIONAL_STATUS) PARSED_FUNCTIONAL_STATUS="$PARSED_FIELD_VALUE" ;; SEMANTIC_STATUS) PARSED_SEMANTIC_STATUS="$PARSED_FIELD_VALUE" ;; TIMING_STATUS) PARSED_TIMING_STATUS="$PARSED_FIELD_VALUE" ;; MEASUREMENT_ELIGIBILITY) PARSED_VALIDATOR_ELIGIBILITY="$PARSED_FIELD_VALUE" ;; esac else case "$field_name" in FUNCTIONAL_STATUS) PARSED_FUNCTIONAL_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR" ;; SEMANTIC_STATUS) PARSED_SEMANTIC_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR" ;; TIMING_STATUS) PARSED_TIMING_STATUS="PARSE_ERROR_$PARSED_FIELD_ERROR" ;; MEASUREMENT_ELIGIBILITY) PARSED_VALIDATOR_ELIGIBILITY="PARSE_ERROR_$PARSED_FIELD_ERROR" ;; esac if [ "$S03_PARSE_ERROR" = "NONE" ]; then S03_PARSE_ERROR="${field_name}_$PARSED_FIELD_ERROR" fi fi done if [ "$S03_PARSE_ERROR" != "NONE" ]; then BLOCK_REASON="$S03_PARSE_ERROR" FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT" if [ "$FUNCTIONAL_ESTABLISHED" -eq 1 ]; then FINAL_RC=22 fi return 0 fi case "$PARSED_FUNCTIONAL_STATUS" in PASS|NOT_DEMONSTRATED) ;; *) BLOCK_REASON="FUNCTIONAL_STATUS_UNRECOGNISED_$PARSED_FUNCTIONAL_STATUS" FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT" FINAL_RC=22 return 0 ;; esac case "$PARSED_SEMANTIC_STATUS" in PASS|FAIL|NOT_DEMONSTRATED) ;; *) BLOCK_REASON="SEMANTIC_STATUS_UNRECOGNISED_$PARSED_SEMANTIC_STATUS" FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT" FINAL_RC=22 return 0 ;; esac if [ "$PARSED_VALIDATOR_ELIGIBILITY" != "NO" ]; then BLOCK_REASON="ELIGIBILITY_CONTRACT_VIOLATION_$PARSED_VALIDATOR_ELIGIBILITY" FINAL_RESULT="INCONCLUSIVE_S03_CONTRACT" FINAL_RC=22 return 0 fi if [ "$FUNCTIONAL_ESTABLISHED" -eq 0 ]; then if [ "$PARSED_FUNCTIONAL_STATUS" != "PASS" ]; then BLOCK_REASON="FUNCTIONAL_STATUS_NOT_PASS" elif [ "$PARSED_SEMANTIC_STATUS" != "PASS" ]; then BLOCK_REASON="SEMANTIC_STATUS_$PARSED_SEMANTIC_STATUS" else BLOCK_REASON="VALIDATOR_EXIT_NOT_PASS" fi FINAL_RESULT="S03_VALIDATION_INCONCLUSIVE" return 0 fi if [ "$PARSED_FUNCTIONAL_STATUS" != "PASS" ]; then BLOCK_REASON="FUNCTIONAL_STATUS_CONFLICT_WITH_EXIT_CODE" FINAL_RESULT="FUNCTIONAL_STATUS_CONFLICT" FINAL_RC=23 return 0 fi if [ "$PARSED_SEMANTIC_STATUS" != "PASS" ]; then BLOCK_REASON="SEMANTIC_STATUS_CONFLICT_$PARSED_SEMANTIC_STATUS" FINAL_RESULT="SEMANTIC_STATUS_CONFLICT" FINAL_RC=25 return 0 fi case "$PARSED_TIMING_STATUS" in NOT_VALID_*) BLOCK_REASON="$PARSED_TIMING_STATUS" FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_NOT_VALID" FINAL_RC=14 ;; UNASSESSED_*) BLOCK_REASON="$PARSED_TIMING_STATUS" FINAL_RESULT="FUNCTIONAL_AND_SEMANTIC_PASS_TIMING_UNASSESSED" FINAL_RC=15 ;; VALID) BLOCK_REASON="TIMING_STATUS_VALID_NOT_YET_CONTRACTED" FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT" FINAL_RC=22 ;; NOT_EVALUATED) BLOCK_REASON="TIMING_STATUS_NOT_EVALUATED" FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT" FINAL_RC=22 ;; *) BLOCK_REASON="TIMING_STATUS_UNRECOGNISED_$PARSED_TIMING_STATUS" FINAL_RESULT="INCONCLUSIVE_TIMING_CONTRACT" FINAL_RC=22 ;; esac return 0 } emit_s03_summary() { summary_destination="$1" { printf "============================================================\n" printf "RIEPILOGO LAUNCHER S03 CANDIDATO\n" printf "============================================================\n" printf "Scenario: S03\n" printf "Durata: %s secondi\n" "${duration:-NOT_AVAILABLE}" printf "Catena dipendenze: S00 -> S01 -> S02 -> S03\n" printf "Stato S00: %s\n" "$S00_STATUS" printf "Stato S01: %s\n" "$S01_STATUS" printf "Stato S02: %s\n" "$S02_STATUS" printf "Stato S03: %s\n" "$S03_STATUS" printf "Codice patcher S01: %s\n" "$S01_PATCHER_RC" printf "Codice patcher S02: %s\n" "$S02_PATCHER_RC" printf "Codice patcher S03: %s\n" "$S03_PATCHER_RC" printf "Configurazione: %s\n" "${S03_PATCHED_CONFIG:-NOT_AVAILABLE}" printf "Run directory: %s\n" "${RUN_DIR:-NOT_AVAILABLE}" printf "Run log: %s\n" "${RUN_LOG:-NOT_AVAILABLE}" printf "Validazione: %s\n" "${VALIDATION_LOG:-NOT_AVAILABLE}" printf "Codice runner: %s\n" "${RUNNER_RC:-NOT_AVAILABLE}" printf "Codice validatore: %s\n" "${VALIDATOR_RC:-NOT_AVAILABLE}" printf "Esito storico validatore: %s\n" "${FUNCTIONAL_RESULT:-NOT_AVAILABLE}" printf "FUNCTIONAL_STATUS=%s\n" "$PARSED_FUNCTIONAL_STATUS" printf "SEMANTIC_STATUS=%s\n" "$PARSED_SEMANTIC_STATUS" printf "TIMING_STATUS=%s\n" "$PARSED_TIMING_STATUS" printf "MEASUREMENT_ELIGIBILITY=%s\n" "$MEASUREMENT_ELIGIBILITY" printf "BLOCK_REASON=%s\n" "$BLOCK_REASON" printf "FINAL_RESULT=%s\n" "$FINAL_RESULT" printf "FINAL_RC=%s\n" "$FINAL_RC" } | tee "$summary_destination" summary_codes=("${PIPESTATUS[@]}") if [ "${summary_codes[1]}" -ne 0 ]; then return 69 fi return 0 } run_prepared_s03() { duration="$1" check_executable "$RUNNER" "Common runner" check_executable "$VALIDATOR_S03" "Validatore S03" CAPTURE="$(mktemp "${TMPDIR:-/tmp}/marte_benchmark_launcher_s03.XXXXXX")" || return 60 trap 'rm -f -- "$CAPTURE"' EXIT HUP INT TERM printf "\n============================================================\n" printf "ESECUZIONE COMMON RUNNER — S03\n" printf "============================================================\n" "$RUNNER" \ "S03_launcher" \ "$S03_PATCHED_CONFIG" \ "State1" \ "$duration" \ 2>&1 | tee "$CAPTURE" RUNNER_CODES=("${PIPESTATUS[@]}") RUNNER_RC="${RUNNER_CODES[0]}" CAPTURE_TEE_RC="${RUNNER_CODES[1]}" if [ "$RUNNER_RC" -ne 0 ]; then printf "RISULTATO FINALE: FAIL_RUNNER\n" return 61 fi if [ "$CAPTURE_TEE_RC" -ne 0 ]; then printf "RISULTATO FINALE: FAIL_LAUNCHER_LOG\n" return 62 fi RUN_DIR="$(sed -n 's/^RUN_DIR=//p' "$CAPTURE" | tail -n 1)" if [ -z "$RUN_DIR" ]; then printf "ERRORE: RUN_DIR non individuata.\n" >&2 return 63 fi if [ ! -d "$RUN_DIR" ]; then printf "ERRORE: directory di run assente: %s\n" "$RUN_DIR" >&2 return 64 fi RUN_LOG="$RUN_DIR/run.log" VALIDATION_LOG="$RUN_DIR/validation.txt" LAUNCHER_SUMMARY="$RUN_DIR/launcher_summary.txt" if [ ! -f "$RUN_LOG" ]; then printf "ERRORE: run.log assente: %s\n" "$RUN_LOG" >&2 return 65 fi printf "\n============================================================\n" printf "VALIDAZIONE S03\n" printf "============================================================\n" timeout 20s "$VALIDATOR_S03" "$RUN_DIR" 2>&1 | tee "$VALIDATION_LOG" VALIDATION_CODES=("${PIPESTATUS[@]}") VALIDATOR_RC="${VALIDATION_CODES[0]}" VALIDATION_TEE_RC="${VALIDATION_CODES[1]}" classify_s03_run "$VALIDATOR_RC" "$VALIDATION_TEE_RC" "$VALIDATION_LOG" if ! emit_s03_summary "$LAUNCHER_SUMMARY"; then FINAL_RESULT="FAIL_LAUNCHER_SUMMARY" FINAL_RC=69 printf "ERRORE: riepilogo launcher S03 non scritto: %s\n" \ "$LAUNCHER_SUMMARY" >&2 fi printf "\nRISULTATO FINALE: %s\n" "$FINAL_RESULT" printf "Riepilogo: %s\n" "$LAUNCHER_SUMMARY" rm -f -- "$CAPTURE" trap - EXIT HUP INT TERM return "$FINAL_RC" } run_prepared_scenario() { scenario_name="$1" scenario_id="$2" config_file="$3" validator="$4" validator_input_mode="$5" duration="$6" dependency_chain="$7" timing_contract="$8" check_executable "$RUNNER" "Common runner" check_executable "$validator" "Validatore $scenario_name" CAPTURE="$( mktemp "${TMPDIR:-/tmp}/marte_benchmark_launcher.XXXXXX" )" || return 60 trap 'rm -f "$CAPTURE"' EXIT HUP INT TERM printf "\n============================================================\n" printf "ESECUZIONE COMMON RUNNER — %s\n" "$scenario_name" printf "============================================================\n" "$RUNNER" \ "${scenario_id}_launcher" \ "$config_file" \ "State1" \ "$duration" \ 2>&1 | tee "$CAPTURE" RUNNER_CODES=("${PIPESTATUS[@]}") RUNNER_RC="${RUNNER_CODES[0]}" CAPTURE_TEE_RC="${RUNNER_CODES[1]}" printf "\nCodice common runner: %s\n" "$RUNNER_RC" printf "Codice tee launcher: %s\n" "$CAPTURE_TEE_RC" if [ "$RUNNER_RC" -ne 0 ]; then printf "RISULTATO FINALE: FAIL_RUNNER\n" return 61 fi if [ "$CAPTURE_TEE_RC" -ne 0 ]; then printf "RISULTATO FINALE: FAIL_LAUNCHER_LOG\n" return 62 fi RUN_DIR="$( sed -n 's/^RUN_DIR=//p' "$CAPTURE" | tail -n 1 )" if [ -z "$RUN_DIR" ]; then printf "ERRORE: RUN_DIR non individuata.\n" >&2 return 63 fi if [ ! -d "$RUN_DIR" ]; then printf "ERRORE: directory di run assente: %s\n" "$RUN_DIR" >&2 return 64 fi RUN_LOG="$RUN_DIR/run.log" VALIDATION_LOG="$RUN_DIR/validation.txt" LAUNCHER_SUMMARY="$RUN_DIR/launcher_summary.txt" if [ ! -f "$RUN_LOG" ]; then printf "ERRORE: run.log assente: %s\n" "$RUN_LOG" >&2 return 65 fi case "$validator_input_mode" in run_log) VALIDATOR_INPUT="$RUN_LOG" ;; run_dir) VALIDATOR_INPUT="$RUN_DIR" ;; *) printf "ERRORE: modalità input validatore non riconosciuta: %s\n" \ "$validator_input_mode" >&2 return 66 ;; esac printf "\n============================================================\n" printf "VALIDAZIONE %s\n" "$scenario_name" printf "============================================================\n" timeout 15s "$validator" "$VALIDATOR_INPUT" 2>&1 | tee "$VALIDATION_LOG" VALIDATION_CODES=("${PIPESTATUS[@]}") VALIDATOR_RC="${VALIDATION_CODES[0]}" VALIDATION_TEE_RC="${VALIDATION_CODES[1]}" classify_run \ "$VALIDATOR_RC" \ "$VALIDATION_TEE_RC" \ "$VALIDATION_LOG" \ "$timing_contract" { printf "============================================================\n" printf "RIEPILOGO LAUNCHER\n" printf "============================================================\n" printf "Scenario: %s\n" "$scenario_name" printf "Durata: %s secondi\n" "$duration" printf "Catena dipendenze: %s\n" "$dependency_chain" printf "Stato S00: %s\n" "$S00_STATUS" printf "Stato S01: %s\n" "$S01_STATUS" printf "Stato S02: %s\n" "$S02_STATUS" printf "Codice patcher S01: %s\n" "$S01_PATCHER_RC" printf "Codice patcher S02: %s\n" "$S02_PATCHER_RC" printf "Configurazione: %s\n" "$config_file" printf "Run directory: %s\n" "$RUN_DIR" printf "Run log: %s\n" "$RUN_LOG" printf "Validazione: %s\n" "$VALIDATION_LOG" printf "Codice runner: %s\n" "$RUNNER_RC" printf "Codice validatore: %s\n" "$VALIDATOR_RC" printf "Esito funzionale: %s\n" "$FUNCTIONAL_RESULT" printf "FUNCTIONAL_STATUS: %s\n" "$PARSED_FUNCTIONAL_STATUS" printf "TIMING_STATUS: %s\n" "$PARSED_TIMING_STATUS" printf "MEASUREMENT_ELIGIBILITY: %s\n" "$MEASUREMENT_ELIGIBILITY" printf "Motivo blocco: %s\n" "$BLOCK_REASON" printf "Codice finale launcher: %s\n" "$FINAL_RC" printf "Risultato finale: %s\n" "$FINAL_RESULT" } | tee "$LAUNCHER_SUMMARY" SUMMARY_CODES=("${PIPESTATUS[@]}") SUMMARY_TEE_RC="${SUMMARY_CODES[1]}" # H2-06: il riepilogo e' il documento che porta il nuovo contratto. # Se non e' stato scritto, il risultato non e' verificabile a posteriori # e non puo' essere presentato come esito valido. if [ "$SUMMARY_TEE_RC" -ne 0 ]; then printf "ERRORE: riepilogo launcher non scritto: %s\n" \ "$LAUNCHER_SUMMARY" >&2 FINAL_RESULT="FAIL_LAUNCHER_SUMMARY" FINAL_RC=69 fi printf "\nRISULTATO FINALE: %s\n" "$FINAL_RESULT" printf "Riepilogo: %s\n" "$LAUNCHER_SUMMARY" rm -f -- "$CAPTURE" trap - EXIT HUP INT TERM return "$FINAL_RC" } run_s01() { duration="$1" if ! validate_duration "$duration"; then return 31 fi S00_STATUS="NOT_CHECKED" S01_STATUS="NOT_CHECKED" S02_STATUS="NOT_REQUIRED" S03_STATUS="NOT_REQUIRED" S01_PATCHER_RC="NOT_RUN" S02_PATCHER_RC="NOT_REQUIRED" S03_PATCHER_RC="NOT_REQUIRED" printf "============================================================\n" printf "SCENARIO S01 — TIMING DISPLAY\n" printf "============================================================\n" printf "Durata: %s secondi\n" "$duration" printf "Catena automatica: S00 -> S01\n" ensure_s01 PREPARE_RC=$? if [ "$PREPARE_RC" -ne 0 ]; then printf "RISULTATO FINALE: FAIL_DEPENDENCY_CHAIN\n" return "$PREPARE_RC" fi run_prepared_scenario \ "S01" \ "S01" \ "$S01_PATCHED_CONFIG" \ "$VALIDATOR_S01" \ "run_log" \ "$duration" \ "S00 -> S01" \ "not_applicable" } run_s02() { duration="$1" if ! validate_duration "$duration"; then return 31 fi S00_STATUS="NOT_CHECKED" S01_STATUS="NOT_CHECKED" S02_STATUS="NOT_CHECKED" S03_STATUS="NOT_REQUIRED" S01_PATCHER_RC="NOT_RUN" S02_PATCHER_RC="NOT_RUN" S03_PATCHER_RC="NOT_REQUIRED" printf "============================================================\n" printf "SCENARIO S02 — BINARY RECORDING\n" printf "============================================================\n" printf "Durata: %s secondi\n" "$duration" printf "Catena automatica: S00 -> S01 -> S02\n" ensure_s02 PREPARE_RC=$? if [ "$PREPARE_RC" -ne 0 ]; then printf "RISULTATO FINALE: FAIL_DEPENDENCY_CHAIN\n" return "$PREPARE_RC" fi run_prepared_scenario \ "S02" \ "S02" \ "$S02_PATCHED_CONFIG" \ "$VALIDATOR_S02" \ "run_dir" \ "$duration" \ "S00 -> S01 -> S02" \ "required" } run_s03() { duration="$1" if ! validate_duration "$duration"; then return 31 fi S00_STATUS="NOT_CHECKED" S01_STATUS="NOT_CHECKED" S02_STATUS="NOT_CHECKED" S03_STATUS="NOT_CHECKED" S01_PATCHER_RC="NOT_RUN" S02_PATCHER_RC="NOT_RUN" S03_PATCHER_RC="NOT_RUN" printf "============================================================\n" printf "SCENARIO S03 — SENTINELLE E VALIDAZIONE SEMANTICA\n" printf "============================================================\n" printf "Durata: %s secondi\n" "$duration" printf "Catena automatica: S00 -> S01 -> S02 -> S03\n" printf "Gate prestazionale: CHIUSO\n" ensure_s03 PREPARE_RC=$? if [ "$PREPARE_RC" -ne 0 ]; then printf "RISULTATO FINALE: FAIL_DEPENDENCY_CHAIN\n" return "$PREPARE_RC" fi run_prepared_s03 "$duration" } ask_duration_and_run() { scenario="$1" printf "Durata in secondi [%s]: " "$DEFAULT_DURATION_SECONDS" if ! IFS= read -r duration; then printf "\nERRORE: input non disponibile.\n" >&2 return 2 fi if [ -z "$duration" ]; then duration="$DEFAULT_DURATION_SECONDS" fi case "$scenario" in S01) run_s01 "$duration" ;; S02) run_s02 "$duration" ;; S03) run_s03 "$duration" ;; *) printf "ERRORE: scenario interno non riconosciuto: %s\n" "$scenario" >&2 return 2 ;; esac } interactive_menu() { printf "============================================================\n" printf "MARTe2 BENCHMARK SUITE\n" printf "============================================================\n" printf "1) S01 — catena automatica S00 -> S01, esegue e valida CycleTime\n" printf "2) S02 — catena automatica S00 -> S01 -> S02, registra e valida il binario\n" printf "3) S03 — catena S00 -> S01 -> S02 -> S03, valida le sentinelle\n" printf "0) Esci\n" printf "\nSelezione: " if ! IFS= read -r selection; then printf "\nERRORE: input non disponibile.\n" >&2 return 2 fi case "$selection" in 1|S01|s01) ask_duration_and_run "S01" ;; 2|S02|s02) ask_duration_and_run "S02" ;; 3|S03|s03) ask_duration_and_run "S03" ;; 0) printf "Uscita.\n" return 0 ;; *) printf "Selezione non valida: %s\n" "$selection" >&2 return 2 ;; esac } # S02-H2: consente di caricare le sole funzioni (per i test) senza # eseguire il menu interattivo o il dispatch degli argomenti. # # La modalita' e' accettata SOLTANTO quando il file viene caricato con # "source". Se il launcher viene eseguito direttamente con la variabile # impostata, deve fallire in modo esplicito: un exit 0 senza avere # eseguito alcuna run sarebbe un falso successo. if [ "${MARTE_LAUNCHER_LIB_ONLY:-0}" = "1" ]; then if [ "${BASH_SOURCE[0]}" != "$0" ]; then return 0 fi printf "ERRORE: MARTE_LAUNCHER_LIB_ONLY=1 e' ammesso solo con 'source'.\n" >&2 printf "Il launcher e' stato eseguito direttamente: nessuna run avviata.\n" >&2 exit 3 fi case "$#" in 0) interactive_menu exit $? ;; 1) case "$1" in S01|s01) run_s01 "$DEFAULT_DURATION_SECONDS" exit $? ;; S02|s02) run_s02 "$DEFAULT_DURATION_SECONDS" exit $? ;; S03|s03) run_s03 "$DEFAULT_DURATION_SECONDS" exit $? ;; -h|--help) print_usage exit 0 ;; *) print_usage >&2 exit 2 ;; esac ;; 2) case "$1" in S01|s01) run_s01 "$2" exit $? ;; S02|s02) run_s02 "$2" exit $? ;; S03|s03) run_s03 "$2" exit $? ;; *) print_usage >&2 exit 2 ;; esac ;; *) print_usage >&2 exit 2 ;; esac