1 ///////////////////////////////////////////////////////////////////////////////
2 // Copyright (c) 2000-2015 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 ///////////////////////////////////////////////////////////////////////////////
9 // Description: Implementation file for Cli
10 // Author: Gecse Roland
11 // mail: ethrge@eth.ericsson.se
13 // Copyright (c) 2000-2015 Ericsson Telecom AB
15 //----------------------------------------------------------------------------
17 #include "../mctr/MainController.h"
20 #include "../editline/libedit/src/editline/readline.h"
26 #include <arpa/inet.h>
27 #include "../../common/version_internal.h"
28 #include "../../common/memory.h"
29 #include "../../common/config_preproc.h"
31 #define PROMPT "MC2> "
32 #define CMTC_TEXT "cmtc"
33 #define SMTC_TEXT "smtc"
34 #define EMTC_TEXT "emtc"
35 #define STOP_TEXT "stop"
36 #define PAUSE_TEXT "pause"
37 #define CONTINUE_TEXT "continue"
38 #define INFO_TEXT "info"
39 #define HELP_TEXT "help"
40 #define RECONF_TEXT "reconf"
41 #define LOG_TEXT "log"
42 #define SHELL_TEXT "!"
43 #define EXIT_TEXT "quit"
44 #define EXIT_TEXT2 "exit"
45 #define SHELL_ESCAPE '!'
46 #define TTCN3_HISTORY_FILENAME ".ttcn3_history"
48 using mctr::MainController
;
52 * shell_mode == TRUE while editing a command line that is passed to the shell
54 static boolean shell_mode
;
58 callback_t callback_function
;
60 const char *description
;
63 static const Command command_list
[] = {
64 { CMTC_TEXT
, &Cli::cmtcCallback
, CMTC_TEXT
" [hostname]",
66 { SMTC_TEXT
, &Cli::smtcCallback
,
67 SMTC_TEXT
" [module_name[[.control]|.testcase_name|.*]",
68 "Start MTC with control part, test case or all test cases." },
69 { STOP_TEXT
, &Cli::stopCallback
, STOP_TEXT
,
70 "Stop test execution." },
71 { PAUSE_TEXT
, &Cli::pauseCallback
, PAUSE_TEXT
" [on|off]",
72 "Set whether to interrupt test execution after each "
74 { CONTINUE_TEXT
, &Cli::continueCallback
, CONTINUE_TEXT
,
75 "Resumes interrupted test execution." },
76 { EMTC_TEXT
, &Cli::emtcCallback
, EMTC_TEXT
, "Terminate MTC." },
77 { LOG_TEXT
, &Cli::logCallback
, LOG_TEXT
" [on|off]",
78 "Enable/disable console logging." },
79 { INFO_TEXT
, &Cli::infoCallback
, INFO_TEXT
,
80 "Display test configuration information." },
81 { RECONF_TEXT
, &Cli::reconfCallback
, RECONF_TEXT
" [config_file]",
82 "Reload configuration file." },
83 { HELP_TEXT
, &Cli::helpCallback
, HELP_TEXT
" <command>",
84 "Display help on command." },
85 { SHELL_TEXT
, &Cli::shellCallback
, SHELL_TEXT
"[shell cmds]",
86 "Execute commands in subshell." },
87 { EXIT_TEXT
, &Cli::exitCallback
, EXIT_TEXT
, "Exit Main Controller." },
88 { EXIT_TEXT2
, &Cli::exitCallback
, EXIT_TEXT2
, "Exit Main Controller." },
89 { NULL
, NULL
, NULL
, NULL
}
94 loggingEnabled
= TRUE
;
96 waitState
= WAIT_NOTHING
;
99 if (pthread_mutex_init(&mutex
, NULL
)) {
100 perror("Cli::Cli: pthread_mutex_init failed.");
103 if (pthread_cond_init(&cond
, NULL
)) {
104 perror("Cli::Cli: pthread_cond_init failed.");
111 pthread_mutex_destroy(&mutex
);
112 pthread_cond_destroy(&cond
);
115 //----------------------------------------------------------------------------
118 int Cli::enterLoop(int argc
, char *argv
[])
120 // Parameter check: mctr [config file name]
129 printf("Using configuration file: %s\n", argv
[1]);
130 if (process_config_read_file(argv
[1], &mycfg
)) {
131 puts("Error was found in the configuration file. Exiting.");
136 MainController::set_kill_timer(mycfg
.kill_timer
);
138 for (int i
= 0; i
< mycfg
.group_list_len
; ++i
) {
139 MainController::add_host(mycfg
.group_list
[i
].group_name
,
140 mycfg
.group_list
[i
].host_name
);
143 for (int i
= 0; i
< mycfg
.component_list_len
; ++i
) {
144 MainController::assign_component(mycfg
.component_list
[i
].host_or_group
,
145 mycfg
.component_list
[i
].component
);
151 if (mycfg
.num_hcs
<= 0) ret_val
= interactiveMode();
152 else ret_val
= batchMode();
158 //----------------------------------------------------------------------------
161 void Cli::status_change()
164 if (waitState
!= WAIT_NOTHING
&& conditionHolds(waitState
)) {
165 waitState
= WAIT_NOTHING
;
171 //----------------------------------------------------------------------------
174 void Cli::error(int /*severity*/, const char *message
)
176 printf("Error: %s\n", message
);
178 // TODO: Error handling based on the MC state where the error happened
181 //----------------------------------------------------------------------------
184 void Cli::notify(const struct timeval
*timestamp
, const char *source
,
185 int /*severity*/, const char *message
)
189 switch(mycfg
.tsformat
){
190 case TSF_TIME
: // handled together
193 time_t tv_sec
= timestamp
->tv_sec
;
194 struct tm
*lt
= localtime(&tv_sec
);
196 printf("localtime() call failed.");
197 printf("%s: %s\n", source
, message
);
201 if (mycfg
.tsformat
== TSF_TIME
) {
202 printf("%02d:%02d:%02d.%06ld %s: %s\n",
203 lt
->tm_hour
, lt
->tm_min
, lt
->tm_sec
, timestamp
->tv_usec
,source
, message
);
205 static const char * const month_names
[] = { "Jan", "Feb", "Mar",
206 "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
207 printf("%4d/%s/%02d %02d:%02d:%02d.%06ld %s: %s\n",
208 lt
->tm_year
+ 1900, month_names
[lt
->tm_mon
],
209 lt
->tm_mday
, lt
->tm_hour
, lt
->tm_min
, lt
->tm_sec
,
217 printf("%ld.%06ld %s: %s\n", (long)timestamp
->tv_sec
, timestamp
->tv_usec
, source
, message
);
222 printf("%s: %s\n", source
, message
);
229 //----------------------------------------------------------------------------
236 //----------------------------------------------------------------------------
239 void Cli::printWelcome()
242 "*************************************************************************\n"
243 "* TTCN-3 Test Executor - Main Controller 2 *\n"
244 "* Version: %-40s *\n"
245 "* Copyright (c) 2000-2015 Ericsson Telecom AB *\n"
246 "* All rights reserved. This program and the accompanying materials *\n"
247 "* are made available under the terms of the Eclipse Public License v1.0 *\n"
248 "* which accompanies this distribution, and is available at *\n"
249 "* http://www.eclipse.org/legal/epl-v10.html *\n"
250 "*************************************************************************\n"
251 "\n", PRODUCT_NUMBER
);
254 void Cli::printUsage(const char *prg_name
)
257 "TTCN-3 Test Executor - Main Controller 2\n"
258 "Version: " PRODUCT_NUMBER
"\n\n"
259 "usage: %s [configuration_file]\n"
260 "where: the optional 'configuration_file' parameter specifies the name "
261 "and\nlocation of the main controller configuration file"
265 //----------------------------------------------------------------------------
268 int Cli::interactiveMode()
270 // Initialize history library
273 const char *home_directory
= getenv("HOME");
274 if(home_directory
== NULL
)
275 home_directory
= ".";
276 char *ttcn3_history_filename
= mprintf("%s/%s", home_directory
,
277 TTCN3_HISTORY_FILENAME
);
278 // Read history from file, don't bother if it does not exist!
279 read_history(ttcn3_history_filename
);
280 // Set our own command completion function
281 rl_completion_entry_function
= (Function
*)completeCommand
;
282 // Override rl_getc() in order to detect shell mode
283 rl_getc_function
= getcWithShellDetection
;
285 // TCP listen port parameter, returns TCP port on which it listens!
286 // Returns 0 on error.
287 if (MainController::start_session(mycfg
.local_addr
, mycfg
.tcp_listen_port
,
288 mycfg
.unix_sockets_enabled
) == 0) {
289 puts("Initialization of TCP server failed. Exiting.");
290 Free(ttcn3_history_filename
);
295 char *line_read
= readline(PROMPT
);
296 if (line_read
!= NULL
) {
300 add_history(line_read
); // history maintains its own copy
301 // process and free line
302 processCommand(line_read
);
313 if (write_history(ttcn3_history_filename
))
314 perror("Could not save history.");
315 Free(ttcn3_history_filename
);
322 printf("Entering batch mode. Waiting for %d HC%s to connect...\n",
323 mycfg
.num_hcs
, mycfg
.num_hcs
> 1 ? "s" : "");
324 if (mycfg
.execute_list_len
<= 0) {
325 puts("No [EXECUTE] section was given in the configuration file. "
329 boolean error_flag
= FALSE
;
330 // start to listen on TCP port
331 if (MainController::start_session(mycfg
.local_addr
, mycfg
.tcp_listen_port
,
332 mycfg
.unix_sockets_enabled
) == 0) {
333 puts("Initialization of TCP server failed. Exiting.");
336 waitMCState(WAIT_HC_CONNECTED
);
337 // download config file
338 MainController::configure(mycfg
.config_read_buffer
);
339 waitMCState(WAIT_ACTIVE
);
340 if (MainController::get_state() != mctr::MC_ACTIVE
) {
341 puts("Error during initialization. Cannot continue in batch mode.");
345 // create MTC on firstly connected HC
346 MainController::create_mtc(0);
347 waitMCState(WAIT_MTC_CREATED
);
348 if (MainController::get_state() != mctr::MC_READY
) {
349 puts("Creation of MTC failed. Cannot continue in batch mode.");
354 // execute each item of the list
355 for (int i
= 0; i
< mycfg
.execute_list_len
; i
++) {
357 waitMCState(WAIT_MTC_READY
);
358 if (MainController::get_state() != mctr::MC_READY
) {
359 puts("MTC terminated unexpectedly. Cannot continue in batch "
368 MainController::exit_mtc();
369 waitMCState(WAIT_MTC_TERMINATED
);
371 // now MC must be in state MC_ACTIVE anyway
373 MainController::shutdown_session();
374 waitMCState(WAIT_SHUTDOWN_COMPLETE
);
375 if (error_flag
) return EXIT_FAILURE
;
376 else return EXIT_SUCCESS
;
379 //----------------------------------------------------------------------------
382 void Cli::processCommand(char *line_read
)
384 for (const Command
*command
= command_list
; command
->name
!= NULL
;
386 size_t command_name_len
= strlen(command
->name
);
387 if (!strncmp(line_read
, command
->name
, command_name_len
)) {
388 memset(line_read
, ' ', command_name_len
);
390 (this->*command
->callback_function
)(line_read
);
394 puts("Unknown command, try again...");
397 //----------------------------------------------------------------------------
399 // Create Main Test Component
401 void Cli::cmtcCallback(const char *arguments
)
404 if(*arguments
== 0) hostIndex
= 0;
406 hostIndex
= getHostIndex(arguments
);
407 if (hostIndex
< 0) return;
409 switch (MainController::get_state()) {
410 case mctr::MC_LISTENING
:
411 case mctr::MC_LISTENING_CONFIGURED
:
412 puts("Waiting for HC to connect...");
413 waitMCState(WAIT_HC_CONNECTED
);
414 case mctr::MC_HC_CONNECTED
:
415 MainController::configure(mycfg
.config_read_buffer
);
416 waitMCState(WAIT_ACTIVE
);
417 if (MainController::get_state() != mctr::MC_ACTIVE
) {
418 puts("Error during initialization. Cannot create MTC.");
421 case mctr::MC_ACTIVE
:
422 MainController::create_mtc(hostIndex
);
423 waitMCState(WAIT_MTC_CREATED
);
426 puts("MTC already exists.");
431 //----------------------------------------------------------------------------
433 // Start Main Test Component and execute the
434 // a) control part or testcase (or *) given in arguments
435 // b) EXECUTE part of supplied configuration file -- if arguments==NULL
437 void Cli::smtcCallback(const char *arguments
)
439 switch (MainController::get_state()) {
440 case mctr::MC_LISTENING
:
441 case mctr::MC_LISTENING_CONFIGURED
:
442 case mctr::MC_HC_CONNECTED
:
443 case mctr::MC_ACTIVE
:
444 puts("MTC does not exist.");
447 if (*arguments
== 0) {
448 // Execute configuration file's execute section
449 if (mycfg
.execute_list_len
> 0) {
450 puts("Executing all items of [EXECUTE] section.");
451 waitState
= WAIT_EXECUTE_LIST
;
452 executeListIndex
= 0;
455 puts("No [EXECUTE] section was given in the configuration "
458 } else { // Check the arguments
459 size_t doti
= 0, alen
= strlen(arguments
), state
= 0;
460 for (size_t r
= 0; r
< alen
; r
++) {
461 switch (arguments
[r
]) {
472 if(state
> 1) { // incorrect argument
473 puts("Incorrect argument format.");
474 helpCallback(SMTC_TEXT
);
476 if(state
== 0) { // only modulename is given in arguments
477 MainController::execute_control(arguments
);
478 } else { // modulename.something in arguments
479 expstring_t arg_copy
= mcopystr(arguments
);
480 arg_copy
[doti
++] = '\0';
481 if (!strcmp(arg_copy
+ doti
, "*"))
482 MainController::execute_testcase(arg_copy
, NULL
);
483 else if (!strcmp(arg_copy
+ doti
, "control"))
484 MainController::execute_control(arg_copy
);
485 else MainController::execute_testcase(arg_copy
,
493 puts("MTC is busy.");
498 //----------------------------------------------------------------------------
500 // Stops test execution
502 void Cli::stopCallback(const char *arguments
)
504 if (*arguments
== 0) {
505 switch (MainController::get_state()) {
506 case mctr::MC_TERMINATING_TESTCASE
:
507 case mctr::MC_EXECUTING_CONTROL
:
508 case mctr::MC_EXECUTING_TESTCASE
:
509 case mctr::MC_PAUSED
:
510 MainController::stop_execution();
511 if (waitState
== WAIT_EXECUTE_LIST
) waitState
= WAIT_NOTHING
;
514 puts("Tests are not running.");
516 } else helpCallback(STOP_TEXT
);
519 //----------------------------------------------------------------------------
521 // Sets whether to interrupt test execution after testcase
523 void Cli::pauseCallback(const char *arguments
)
525 if (arguments
[0] != '\0') {
526 if (!strcmp(arguments
, "on")) {
527 if (!MainController::get_stop_after_testcase()) {
528 MainController::stop_after_testcase(TRUE
);
529 puts("Pause function is enabled. "
530 "Execution will stop at the end of each testcase.");
531 } else puts("Pause function is already enabled.");
532 } else if (!strcmp(arguments
, "off")) {
533 if (MainController::get_stop_after_testcase()) {
534 MainController::stop_after_testcase(FALSE
);
535 puts("Pause function is disabled. "
536 "Execution will continue at the end of each testcase.");
537 } else puts("Pause function is already disabled.");
538 } else helpCallback(PAUSE_TEXT
);
539 } else printf("Pause function is %s.\n",
540 MainController::get_stop_after_testcase() ? "enabled" : "disabled");
543 //----------------------------------------------------------------------------
545 // Resumes interrupted test execution
547 void Cli::continueCallback(const char *arguments
)
549 if (*arguments
== 0) {
550 switch (MainController::get_state()) {
551 case mctr::MC_TERMINATING_TESTCASE
:
552 case mctr::MC_EXECUTING_CONTROL
:
553 case mctr::MC_EXECUTING_TESTCASE
:
554 puts("Execution is not paused.");
556 case mctr::MC_PAUSED
:
557 MainController::continue_testcase();
560 puts("Tests are not running.");
562 } else helpCallback(CONTINUE_TEXT
);
565 //----------------------------------------------------------------------------
567 // Exit Main Test Component
569 void Cli::emtcCallback(const char *arguments
)
571 if(*arguments
== 0) {
572 switch (MainController::get_state()) {
573 case mctr::MC_LISTENING
:
574 case mctr::MC_LISTENING_CONFIGURED
:
575 case mctr::MC_HC_CONNECTED
:
576 case mctr::MC_ACTIVE
:
577 puts("MTC does not exist.");
580 MainController::exit_mtc();
581 waitMCState(WAIT_MTC_TERMINATED
);
584 puts("MTC cannot be terminated.");
587 helpCallback(EMTC_TEXT
);
591 //----------------------------------------------------------------------------
593 // Controls console logging
595 void Cli::logCallback(const char *arguments
)
597 if (arguments
[0] != '\0') {
598 if (!strcmp(arguments
, "on")) {
599 loggingEnabled
= TRUE
;
600 puts("Console logging is enabled.");
601 } else if (!strcmp(arguments
, "off")) {
602 loggingEnabled
= FALSE
;
603 puts("Console logging is disabled.");
604 } else helpCallback(LOG_TEXT
);
605 } else printf("Console logging is %s.\n",
606 loggingEnabled
? "enabled" : "disabled");
609 //----------------------------------------------------------------------------
611 // Print connection information
613 void Cli::infoCallback(const char *arguments
)
615 if (*arguments
== 0) printInfo();
616 else helpCallback(INFO_TEXT
);
619 //----------------------------------------------------------------------------
621 // Reconfigure MC and HCs
623 void Cli::reconfCallback(const char *arguments
)
625 if(*arguments
== 0) { // reconf called without its optional argument
626 puts("Reconfiguration of MC and HCs using original configuration "
627 "data\n -- not supported, yet.");
628 } else { // reconf called with config_file argument
629 puts("Reconfiguration of MC and HCs using configuration file"
630 "specified in\ncommand line argument -- not supported, yet.");
634 //----------------------------------------------------------------------------
636 // Print general help or help on command usage to console
638 void Cli::helpCallback(const char *arguments
)
640 if (*arguments
== 0) {
641 puts("Help is available for the following commands:");
642 for (const Command
*command
= command_list
;
643 command
->name
!= NULL
; command
++) {
644 printf(" %s", command
->name
);
648 for (const Command
*command
= command_list
;
649 command
->name
!= NULL
; command
++) {
650 if (!strncmp(arguments
, command
->name
,
651 strlen(command
->name
))) {
652 printf("%s usage: %s\n%s\n", command
->name
,
654 command
->description
);
658 printf("No help for %s.\n", arguments
);
662 //----------------------------------------------------------------------------
664 // Pass command to shell
666 void Cli::shellCallback(const char *arguments
)
668 if(system(arguments
) == -1) {
669 perror("Error executing command in subshell.");
673 //----------------------------------------------------------------------------
675 // User initiated MC termination, exits the program.
676 // Save history into file and terminate CLI session.
678 void Cli::exitCallback(const char *arguments
)
680 if (*arguments
== 0) {
681 switch (MainController::get_state()) {
683 MainController::exit_mtc();
684 waitMCState(WAIT_MTC_TERMINATED
);
685 case mctr::MC_LISTENING
:
686 case mctr::MC_LISTENING_CONFIGURED
:
687 case mctr::MC_HC_CONNECTED
:
688 case mctr::MC_ACTIVE
:
689 MainController::shutdown_session();
690 waitMCState(WAIT_SHUTDOWN_COMPLETE
);
694 puts("Cannot exit until execution is finished.");
697 helpCallback(EXIT_TEXT
);
701 //----------------------------------------------------------------------------
703 // Command completion function implementation for readline() library.
704 // Heavily uses the ``static Command command_list[]'' array!
706 char *Cli::completeCommand(const char *prefix
, int state
)
708 static int command_index
;
709 static size_t prefix_len
;
710 const char *command_name
;
713 return rl_filename_completion_function(prefix
, state
);
717 prefix_len
= strlen(prefix
);
720 while((command_name
= command_list
[command_index
].name
)) {
722 if(strncmp(prefix
, command_name
, prefix_len
) == 0) {
723 // Must allocate buffer for returned string (readline frees it)
724 return strdup(command_name
);
731 //----------------------------------------------------------------------------
733 // Character input function implementation for readline() library.
735 int Cli::getcWithShellDetection(FILE *fp
)
737 int input_char
= getc(fp
);
738 if(input_char
== SHELL_ESCAPE
)
744 //----------------------------------------------------------------------------
747 void Cli::stripLWS(char *input_text
)
749 if(input_text
== NULL
) {
750 puts("stripLWS() called with NULL.");
751 exit(EXIT_FAILURE
); // This shall never happen
753 size_t head_index
, tail_index
, input_len
= strlen(input_text
);
754 if(input_len
< 1) return;
755 for(head_index
= 0; isspace(input_text
[head_index
]); head_index
++) ;
756 for(tail_index
= input_len
- 1; tail_index
>= head_index
&&
757 isspace(input_text
[tail_index
]); tail_index
--) ;
758 size_t output_len
= tail_index
- head_index
+ 1;
759 memmove(input_text
, input_text
+ head_index
, output_len
);
760 memset(input_text
+ output_len
, 0, input_len
- output_len
);
763 const char *Cli::verdict2str(verdicttype verdict
)
781 //----------------------------------------------------------------------------
784 void Cli::printInfo()
786 puts("MC information:");
787 printf(" MC state: %s\n",
788 MainController::get_mc_state_name(MainController::get_state()));
789 puts(" host information:");
791 for ( ; ; host_index
++) {
792 mctr::host_struct
*host
= MainController::get_host_data(host_index
);
794 printf(" - %s", host
->hostname
);
795 const char *ip_addr
= host
->ip_addr
->get_addr_str();
796 // if the hostname differs from the IP address
797 // (i.e. the host has a DNS entry)
798 if (strcmp(ip_addr
, host
->hostname
)) printf(" [%s]", ip_addr
);
799 // if the local hostname differs from the prefix of the DNS name
800 if (strncmp(host
->hostname
, host
->hostname_local
,
801 strlen(host
->hostname_local
)))
802 printf(" (%s)", host
->hostname_local
);
804 printf(" operating system: %s %s on %s\n", host
->system_name
,
805 host
->system_release
, host
->machine_type
);
806 printf(" HC state: %s\n",
807 MainController::get_hc_state_name(host
->hc_state
));
809 puts(" test component information:");
810 // make a copy of the array containing component references
811 int n_components
= host
->n_components
;
812 component
*components
= (component
*)Malloc(n_components
*
814 memcpy(components
, host
->components
, n_components
*
816 // the host structure has to be released in order to get access
817 // to the component structures
818 MainController::release_data();
819 for (int component_index
= 0; component_index
< n_components
;
821 mctr::component_struct
*comp
= MainController::
822 get_component_data(components
[component_index
]);
823 // if the component has a name
824 if (comp
->comp_name
!= NULL
)
825 printf(" - name: %s, component reference: %d\n",
826 comp
->comp_name
, comp
->comp_ref
);
827 else printf(" - component reference: %d\n",
829 if (comp
->comp_type
.definition_name
!= NULL
) {
830 printf(" component type: ");
831 if (comp
->comp_type
.module_name
!= NULL
)
832 printf("%s.", comp
->comp_type
.module_name
);
833 printf("%s\n", comp
->comp_type
.definition_name
);
835 printf(" state: %s\n",
836 MainController::get_tc_state_name(comp
->tc_state
));
837 if (comp
->tc_fn_name
.definition_name
!= NULL
) {
838 printf(" executed %s: ",
839 comp
->comp_ref
== MTC_COMPREF
?
840 "test case" : "function");
841 if (comp
->tc_fn_name
.module_name
!= NULL
)
842 printf("%s.", comp
->tc_fn_name
.module_name
);
843 printf("%s\n", comp
->tc_fn_name
.definition_name
);
845 if (comp
->tc_state
== mctr::TC_EXITING
||
846 comp
->tc_state
== mctr::TC_EXITED
)
847 printf(" local verdict: %s\n",
848 verdict2str(comp
->local_verdict
));
849 MainController::release_data();
851 if (n_components
== 0) puts(" no components on this host");
854 MainController::release_data();
858 if (host_index
== 0) puts(" no HCs are connected");
859 printf(" pause function: %s\n", MainController::get_stop_after_testcase() ?
860 "enabled" : "disabled");
861 printf(" console logging: %s\n", loggingEnabled
?
862 "enabled" : "disabled");
866 //----------------------------------------------------------------------------
871 if (pthread_mutex_lock(&mutex
)) {
872 perror("Cli::lock: pthread_mutex_lock failed.");
879 if (pthread_mutex_unlock(&mutex
)) {
880 perror("Cli::unlock: pthread_mutex_unlock failed.");
887 if (pthread_cond_wait(&cond
, &mutex
)) {
888 perror("Cli::wait: pthread_cond_wait failed.");
895 if (pthread_cond_signal(&cond
)) {
896 perror("Cli::signal: pthread_cond_signal failed.");
901 void Cli::waitMCState(waitStateEnum newWaitState
)
904 if (newWaitState
!= WAIT_NOTHING
) {
905 if (conditionHolds(newWaitState
)) {
906 waitState
= WAIT_NOTHING
;
908 waitState
= newWaitState
;
912 fputs("Cli::waitMCState: invalid argument", stderr
);
918 boolean
Cli::conditionHolds(waitStateEnum askedState
)
920 switch (askedState
) {
921 case WAIT_HC_CONNECTED
:
922 if (MainController::get_state() == mctr::MC_HC_CONNECTED
) {
923 if (mycfg
.num_hcs
> 0) {
924 return MainController::get_nof_hosts() >= mycfg
.num_hcs
;
929 switch (MainController::get_state()) {
930 case mctr::MC_ACTIVE
: // normal case
931 case mctr::MC_HC_CONNECTED
: // error happened with config file
932 case mctr::MC_LISTENING
: // even more strange situations
937 case WAIT_MTC_CREATED
:
939 switch (MainController::get_state()) {
940 case mctr::MC_READY
: // normal case
941 case mctr::MC_ACTIVE
: // MTC crashed unexpectedly
942 case mctr::MC_LISTENING_CONFIGURED
: // MTC and all HCs are crashed
944 case mctr::MC_HC_CONNECTED
: // even more strange situations
949 case WAIT_MTC_TERMINATED
:
950 return MainController::get_state() == mctr::MC_ACTIVE
;
951 case WAIT_SHUTDOWN_COMPLETE
:
952 return MainController::get_state() == mctr::MC_INACTIVE
;
953 case WAIT_EXECUTE_LIST
:
954 if (MainController::get_state() == mctr::MC_READY
) {
955 if (++executeListIndex
< mycfg
.execute_list_len
) {
957 executeFromList(executeListIndex
);
960 puts("Execution of [EXECUTE] section finished.");
961 waitState
= WAIT_NOTHING
;
970 int Cli::getHostIndex(const char* hostname
)
972 int hostname_len
= strlen(hostname
);
973 int index
, found
= -1;
974 for (index
= 0; ; index
++) {
975 const mctr::host_struct
*host
=
976 MainController::get_host_data(index
);
978 if (!strncmp(host
->hostname
, hostname
, hostname_len
) ||
979 !strncmp(host
->hostname_local
, hostname
, hostname_len
)) {
980 MainController::release_data();
981 if (found
== -1) found
= index
;
983 printf("Hostname %s is ambiguous.\n", hostname
);
987 } else MainController::release_data();
989 MainController::release_data();
990 if (found
== -1) printf("No such host: %s.\n", hostname
);
997 void Cli::executeFromList(int index
)
999 if (index
>= mycfg
.execute_list_len
) {
1000 fputs("Cli::executeFromList: invalid argument", stderr
);
1003 if (mycfg
.execute_list
[index
].testcase_name
== NULL
) {
1004 MainController::execute_control(mycfg
.execute_list
[index
].module_name
);
1005 } else if (!strcmp(mycfg
.execute_list
[index
].testcase_name
, "*")) {
1006 MainController::execute_testcase(mycfg
.execute_list
[index
].module_name
,
1009 MainController::execute_testcase(mycfg
.execute_list
[index
].module_name
,
1010 mycfg
.execute_list
[index
].testcase_name
);
1014 //----------------------------------------------------------------------------
1017 // indent-tabs-mode: nil
1018 // c-basic-offset: 2
1021 extern boolean error_flag
; // in config_read.y
1022 extern std::string
get_cfg_read_current_file(); // in config_read.y
1023 extern int config_read_lineno
; // in config_read.l
1024 extern char *config_read_text
; // in config_read.l
1026 void config_read_warning(const char *warning_str
, ...)
1028 fprintf(stderr
, "Warning: in configuration file `%s', line %d: ",
1029 get_cfg_read_current_file().c_str(), config_read_lineno
);
1031 va_start(pvar
, warning_str
);
1032 vfprintf(stderr
, warning_str
, pvar
);
1037 void config_read_error(const char *error_str
, ...)
1039 fprintf(stderr
, "Parse error in configuration file `%s': in line %d, "
1040 "at or before token `%s': ",
1041 get_cfg_read_current_file().c_str(), config_read_lineno
, config_read_text
);
1043 va_start(pvar
, error_str
);
1044 vfprintf(stderr
, error_str
, pvar
);
1050 void config_preproc_error(const char *error_str
, ...)
1052 fprintf(stderr
, "Parse error while pre-processing configuration file "
1053 "`%s': in line %d: ",
1054 get_cfg_preproc_current_file().c_str(),
1055 config_preproc_yylineno
);
1057 va_start(pvar
, error_str
);
1058 vfprintf(stderr
, error_str
, pvar
);
1064 // called by functions in path.c
1065 void path_error(const char *fmt
, ...)
1067 fprintf(stderr
, "File error: ");
1069 va_start(parameters
, fmt
);
1070 vfprintf(stderr
, fmt
, parameters
);