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" | |
f08ff9ca | 83 | "usage: %s [-h] [-b file] configuration_file\n" |
970ed795 EL |
84 | " or %s -l\n" |
85 | " or %s -v\n" | |
86 | "\n" | |
87 | "OPTIONS:\n" | |
f08ff9ca BB |
88 | " -b file: run specified batch file at start (debugger must be activated)\n" |
89 | " -h: automatically halt execution at start (debugger must be activated)\n" | |
970ed795 EL |
90 | " -l: list startable test cases and control parts\n" |
91 | " -v: show version and module information\n", | |
92 | program_name, program_name, program_name); | |
93 | } | |
94 | ||
95 | int main(int argc, char *argv[]) | |
96 | { | |
97 | stored_argv = argv[0]; | |
98 | struct sigaction act; | |
99 | act.sa_handler = signal_handler; | |
100 | sigemptyset(&act.sa_mask); | |
101 | act.sa_flags = 0; | |
102 | sigaction(SIGSEGV, &act, 0); | |
a38c6d4c | 103 | sigaction(SIGABRT, &act, 0); |
970ed795 EL |
104 | |
105 | #ifdef MEMORY_DEBUG | |
106 | debug_new_counter.set_program_name(argv[0]); | |
107 | #endif | |
108 | errno = 0; | |
109 | int c, i, ret_val = EXIT_SUCCESS; | |
f08ff9ca | 110 | boolean bflag = FALSE, hflag = FALSE, lflag = FALSE, vflag = FALSE, errflag = FALSE; |
970ed795 EL |
111 | const char *config_file = NULL; |
112 | TTCN_Module *only_runnable = Module_List::single_control_part(); | |
113 | ||
f08ff9ca | 114 | while ((c = getopt(argc, argv, "b:hlv")) != -1) { |
970ed795 | 115 | switch (c) { |
f08ff9ca BB |
116 | case 'b': |
117 | if (bflag || lflag || vflag) errflag = TRUE; // duplicate or conflicting | |
118 | else { | |
119 | bflag = TRUE; | |
120 | ttcn3_debugger.set_initial_batch_file(optarg); | |
121 | } | |
122 | break; | |
123 | case 'h': | |
124 | if (hflag || lflag || vflag) errflag = TRUE; // duplicate or conflicting | |
125 | else { | |
126 | hflag = TRUE; | |
127 | ttcn3_debugger.set_halt_at_start(); | |
128 | } | |
129 | break; | |
970ed795 EL |
130 | case 'l': |
131 | if (lflag || vflag) errflag = TRUE; // duplicate or conflicting | |
132 | else lflag = TRUE; | |
133 | break; | |
134 | case 'v': | |
135 | if (lflag || vflag) errflag = TRUE; // duplicate or conflicting | |
136 | else vflag = TRUE; | |
137 | break; | |
138 | default: | |
139 | errflag = TRUE; | |
140 | } | |
141 | } | |
142 | ||
f08ff9ca BB |
143 | if (!errflag) { |
144 | if (lflag || vflag) { | |
145 | if (optind != argc) errflag = TRUE; // -l or -v and non-option arg | |
146 | } else { | |
147 | if (optind > argc - 1) { // no config file argument | |
148 | errflag = (only_runnable == 0); | |
149 | } | |
150 | else config_file = argv[optind]; | |
970ed795 | 151 | } |
970ed795 EL |
152 | } |
153 | ||
154 | if (errflag) { | |
155 | if (argc == 1) fputs("TTCN-3 Test Executor (single mode), version " | |
156 | PRODUCT_NUMBER "\n", stderr); | |
157 | usage(argv[0]); | |
158 | TCov::close_file(); | |
159 | return EXIT_FAILURE; | |
160 | } else if (lflag) { | |
161 | try { | |
162 | // create buffer for error messages | |
163 | TTCN_Logger::initialize_logger(); | |
164 | Module_List::pre_init_modules(); | |
165 | Module_List::list_testcases(); | |
166 | } catch (...) { | |
167 | ret_val = EXIT_FAILURE; | |
168 | } | |
169 | TTCN_Logger::terminate_logger(); | |
170 | TCov::close_file(); | |
171 | return ret_val; | |
172 | } else if (vflag) { | |
173 | fputs("TTCN-3 Test Executor (single mode)\n" | |
174 | "Product number: " PRODUCT_NUMBER "\n" | |
175 | "Build date (Base Library): " __DATE__ " " __TIME__ "\n" | |
176 | "Base Library was compiled with: " C_COMPILER_VERSION "\n\n" | |
177 | COPYRIGHT_STRING "\n\n", stderr); | |
178 | #ifdef LICENSE | |
179 | print_license_info(); | |
180 | putc('\n', stderr); | |
181 | #endif | |
182 | fputs("Module information:\n", stderr); | |
183 | Module_List::print_version(); | |
184 | TCov::close_file(); | |
185 | return EXIT_SUCCESS; | |
186 | } | |
187 | ||
188 | fputs("TTCN-3 Test Executor (single mode), version " PRODUCT_NUMBER "\n", | |
189 | stderr); | |
190 | ||
191 | #ifdef LICENSE | |
192 | init_openssl(); | |
193 | license_struct lstr; | |
194 | load_license(&lstr); | |
195 | if (!verify_license(&lstr)) { | |
196 | free_license(&lstr); | |
197 | free_openssl(); | |
198 | exit(EXIT_FAILURE); | |
199 | } | |
200 | if (!check_feature(&lstr, FEATURE_SINGLE)) { | |
201 | fputs("The license key does not allow test execution in single mode.\n", | |
202 | stderr); | |
203 | TCov::close_file(); | |
204 | return EXIT_FAILURE; | |
205 | } | |
206 | free_license(&lstr); | |
207 | free_openssl(); | |
208 | #endif | |
209 | ||
210 | self = MTC_COMPREF; | |
211 | TTCN_Runtime::set_state(TTCN_Runtime::SINGLE_CONTROLPART); | |
212 | TTCN_Runtime::install_signal_handlers(); | |
213 | TTCN_Snapshot::initialize(); | |
214 | TTCN_Logger::initialize_logger(); | |
215 | TTCN_Logger::set_executable_name(argv[0]); | |
216 | TTCN_Logger::set_start_time(); | |
217 | ||
218 | try { | |
219 | TTCN_Logger::log_executor_runtime( | |
220 | TitanLoggerApi::ExecutorRuntime_reason::executor__start__single__mode); | |
221 | Module_List::pre_init_modules(); | |
222 | ||
223 | if (config_file != 0) { | |
224 | fprintf(stderr, "Using configuration file: `%s'\n", config_file); | |
225 | TTCN_Logger::log_configdata( | |
226 | TitanLoggerApi::ExecutorConfigdata_reason::using__config__file, config_file); | |
227 | } | |
228 | ||
229 | TTCN_Snapshot::check_fd_setsize(); | |
230 | ||
231 | boolean config_file_failure = | |
232 | config_file && !process_config_file(config_file); | |
233 | TTCN_Runtime::load_logger_plugins(); | |
234 | // Quick return if no config file. | |
235 | TTCN_Runtime::set_logger_parameters(); | |
236 | TTCN_Logger::open_file(); | |
237 | TTCN_Logger::write_logger_settings(); | |
238 | if (config_file_failure) goto fail; | |
239 | // Config file parsed or no config file: we may be able to run. | |
240 | if (config_file) { | |
241 | if (++optind != argc) { | |
242 | // There are further commandline arguments after config file. | |
243 | // Override testcase list. | |
244 | // First, throw away the old list parsed from the config file. | |
245 | for (i = 0; i < execute_list_len; i++) { | |
246 | Free(execute_list[i].module_name); | |
247 | Free(execute_list[i].testcase_name); | |
248 | } | |
249 | ||
250 | // The new execute list length is known in advance. | |
251 | execute_list_len = argc - optind; | |
252 | execute_list = (execute_list_item *)Realloc( | |
253 | execute_list, execute_list_len * sizeof(*execute_list)); | |
254 | ||
255 | expstring_t testcase_names = memptystr(); // collects names for printout | |
256 | ||
257 | for (i = optind; i < argc; ++i) { | |
258 | testcase_names = mputstr(testcase_names, argv[i]); | |
259 | testcase_names = mputc(testcase_names, '\t'); | |
260 | ||
261 | char *dot = strchr(argv[i], '.'); | |
262 | if (dot != 0) { | |
263 | *dot++ = '\0'; // cut the string into two | |
264 | if (!strcmp(dot, "control")) | |
265 | dot = 0; | |
266 | } | |
267 | execute_list[i-optind].module_name = mcopystr(argv[i]); | |
268 | execute_list[i-optind].testcase_name = dot ? mcopystr(dot) : dot; | |
269 | // do not copy NULL pointer, it results in non-0 empty string | |
270 | } // next i | |
271 | fprintf(stderr, "Overriding testcase list: %s\n", testcase_names); | |
272 | TTCN_Logger::log_configdata( | |
273 | TitanLoggerApi::ExecutorConfigdata_reason::overriding__testcase__list, | |
274 | testcase_names); | |
275 | Free(testcase_names); | |
276 | } | |
277 | } | |
278 | ||
279 | if (execute_list_len == 0 && only_runnable) { | |
280 | // No config file or correct config file without EXECUTE section, | |
281 | // AND precisely one control part: run that one. | |
282 | execute_list_len = 1; | |
283 | execute_list = (execute_list_item *)Malloc(sizeof(*execute_list)); | |
284 | execute_list[0].module_name = mcopystr(only_runnable->get_name()); | |
285 | execute_list[0].testcase_name = 0; // control part | |
286 | } | |
287 | ||
288 | if (execute_list_len > 0) { // we have something to run | |
289 | Module_List::log_param(); | |
290 | Module_List::post_init_modules(); | |
291 | ||
292 | for (i = 0; i < execute_list_len; i++) { | |
f08ff9ca BB |
293 | if (ttcn3_debugger.is_exiting()) { |
294 | break; | |
295 | } | |
970ed795 EL |
296 | if (execute_list[i].testcase_name == NULL) |
297 | Module_List::execute_control(execute_list[i].module_name); | |
298 | else if (!strcmp(execute_list[i].testcase_name, "*")) | |
299 | Module_List::execute_all_testcases( | |
300 | execute_list[i].module_name); | |
301 | else | |
302 | Module_List::execute_testcase(execute_list[i].module_name, | |
303 | execute_list[i].testcase_name); | |
304 | } | |
305 | } else { | |
306 | TTCN_warning("Nothing to run!"); | |
307 | fail: | |
308 | ret_val = EXIT_FAILURE; | |
309 | } | |
310 | } catch (...) { | |
311 | TTCN_Logger::log_str(TTCN_Logger::ERROR_UNQUALIFIED, | |
312 | "Fatal error. Aborting execution."); | |
313 | ret_val = EXIT_FAILURE; | |
314 | } | |
315 | TTCN_Runtime::restore_signal_handlers(); | |
316 | TTCN_Runtime::log_verdict_statistics(); | |
317 | TTCN_Logger::log_executor_runtime( | |
318 | TitanLoggerApi::ExecutorRuntime_reason::executor__finish__single__mode); | |
319 | TTCN_Logger::close_file(); | |
320 | TCov::close_file(); | |
321 | // close_file() must be called before the information is lost | |
322 | // close_file() WRITES to log | |
323 | ||
324 | TTCN_Logger::clear_parameters(); | |
325 | PORT::clear_parameters(); | |
326 | COMPONENT::clear_component_names(); | |
327 | TTCN_EncDec::clear_error(); | |
328 | ||
329 | for (i = 0; i < execute_list_len; i++) { | |
330 | Free(execute_list[i].module_name); | |
331 | Free(execute_list[i].testcase_name); | |
332 | } | |
333 | Free(execute_list); | |
334 | ||
335 | TTCN_Logger::terminate_logger(); | |
336 | TTCN_Snapshot::terminate(); | |
337 | ||
338 | return ret_val; | |
339 | } |