/****************************************************************************** * Copyright (c) 2000-2021 Ericsson Telecom AB * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v2.0 * which accompanies this distribution, and is available at * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html * * Contributors: * Baji, Laszlo * Balasko, Jeno * Beres, Szabolcs * Delic, Adam * Feher, Csaba * Kovacs, Ferenc * Lovassy, Arpad * Raduly, Csaba * Szabados, Kristof * Szabo, Janos Zoltan – initial implementation * Szalai, Gabor * Zalanyi, Balazs Andor * Pandi, Krisztian * ******************************************************************************/ #include #include #include #include #include #include "../common/dbgnew.hh" #include "../common/version_internal.h" #include "Logger.hh" #include "Snapshot.hh" #include "Port.hh" #include "Module_list.hh" #include "Runtime.hh" #include "Component.hh" #include "Encdec.hh" #include "TitanLoggerApi.hh" #include "TCov.hh" #if defined(LINUX) && !defined(ALPINE_LINUX) #include #endif #ifdef LICENSE #include "../common/license.h" #endif #include const char * stored_argv = "Unidentified program"; static const char segfault[] = ": Segmentation fault occurred\n"; static const char abortcall[] = ": Abort was called\n"; void signal_handler(int signum) { int retval; retval = write(STDERR_FILENO, stored_argv, strlen(stored_argv)); if(signum==SIGSEGV){ retval = write(STDERR_FILENO, segfault , sizeof(segfault)-1); // sizeof includes \0 } else { retval = write(STDERR_FILENO, abortcall , sizeof(abortcall)-1); // sizeof includes \0 } #if defined(LINUX) && !defined(ALPINE_LINUX) int nptrs; void *buffer[100]; nptrs = backtrace(buffer, 100); backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); fflush(stderr); #endif (void)retval; TTCN_Logger::close_file(); signal(SIGABRT, SIG_DFL); abort(); } static void usage(const char* program_name) { fprintf(stderr, "\n" "usage: %s [-h] [-b file] configuration_file\n" " or %s -l\n" " or %s -p\n" " or %s -v\n" "\n" "OPTIONS:\n" " -b file: run specified batch file at start (debugger must be activated)\n" " -h: automatically halt execution at start (debugger must be activated)\n" " -l: list startable test cases and control parts\n" " -p: list module parameters\n" " -v: show version and module information\n", program_name, program_name, program_name, program_name); } int main(int argc, char *argv[]) { stored_argv = argv[0]; struct sigaction act; act.sa_handler = signal_handler; sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGSEGV, &act, 0); sigaction(SIGABRT, &act, 0); #ifdef MEMORY_DEBUG debug_new_counter.set_program_name(argv[0]); #endif errno = 0; int c, i, ret_val = EXIT_SUCCESS; boolean bflag = FALSE, hflag = FALSE, lflag = FALSE, vflag = FALSE, pflag = FALSE, errflag = FALSE; const char *config_file = NULL; TTCN_Module *only_runnable = Module_List::single_control_part(); while ((c = getopt(argc, argv, "b:hlvp")) != -1) { switch (c) { case 'b': if (bflag || lflag || vflag || pflag) errflag = TRUE; // duplicate or conflicting else { bflag = TRUE; ttcn3_debugger.set_initial_batch_file(optarg); } break; case 'h': if (hflag || lflag || vflag || pflag) errflag = TRUE; // duplicate or conflicting else { hflag = TRUE; ttcn3_debugger.set_halt_at_start(); } break; case 'l': if (lflag || vflag || pflag || bflag || hflag) errflag = TRUE; // duplicate or conflicting else lflag = TRUE; break; case 'p': if (pflag || lflag || vflag || bflag || hflag) errflag = TRUE; // duplicate or conflicting else pflag = TRUE; break; case 'v': if (lflag || vflag || pflag || bflag || hflag) errflag = TRUE; // duplicate or conflicting else vflag = TRUE; break; default: errflag = TRUE; } } if (!errflag) { if (lflag || vflag || pflag) { if (optind != argc) errflag = TRUE; // -l, -p or -v and non-option arg } else { if (optind > argc - 1) { // no config file argument errflag = (only_runnable == 0); } else config_file = argv[optind]; } } if (errflag) { if (argc == 1) fputs("TTCN-3 Test Executor (single mode), version " PRODUCT_NUMBER "\n", stderr); usage(argv[0]); TCov::close_file(); return EXIT_FAILURE; } else if (lflag || pflag) { try { // create buffer for error messages TTCN_Logger::initialize_logger(); Module_List::pre_init_modules(); if (lflag) { Module_List::list_testcases(); } else { // pflag Module_List::list_modulepars(); } } catch (...) { ret_val = EXIT_FAILURE; } TTCN_Logger::terminate_logger(); TCov::close_file(); return ret_val; } else if (vflag) { fputs("TTCN-3 Test Executor (single mode)\n" "Version: " VERSION_STRING "\n" "Build date (Base Library): " __DATE__ " " __TIME__ "\n" "Base Library was compiled with: " C_COMPILER_VERSION "\n\n" COPYRIGHT_STRING "\n\n", stderr); #ifdef LICENSE print_license_info(); putc('\n', stderr); #endif fputs("Module information:\n", stderr); Module_List::print_version(); TCov::close_file(); return EXIT_SUCCESS; } fputs("TTCN-3 Test Executor (single mode), version " PRODUCT_NUMBER "\n", stderr); #ifdef LICENSE init_openssl(); license_struct lstr; load_license(&lstr); if (!verify_license(&lstr)) { free_license(&lstr); free_openssl(); exit(EXIT_FAILURE); } if (!check_feature(&lstr, FEATURE_SINGLE)) { fputs("The license key does not allow test execution in single mode.\n", stderr); TCov::close_file(); return EXIT_FAILURE; } free_license(&lstr); free_openssl(); #endif self = MTC_COMPREF; TTCN_Runtime::set_state(TTCN_Runtime::SINGLE_CONTROLPART); TTCN_Runtime::install_signal_handlers(); TTCN_Snapshot::initialize(); TTCN_Logger::initialize_logger(); TTCN_Logger::set_executable_name(argv[0]); TTCN_Logger::set_start_time(); try { TTCN_Logger::log_executor_runtime( TitanLoggerApi::ExecutorRuntime_reason::executor__start__single__mode); Module_List::pre_init_modules(); if (config_file != 0) { fprintf(stderr, "Using configuration file: `%s'\n", config_file); TTCN_Logger::log_configdata( TitanLoggerApi::ExecutorConfigdata_reason::using__config__file, config_file); } TTCN_Snapshot::check_fd_setsize(); boolean config_file_failure = config_file && !process_config_file(config_file); TTCN_Runtime::load_logger_plugins(); // Quick return if no config file. TTCN_Runtime::set_logger_parameters(); TTCN_Logger::open_file(); TTCN_Logger::write_logger_settings(); if (config_file_failure) goto fail; // Config file parsed or no config file: we may be able to run. if (config_file) { if (++optind != argc) { // There are further commandline arguments after config file. // Override testcase list. // First, throw away the old list parsed from the config file. for (i = 0; i < execute_list_len; i++) { Free(execute_list[i].module_name); Free(execute_list[i].testcase_name); } // The new execute list length is known in advance. execute_list_len = argc - optind; execute_list = (execute_list_item *)Realloc( execute_list, execute_list_len * sizeof(*execute_list)); expstring_t testcase_names = memptystr(); // collects names for printout for (i = optind; i < argc; ++i) { testcase_names = mputstr(testcase_names, argv[i]); testcase_names = mputc(testcase_names, '\t'); char *dot = strchr(argv[i], '.'); if (dot != 0) { *dot++ = '\0'; // cut the string into two if (!strcmp(dot, "control")) dot = 0; } execute_list[i-optind].module_name = mcopystr(argv[i]); execute_list[i-optind].testcase_name = dot ? mcopystr(dot) : dot; // do not copy NULL pointer, it results in non-0 empty string } // next i fprintf(stderr, "Overriding testcase list: %s\n", testcase_names); TTCN_Logger::log_configdata( TitanLoggerApi::ExecutorConfigdata_reason::overriding__testcase__list, testcase_names); Free(testcase_names); } } if (execute_list_len == 0 && only_runnable) { // No config file or correct config file without EXECUTE section, // AND precisely one control part: run that one. execute_list_len = 1; execute_list = (execute_list_item *)Malloc(sizeof(*execute_list)); execute_list[0].module_name = mcopystr(only_runnable->get_name()); execute_list[0].testcase_name = 0; // control part } if (execute_list_len > 0) { // we have something to run Module_List::log_param(); Module_List::post_init_modules(); for (i = 0; i < execute_list_len; i++) { if (ttcn3_debugger.is_exiting()) { break; } if (execute_list[i].testcase_name == NULL) Module_List::execute_control(execute_list[i].module_name); else if (!strcmp(execute_list[i].testcase_name, "*")) Module_List::execute_all_testcases( execute_list[i].module_name); else Module_List::execute_testcase(execute_list[i].module_name, execute_list[i].testcase_name); } } else { TTCN_warning("Nothing to run!"); fail: ret_val = EXIT_FAILURE; } } catch (...) { TTCN_Logger::log_str(TTCN_Logger::ERROR_UNQUALIFIED, "Fatal error. Aborting execution."); ret_val = EXIT_FAILURE; } TTCN_Runtime::restore_signal_handlers(); TTCN_Runtime::log_verdict_statistics(); TTCN_Logger::log_executor_runtime( TitanLoggerApi::ExecutorRuntime_reason::executor__finish__single__mode); TTCN_Logger::close_file(); TCov::close_file(); // close_file() must be called before the information is lost // close_file() WRITES to log TTCN_Logger::clear_parameters(); PORT::clear_parameters(); COMPONENT::clear_component_names(); TTCN_EncDec::clear_error(); for (i = 0; i < execute_list_len; i++) { Free(execute_list[i].module_name); Free(execute_list[i].testcase_name); } Free(execute_list); TTCN_Logger::terminate_logger(); TTCN_Snapshot::terminate(); TTCN_Runtime::clean_up(); return ret_val; }