Commit | Line | Data |
---|---|---|
d44e3c4f | 1 | /****************************************************************************** |
2 | * Copyright (c) 2000-2016 Ericsson Telecom AB | |
3 | * All rights reserved. This program and the accompanying materials | |
4 | * are made available under the terms of the Eclipse Public License v1.0 | |
5 | * which accompanies this distribution, and is available at | |
6 | * http://www.eclipse.org/legal/epl-v10.html | |
7 | * | |
8 | * Contributors: | |
9 | * Baji, Laszlo | |
10 | * Balasko, Jeno | |
11 | * Beres, Szabolcs | |
12 | * Delic, Adam | |
13 | * Feher, Csaba | |
14 | * Kovacs, Ferenc | |
15 | * Lovassy, Arpad | |
16 | * Raduly, Csaba | |
17 | * Szabados, Kristof | |
18 | * Szabo, Janos Zoltan – initial implementation | |
19 | * Szalai, Gabor | |
20 | * Zalanyi, Balazs Andor | |
21 | * Pandi, Krisztian | |
22 | * | |
23 | ******************************************************************************/ | |
970ed795 EL |
24 | #include <stdio.h> |
25 | #include <stdlib.h> | |
26 | #include <string.h> | |
27 | #include <errno.h> | |
28 | #include <unistd.h> | |
29 | ||
30 | #include "../common/dbgnew.hh" | |
31 | #include "../common/version_internal.h" | |
32 | #include "Logger.hh" | |
33 | #include "Snapshot.hh" | |
34 | #include "Port.hh" | |
35 | #include "Module_list.hh" | |
36 | #include "Runtime.hh" | |
37 | #include "Component.hh" | |
38 | #include "Encdec.hh" | |
39 | #include "TitanLoggerApi.hh" | |
40 | #include "TCov.hh" | |
a38c6d4c | 41 | #ifdef LINUX |
42 | #include <execinfo.h> | |
43 | #endif | |
970ed795 EL |
44 | |
45 | #ifdef LICENSE | |
46 | #include "../common/license.h" | |
47 | #endif | |
48 | ||
49 | #include <signal.h> | |
50 | ||
51 | const char * stored_argv = "Unidentified program"; | |
52 | ||
53 | static const char segfault[] = ": Segmentation fault occurred\n"; | |
a38c6d4c | 54 | static const char abortcall[] = ": Abort was called\n"; |
970ed795 | 55 | |
a38c6d4c | 56 | void signal_handler(int signum) |
970ed795 EL |
57 | { |
58 | int retval; | |
59 | retval = write(STDERR_FILENO, stored_argv, strlen(stored_argv)); | |
a38c6d4c | 60 | if(signum==SIGSEGV){ |
970ed795 | 61 | retval = write(STDERR_FILENO, segfault , sizeof(segfault)-1); // sizeof includes \0 |
a38c6d4c | 62 | } else { |
63 | retval = write(STDERR_FILENO, abortcall , sizeof(abortcall)-1); // sizeof includes \0 | |
64 | } | |
65 | #ifdef LINUX | |
66 | int nptrs; | |
67 | void *buffer[100]; | |
68 | nptrs = backtrace(buffer, 100); | |
69 | backtrace_symbols_fd(buffer, nptrs, STDERR_FILENO); | |
70 | ||
71 | fflush(stderr); | |
72 | #endif | |
970ed795 EL |
73 | (void)retval; |
74 | TTCN_Logger::close_file(); | |
75 | ||
a38c6d4c | 76 | signal(SIGABRT, SIG_DFL); |
970ed795 EL |
77 | abort(); |
78 | } | |
79 | ||
80 | static void usage(const char* program_name) | |
81 | { | |
82 | fprintf(stderr, "\n" | |
83 | "usage: %s configuration_file\n" | |
84 | " or %s -l\n" | |
85 | " or %s -v\n" | |
86 | "\n" | |
87 | "OPTIONS:\n" | |
88 | " -l: list startable test cases and control parts\n" | |
89 | " -v: show version and module information\n", | |
90 | program_name, program_name, program_name); | |
91 | } | |
92 | ||
93 | int main(int argc, char *argv[]) | |
94 | { | |
95 | stored_argv = argv[0]; | |
96 | struct sigaction act; | |
97 | act.sa_handler = signal_handler; | |
98 | sigemptyset(&act.sa_mask); | |
99 | act.sa_flags = 0; | |
100 | sigaction(SIGSEGV, &act, 0); | |
a38c6d4c | 101 | sigaction(SIGABRT, &act, 0); |
970ed795 EL |
102 | |
103 | #ifdef MEMORY_DEBUG | |
104 | debug_new_counter.set_program_name(argv[0]); | |
105 | #endif | |
106 | errno = 0; | |
107 | int c, i, ret_val = EXIT_SUCCESS; | |
108 | boolean lflag = FALSE, vflag = FALSE, errflag = FALSE; | |
109 | const char *config_file = NULL; | |
110 | TTCN_Module *only_runnable = Module_List::single_control_part(); | |
111 | ||
112 | while ((c = getopt(argc, argv, "lv")) != -1) { | |
113 | switch (c) { | |
114 | case 'l': | |
115 | if (lflag || vflag) errflag = TRUE; // duplicate or conflicting | |
116 | else lflag = TRUE; | |
117 | break; | |
118 | case 'v': | |
119 | if (lflag || vflag) errflag = TRUE; // duplicate or conflicting | |
120 | else vflag = TRUE; | |
121 | break; | |
122 | default: | |
123 | errflag = TRUE; | |
124 | } | |
125 | } | |
126 | ||
127 | if (lflag || vflag) { | |
128 | if (optind != argc) errflag = TRUE; // -l or -v and non-option arg | |
129 | } else { | |
130 | if (optind > argc - 1) { // no config file argument | |
131 | errflag = (only_runnable == 0); | |
132 | } | |
133 | else config_file = argv[optind]; | |
134 | } | |
135 | ||
136 | if (errflag) { | |
137 | if (argc == 1) fputs("TTCN-3 Test Executor (single mode), version " | |
138 | PRODUCT_NUMBER "\n", stderr); | |
139 | usage(argv[0]); | |
140 | TCov::close_file(); | |
141 | return EXIT_FAILURE; | |
142 | } else if (lflag) { | |
143 | try { | |
144 | // create buffer for error messages | |
145 | TTCN_Logger::initialize_logger(); | |
146 | Module_List::pre_init_modules(); | |
147 | Module_List::list_testcases(); | |
148 | } catch (...) { | |
149 | ret_val = EXIT_FAILURE; | |
150 | } | |
151 | TTCN_Logger::terminate_logger(); | |
152 | TCov::close_file(); | |
153 | return ret_val; | |
154 | } else if (vflag) { | |
155 | fputs("TTCN-3 Test Executor (single mode)\n" | |
156 | "Product number: " PRODUCT_NUMBER "\n" | |
157 | "Build date (Base Library): " __DATE__ " " __TIME__ "\n" | |
158 | "Base Library was compiled with: " C_COMPILER_VERSION "\n\n" | |
159 | COPYRIGHT_STRING "\n\n", stderr); | |
160 | #ifdef LICENSE | |
161 | print_license_info(); | |
162 | putc('\n', stderr); | |
163 | #endif | |
164 | fputs("Module information:\n", stderr); | |
165 | Module_List::print_version(); | |
166 | TCov::close_file(); | |
167 | return EXIT_SUCCESS; | |
168 | } | |
169 | ||
170 | fputs("TTCN-3 Test Executor (single mode), version " PRODUCT_NUMBER "\n", | |
171 | stderr); | |
172 | ||
173 | #ifdef LICENSE | |
174 | init_openssl(); | |
175 | license_struct lstr; | |
176 | load_license(&lstr); | |
177 | if (!verify_license(&lstr)) { | |
178 | free_license(&lstr); | |
179 | free_openssl(); | |
180 | exit(EXIT_FAILURE); | |
181 | } | |
182 | if (!check_feature(&lstr, FEATURE_SINGLE)) { | |
183 | fputs("The license key does not allow test execution in single mode.\n", | |
184 | stderr); | |
185 | TCov::close_file(); | |
186 | return EXIT_FAILURE; | |
187 | } | |
188 | free_license(&lstr); | |
189 | free_openssl(); | |
190 | #endif | |
191 | ||
192 | self = MTC_COMPREF; | |
193 | TTCN_Runtime::set_state(TTCN_Runtime::SINGLE_CONTROLPART); | |
194 | TTCN_Runtime::install_signal_handlers(); | |
195 | TTCN_Snapshot::initialize(); | |
196 | TTCN_Logger::initialize_logger(); | |
197 | TTCN_Logger::set_executable_name(argv[0]); | |
198 | TTCN_Logger::set_start_time(); | |
199 | ||
200 | try { | |
201 | TTCN_Logger::log_executor_runtime( | |
202 | TitanLoggerApi::ExecutorRuntime_reason::executor__start__single__mode); | |
203 | Module_List::pre_init_modules(); | |
204 | ||
205 | if (config_file != 0) { | |
206 | fprintf(stderr, "Using configuration file: `%s'\n", config_file); | |
207 | TTCN_Logger::log_configdata( | |
208 | TitanLoggerApi::ExecutorConfigdata_reason::using__config__file, config_file); | |
209 | } | |
210 | ||
211 | TTCN_Snapshot::check_fd_setsize(); | |
212 | ||
213 | boolean config_file_failure = | |
214 | config_file && !process_config_file(config_file); | |
215 | TTCN_Runtime::load_logger_plugins(); | |
216 | // Quick return if no config file. | |
217 | TTCN_Runtime::set_logger_parameters(); | |
218 | TTCN_Logger::open_file(); | |
219 | TTCN_Logger::write_logger_settings(); | |
220 | if (config_file_failure) goto fail; | |
221 | // Config file parsed or no config file: we may be able to run. | |
222 | if (config_file) { | |
223 | if (++optind != argc) { | |
224 | // There are further commandline arguments after config file. | |
225 | // Override testcase list. | |
226 | // First, throw away the old list parsed from the config file. | |
227 | for (i = 0; i < execute_list_len; i++) { | |
228 | Free(execute_list[i].module_name); | |
229 | Free(execute_list[i].testcase_name); | |
230 | } | |
231 | ||
232 | // The new execute list length is known in advance. | |
233 | execute_list_len = argc - optind; | |
234 | execute_list = (execute_list_item *)Realloc( | |
235 | execute_list, execute_list_len * sizeof(*execute_list)); | |
236 | ||
237 | expstring_t testcase_names = memptystr(); // collects names for printout | |
238 | ||
239 | for (i = optind; i < argc; ++i) { | |
240 | testcase_names = mputstr(testcase_names, argv[i]); | |
241 | testcase_names = mputc(testcase_names, '\t'); | |
242 | ||
243 | char *dot = strchr(argv[i], '.'); | |
244 | if (dot != 0) { | |
245 | *dot++ = '\0'; // cut the string into two | |
246 | if (!strcmp(dot, "control")) | |
247 | dot = 0; | |
248 | } | |
249 | execute_list[i-optind].module_name = mcopystr(argv[i]); | |
250 | execute_list[i-optind].testcase_name = dot ? mcopystr(dot) : dot; | |
251 | // do not copy NULL pointer, it results in non-0 empty string | |
252 | } // next i | |
253 | fprintf(stderr, "Overriding testcase list: %s\n", testcase_names); | |
254 | TTCN_Logger::log_configdata( | |
255 | TitanLoggerApi::ExecutorConfigdata_reason::overriding__testcase__list, | |
256 | testcase_names); | |
257 | Free(testcase_names); | |
258 | } | |
259 | } | |
260 | ||
261 | if (execute_list_len == 0 && only_runnable) { | |
262 | // No config file or correct config file without EXECUTE section, | |
263 | // AND precisely one control part: run that one. | |
264 | execute_list_len = 1; | |
265 | execute_list = (execute_list_item *)Malloc(sizeof(*execute_list)); | |
266 | execute_list[0].module_name = mcopystr(only_runnable->get_name()); | |
267 | execute_list[0].testcase_name = 0; // control part | |
268 | } | |
269 | ||
270 | if (execute_list_len > 0) { // we have something to run | |
271 | Module_List::log_param(); | |
272 | Module_List::post_init_modules(); | |
273 | ||
274 | for (i = 0; i < execute_list_len; i++) { | |
275 | if (execute_list[i].testcase_name == NULL) | |
276 | Module_List::execute_control(execute_list[i].module_name); | |
277 | else if (!strcmp(execute_list[i].testcase_name, "*")) | |
278 | Module_List::execute_all_testcases( | |
279 | execute_list[i].module_name); | |
280 | else | |
281 | Module_List::execute_testcase(execute_list[i].module_name, | |
282 | execute_list[i].testcase_name); | |
283 | } | |
284 | } else { | |
285 | TTCN_warning("Nothing to run!"); | |
286 | fail: | |
287 | ret_val = EXIT_FAILURE; | |
288 | } | |
289 | } catch (...) { | |
290 | TTCN_Logger::log_str(TTCN_Logger::ERROR_UNQUALIFIED, | |
291 | "Fatal error. Aborting execution."); | |
292 | ret_val = EXIT_FAILURE; | |
293 | } | |
294 | TTCN_Runtime::restore_signal_handlers(); | |
295 | TTCN_Runtime::log_verdict_statistics(); | |
296 | TTCN_Logger::log_executor_runtime( | |
297 | TitanLoggerApi::ExecutorRuntime_reason::executor__finish__single__mode); | |
298 | TTCN_Logger::close_file(); | |
299 | TCov::close_file(); | |
300 | // close_file() must be called before the information is lost | |
301 | // close_file() WRITES to log | |
302 | ||
303 | TTCN_Logger::clear_parameters(); | |
304 | PORT::clear_parameters(); | |
305 | COMPONENT::clear_component_names(); | |
306 | TTCN_EncDec::clear_error(); | |
307 | ||
308 | for (i = 0; i < execute_list_len; i++) { | |
309 | Free(execute_list[i].module_name); | |
310 | Free(execute_list[i].testcase_name); | |
311 | } | |
312 | Free(execute_list); | |
313 | ||
314 | TTCN_Logger::terminate_logger(); | |
315 | TTCN_Snapshot::terminate(); | |
316 | ||
317 | return ret_val; | |
318 | } |