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
19 * Szabo, Janos Zoltan – initial implementation
21 * Zalanyi, Balazs Andor
22 * Roland Gecse - author
24 ******************************************************************************/
26 // Description: Implementation file for Cli
28 //----------------------------------------------------------------------------
30 #include "../mctr/MainController.h"
33 #include "../editline/libedit/src/editline/readline.h"
39 #include <arpa/inet.h>
40 #include "../../common/version_internal.h"
41 #include "../../common/memory.h"
42 #include "../../common/config_preproc.h"
44 #define PROMPT "MC2> "
45 #define CMTC_TEXT "cmtc"
46 #define SMTC_TEXT "smtc"
47 #define EMTC_TEXT "emtc"
48 #define STOP_TEXT "stop"
49 #define PAUSE_TEXT "pause"
50 #define CONTINUE_TEXT "continue"
51 #define INFO_TEXT "info"
52 #define HELP_TEXT "help"
53 #define RECONF_TEXT "reconf"
54 #define LOG_TEXT "log"
55 #define SHELL_TEXT "!"
56 #define EXIT_TEXT "quit"
57 #define EXIT_TEXT2 "exit"
58 #define SHELL_ESCAPE '!'
59 #define TTCN3_HISTORY_FILENAME ".ttcn3_history"
61 using mctr::MainController
;
65 * shell_mode == TRUE while editing a command line that is passed to the shell
67 static boolean shell_mode
;
71 callback_t callback_function
;
73 const char *description
;
76 static const Command command_list
[] = {
77 { CMTC_TEXT
, &Cli::cmtcCallback
, CMTC_TEXT
" [hostname]",
79 { SMTC_TEXT
, &Cli::smtcCallback
,
80 SMTC_TEXT
" [module_name[[.control]|.testcase_name|.*]",
81 "Start MTC with control part, test case or all test cases." },
82 { STOP_TEXT
, &Cli::stopCallback
, STOP_TEXT
,
83 "Stop test execution." },
84 { PAUSE_TEXT
, &Cli::pauseCallback
, PAUSE_TEXT
" [on|off]",
85 "Set whether to interrupt test execution after each "
87 { CONTINUE_TEXT
, &Cli::continueCallback
, CONTINUE_TEXT
,
88 "Resumes interrupted test execution." },
89 { EMTC_TEXT
, &Cli::emtcCallback
, EMTC_TEXT
, "Terminate MTC." },
90 { LOG_TEXT
, &Cli::logCallback
, LOG_TEXT
" [on|off]",
91 "Enable/disable console logging." },
92 { INFO_TEXT
, &Cli::infoCallback
, INFO_TEXT
,
93 "Display test configuration information." },
94 { RECONF_TEXT
, &Cli::reconfCallback
, RECONF_TEXT
" [config_file]",
95 "Reload configuration file." },
96 { HELP_TEXT
, &Cli::helpCallback
, HELP_TEXT
" <command>",
97 "Display help on command." },
98 { SHELL_TEXT
, &Cli::shellCallback
, SHELL_TEXT
"[shell cmds]",
99 "Execute commands in subshell." },
100 { EXIT_TEXT
, &Cli::exitCallback
, EXIT_TEXT
, "Exit Main Controller." },
101 { EXIT_TEXT2
, &Cli::exitCallback
, EXIT_TEXT2
, "Exit Main Controller." },
102 { NULL
, NULL
, NULL
, NULL
}
107 loggingEnabled
= TRUE
;
109 waitState
= WAIT_NOTHING
;
110 executeListIndex
= 0;
112 if (pthread_mutex_init(&mutex
, NULL
)) {
113 perror("Cli::Cli: pthread_mutex_init failed.");
116 if (pthread_cond_init(&cond
, NULL
)) {
117 perror("Cli::Cli: pthread_cond_init failed.");
124 pthread_mutex_destroy(&mutex
);
125 pthread_cond_destroy(&cond
);
128 //----------------------------------------------------------------------------
131 int Cli::enterLoop(int argc
, char *argv
[])
133 // Parameter check: mctr [config file name]
142 printf("Using configuration file: %s\n", argv
[1]);
143 if (process_config_read_file(argv
[1], &mycfg
)) {
144 puts("Error was found in the configuration file. Exiting.");
149 MainController::set_kill_timer(mycfg
.kill_timer
);
151 for (int i
= 0; i
< mycfg
.group_list_len
; ++i
) {
152 MainController::add_host(mycfg
.group_list
[i
].group_name
,
153 mycfg
.group_list
[i
].host_name
);
156 for (int i
= 0; i
< mycfg
.component_list_len
; ++i
) {
157 MainController::assign_component(mycfg
.component_list
[i
].host_or_group
,
158 mycfg
.component_list
[i
].component
);
164 if (mycfg
.num_hcs
<= 0) ret_val
= interactiveMode();
165 else ret_val
= batchMode();
171 //----------------------------------------------------------------------------
174 void Cli::status_change()
177 if (waitState
!= WAIT_NOTHING
&& conditionHolds(waitState
)) {
178 waitState
= WAIT_NOTHING
;
184 //----------------------------------------------------------------------------
187 void Cli::error(int /*severity*/, const char *message
)
189 printf("Error: %s\n", message
);
191 // TODO: Error handling based on the MC state where the error happened
194 //----------------------------------------------------------------------------
197 void Cli::notify(const struct timeval
*timestamp
, const char *source
,
198 int /*severity*/, const char *message
)
202 switch(mycfg
.tsformat
){
203 case TSF_TIME
: // handled together
206 time_t tv_sec
= timestamp
->tv_sec
;
207 struct tm
*lt
= localtime(&tv_sec
);
209 printf("localtime() call failed.");
210 printf("%s: %s\n", source
, message
);
214 if (mycfg
.tsformat
== TSF_TIME
) {
215 printf("%02d:%02d:%02d.%06ld %s: %s\n",
216 lt
->tm_hour
, lt
->tm_min
, lt
->tm_sec
, timestamp
->tv_usec
,source
, message
);
218 static const char * const month_names
[] = { "Jan", "Feb", "Mar",
219 "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
220 printf("%4d/%s/%02d %02d:%02d:%02d.%06ld %s: %s\n",
221 lt
->tm_year
+ 1900, month_names
[lt
->tm_mon
],
222 lt
->tm_mday
, lt
->tm_hour
, lt
->tm_min
, lt
->tm_sec
,
230 printf("%ld.%06ld %s: %s\n", (long)timestamp
->tv_sec
, timestamp
->tv_usec
, source
, message
);
235 printf("%s: %s\n", source
, message
);
242 //----------------------------------------------------------------------------
249 //----------------------------------------------------------------------------
252 void Cli::printWelcome()
255 "*************************************************************************\n"
256 "* TTCN-3 Test Executor - Main Controller 2 *\n"
257 "* Version: %-40s *\n"
258 "* Copyright (c) 2000-2016 Ericsson Telecom AB *\n"
259 "* All rights reserved. This program and the accompanying materials *\n"
260 "* are made available under the terms of the Eclipse Public License v1.0 *\n"
261 "* which accompanies this distribution, and is available at *\n"
262 "* http://www.eclipse.org/legal/epl-v10.html *\n"
263 "*************************************************************************\n"
264 "\n", PRODUCT_NUMBER
);
267 void Cli::printUsage(const char *prg_name
)
270 "TTCN-3 Test Executor - Main Controller 2\n"
271 "Version: " PRODUCT_NUMBER
"\n\n"
272 "usage: %s [configuration_file]\n"
273 "where: the optional 'configuration_file' parameter specifies the name "
274 "and\nlocation of the main controller configuration file"
278 //----------------------------------------------------------------------------
281 int Cli::interactiveMode()
283 // Initialize history library
286 const char *home_directory
= getenv("HOME");
287 if(home_directory
== NULL
)
288 home_directory
= ".";
289 char *ttcn3_history_filename
= mprintf("%s/%s", home_directory
,
290 TTCN3_HISTORY_FILENAME
);
291 // Read history from file, don't bother if it does not exist!
292 read_history(ttcn3_history_filename
);
293 // Set our own command completion function
294 rl_completion_entry_function
= (Function
*)completeCommand
;
295 // Override rl_getc() in order to detect shell mode
296 rl_getc_function
= getcWithShellDetection
;
298 // TCP listen port parameter, returns TCP port on which it listens!
299 // Returns 0 on error.
300 if (MainController::start_session(mycfg
.local_addr
, mycfg
.tcp_listen_port
,
301 mycfg
.unix_sockets_enabled
) == 0) {
302 puts("Initialization of TCP server failed. Exiting.");
303 Free(ttcn3_history_filename
);
308 char *line_read
= readline(PROMPT
);
309 if (line_read
!= NULL
) {
313 add_history(line_read
); // history maintains its own copy
314 // process and free line
315 processCommand(line_read
);
326 if (write_history(ttcn3_history_filename
))
327 perror("Could not save history.");
328 Free(ttcn3_history_filename
);
335 printf("Entering batch mode. Waiting for %d HC%s to connect...\n",
336 mycfg
.num_hcs
, mycfg
.num_hcs
> 1 ? "s" : "");
337 if (mycfg
.execute_list_len
<= 0) {
338 puts("No [EXECUTE] section was given in the configuration file. "
342 boolean error_flag
= FALSE
;
343 // start to listen on TCP port
344 if (MainController::start_session(mycfg
.local_addr
, mycfg
.tcp_listen_port
,
345 mycfg
.unix_sockets_enabled
) == 0) {
346 puts("Initialization of TCP server failed. Exiting.");
349 waitMCState(WAIT_HC_CONNECTED
);
350 // download config file
351 MainController::configure(mycfg
.config_read_buffer
);
352 waitMCState(WAIT_ACTIVE
);
353 if (MainController::get_state() != mctr::MC_ACTIVE
) {
354 puts("Error during initialization. Cannot continue in batch mode.");
358 // create MTC on firstly connected HC
359 MainController::create_mtc(0);
360 waitMCState(WAIT_MTC_CREATED
);
361 if (MainController::get_state() != mctr::MC_READY
) {
362 puts("Creation of MTC failed. Cannot continue in batch mode.");
367 // execute each item of the list
368 for (int i
= 0; i
< mycfg
.execute_list_len
; i
++) {
370 waitMCState(WAIT_MTC_READY
);
371 if (MainController::get_state() != mctr::MC_READY
) {
372 puts("MTC terminated unexpectedly. Cannot continue in batch "
381 MainController::exit_mtc();
382 waitMCState(WAIT_MTC_TERMINATED
);
384 // now MC must be in state MC_ACTIVE anyway
386 MainController::shutdown_session();
387 waitMCState(WAIT_SHUTDOWN_COMPLETE
);
388 if (error_flag
) return EXIT_FAILURE
;
389 else return EXIT_SUCCESS
;
392 //----------------------------------------------------------------------------
395 void Cli::processCommand(char *line_read
)
397 for (const Command
*command
= command_list
; command
->name
!= NULL
;
399 size_t command_name_len
= strlen(command
->name
);
400 if (!strncmp(line_read
, command
->name
, command_name_len
)) {
401 memset(line_read
, ' ', command_name_len
);
403 (this->*command
->callback_function
)(line_read
);
407 puts("Unknown command, try again...");
410 //----------------------------------------------------------------------------
412 // Create Main Test Component
414 void Cli::cmtcCallback(const char *arguments
)
417 if(*arguments
== 0) hostIndex
= 0;
419 hostIndex
= getHostIndex(arguments
);
420 if (hostIndex
< 0) return;
422 switch (MainController::get_state()) {
423 case mctr::MC_LISTENING
:
424 case mctr::MC_LISTENING_CONFIGURED
:
425 puts("Waiting for HC to connect...");
426 waitMCState(WAIT_HC_CONNECTED
);
427 case mctr::MC_HC_CONNECTED
:
428 MainController::configure(mycfg
.config_read_buffer
);
429 waitMCState(WAIT_ACTIVE
);
430 if (MainController::get_state() != mctr::MC_ACTIVE
) {
431 puts("Error during initialization. Cannot create MTC.");
434 case mctr::MC_ACTIVE
:
435 MainController::create_mtc(hostIndex
);
436 waitMCState(WAIT_MTC_CREATED
);
439 puts("MTC already exists.");
444 //----------------------------------------------------------------------------
446 // Start Main Test Component and execute the
447 // a) control part or testcase (or *) given in arguments
448 // b) EXECUTE part of supplied configuration file -- if arguments==NULL
450 void Cli::smtcCallback(const char *arguments
)
452 switch (MainController::get_state()) {
453 case mctr::MC_LISTENING
:
454 case mctr::MC_LISTENING_CONFIGURED
:
455 case mctr::MC_HC_CONNECTED
:
456 case mctr::MC_ACTIVE
:
457 puts("MTC does not exist.");
460 if (*arguments
== 0) {
461 // Execute configuration file's execute section
462 if (mycfg
.execute_list_len
> 0) {
463 puts("Executing all items of [EXECUTE] section.");
464 waitState
= WAIT_EXECUTE_LIST
;
465 executeListIndex
= 0;
468 puts("No [EXECUTE] section was given in the configuration "
471 } else { // Check the arguments
472 size_t doti
= 0, alen
= strlen(arguments
), state
= 0;
473 for (size_t r
= 0; r
< alen
; r
++) {
474 switch (arguments
[r
]) {
485 if(state
> 1) { // incorrect argument
486 puts("Incorrect argument format.");
487 helpCallback(SMTC_TEXT
);
489 if(state
== 0) { // only modulename is given in arguments
490 MainController::execute_control(arguments
);
491 } else { // modulename.something in arguments
492 expstring_t arg_copy
= mcopystr(arguments
);
493 arg_copy
[doti
++] = '\0';
494 if (!strcmp(arg_copy
+ doti
, "*"))
495 MainController::execute_testcase(arg_copy
, NULL
);
496 else if (!strcmp(arg_copy
+ doti
, "control"))
497 MainController::execute_control(arg_copy
);
498 else MainController::execute_testcase(arg_copy
,
506 puts("MTC is busy.");
511 //----------------------------------------------------------------------------
513 // Stops test execution
515 void Cli::stopCallback(const char *arguments
)
517 if (*arguments
== 0) {
518 switch (MainController::get_state()) {
519 case mctr::MC_TERMINATING_TESTCASE
:
520 case mctr::MC_EXECUTING_CONTROL
:
521 case mctr::MC_EXECUTING_TESTCASE
:
522 case mctr::MC_PAUSED
:
523 MainController::stop_execution();
524 if (waitState
== WAIT_EXECUTE_LIST
) waitState
= WAIT_NOTHING
;
527 puts("Tests are not running.");
529 } else helpCallback(STOP_TEXT
);
532 //----------------------------------------------------------------------------
534 // Sets whether to interrupt test execution after testcase
536 void Cli::pauseCallback(const char *arguments
)
538 if (arguments
[0] != '\0') {
539 if (!strcmp(arguments
, "on")) {
540 if (!MainController::get_stop_after_testcase()) {
541 MainController::stop_after_testcase(TRUE
);
542 puts("Pause function is enabled. "
543 "Execution will stop at the end of each testcase.");
544 } else puts("Pause function is already enabled.");
545 } else if (!strcmp(arguments
, "off")) {
546 if (MainController::get_stop_after_testcase()) {
547 MainController::stop_after_testcase(FALSE
);
548 puts("Pause function is disabled. "
549 "Execution will continue at the end of each testcase.");
550 } else puts("Pause function is already disabled.");
551 } else helpCallback(PAUSE_TEXT
);
552 } else printf("Pause function is %s.\n",
553 MainController::get_stop_after_testcase() ? "enabled" : "disabled");
556 //----------------------------------------------------------------------------
558 // Resumes interrupted test execution
560 void Cli::continueCallback(const char *arguments
)
562 if (*arguments
== 0) {
563 switch (MainController::get_state()) {
564 case mctr::MC_TERMINATING_TESTCASE
:
565 case mctr::MC_EXECUTING_CONTROL
:
566 case mctr::MC_EXECUTING_TESTCASE
:
567 puts("Execution is not paused.");
569 case mctr::MC_PAUSED
:
570 MainController::continue_testcase();
573 puts("Tests are not running.");
575 } else helpCallback(CONTINUE_TEXT
);
578 //----------------------------------------------------------------------------
580 // Exit Main Test Component
582 void Cli::emtcCallback(const char *arguments
)
584 if(*arguments
== 0) {
585 switch (MainController::get_state()) {
586 case mctr::MC_LISTENING
:
587 case mctr::MC_LISTENING_CONFIGURED
:
588 case mctr::MC_HC_CONNECTED
:
589 case mctr::MC_ACTIVE
:
590 puts("MTC does not exist.");
593 MainController::exit_mtc();
594 waitMCState(WAIT_MTC_TERMINATED
);
597 puts("MTC cannot be terminated.");
600 helpCallback(EMTC_TEXT
);
604 //----------------------------------------------------------------------------
606 // Controls console logging
608 void Cli::logCallback(const char *arguments
)
610 if (arguments
[0] != '\0') {
611 if (!strcmp(arguments
, "on")) {
612 loggingEnabled
= TRUE
;
613 puts("Console logging is enabled.");
614 } else if (!strcmp(arguments
, "off")) {
615 loggingEnabled
= FALSE
;
616 puts("Console logging is disabled.");
617 } else helpCallback(LOG_TEXT
);
618 } else printf("Console logging is %s.\n",
619 loggingEnabled
? "enabled" : "disabled");
622 //----------------------------------------------------------------------------
624 // Print connection information
626 void Cli::infoCallback(const char *arguments
)
628 if (*arguments
== 0) printInfo();
629 else helpCallback(INFO_TEXT
);
632 //----------------------------------------------------------------------------
634 // Reconfigure MC and HCs
636 void Cli::reconfCallback(const char *arguments
)
638 if(*arguments
== 0) { // reconf called without its optional argument
639 puts("Reconfiguration of MC and HCs using original configuration "
640 "data\n -- not supported, yet.");
641 } else { // reconf called with config_file argument
642 puts("Reconfiguration of MC and HCs using configuration file"
643 "specified in\ncommand line argument -- not supported, yet.");
647 //----------------------------------------------------------------------------
649 // Print general help or help on command usage to console
651 void Cli::helpCallback(const char *arguments
)
653 if (*arguments
== 0) {
654 puts("Help is available for the following commands:");
655 for (const Command
*command
= command_list
;
656 command
->name
!= NULL
; command
++) {
657 printf(" %s", command
->name
);
661 for (const Command
*command
= command_list
;
662 command
->name
!= NULL
; command
++) {
663 if (!strncmp(arguments
, command
->name
,
664 strlen(command
->name
))) {
665 printf("%s usage: %s\n%s\n", command
->name
,
667 command
->description
);
671 printf("No help for %s.\n", arguments
);
675 //----------------------------------------------------------------------------
677 // Pass command to shell
679 void Cli::shellCallback(const char *arguments
)
681 if(system(arguments
) == -1) {
682 perror("Error executing command in subshell.");
686 //----------------------------------------------------------------------------
688 // User initiated MC termination, exits the program.
689 // Save history into file and terminate CLI session.
691 void Cli::exitCallback(const char *arguments
)
693 if (*arguments
== 0) {
694 switch (MainController::get_state()) {
696 MainController::exit_mtc();
697 waitMCState(WAIT_MTC_TERMINATED
);
698 case mctr::MC_LISTENING
:
699 case mctr::MC_LISTENING_CONFIGURED
:
700 case mctr::MC_HC_CONNECTED
:
701 case mctr::MC_ACTIVE
:
702 MainController::shutdown_session();
703 waitMCState(WAIT_SHUTDOWN_COMPLETE
);
707 puts("Cannot exit until execution is finished.");
710 helpCallback(EXIT_TEXT
);
714 //----------------------------------------------------------------------------
716 // Command completion function implementation for readline() library.
717 // Heavily uses the ``static Command command_list[]'' array!
719 char *Cli::completeCommand(const char *prefix
, int state
)
721 static int command_index
;
722 static size_t prefix_len
;
723 const char *command_name
;
726 return rl_filename_completion_function(prefix
, state
);
730 prefix_len
= strlen(prefix
);
733 while((command_name
= command_list
[command_index
].name
)) {
735 if(strncmp(prefix
, command_name
, prefix_len
) == 0) {
736 // Must allocate buffer for returned string (readline frees it)
737 return strdup(command_name
);
744 //----------------------------------------------------------------------------
746 // Character input function implementation for readline() library.
748 int Cli::getcWithShellDetection(FILE *fp
)
750 int input_char
= getc(fp
);
751 if(input_char
== SHELL_ESCAPE
)
757 //----------------------------------------------------------------------------
760 void Cli::stripLWS(char *input_text
)
762 if(input_text
== NULL
) {
763 puts("stripLWS() called with NULL.");
764 exit(EXIT_FAILURE
); // This shall never happen
766 size_t head_index
, tail_index
, input_len
= strlen(input_text
);
767 if(input_len
< 1) return;
768 for(head_index
= 0; isspace(input_text
[head_index
]); head_index
++) ;
769 for(tail_index
= input_len
- 1; tail_index
>= head_index
&&
770 isspace(input_text
[tail_index
]); tail_index
--) ;
771 size_t output_len
= tail_index
- head_index
+ 1;
772 memmove(input_text
, input_text
+ head_index
, output_len
);
773 memset(input_text
+ output_len
, 0, input_len
- output_len
);
776 const char *Cli::verdict2str(verdicttype verdict
)
794 //----------------------------------------------------------------------------
797 void Cli::printInfo()
799 puts("MC information:");
800 printf(" MC state: %s\n",
801 MainController::get_mc_state_name(MainController::get_state()));
802 puts(" host information:");
804 for ( ; ; host_index
++) {
805 mctr::host_struct
*host
= MainController::get_host_data(host_index
);
807 printf(" - %s", host
->hostname
);
808 const char *ip_addr
= host
->ip_addr
->get_addr_str();
809 // if the hostname differs from the IP address
810 // (i.e. the host has a DNS entry)
811 if (strcmp(ip_addr
, host
->hostname
)) printf(" [%s]", ip_addr
);
812 // if the local hostname differs from the prefix of the DNS name
813 if (strncmp(host
->hostname
, host
->hostname_local
,
814 strlen(host
->hostname_local
)))
815 printf(" (%s)", host
->hostname_local
);
817 printf(" operating system: %s %s on %s\n", host
->system_name
,
818 host
->system_release
, host
->machine_type
);
819 printf(" HC state: %s\n",
820 MainController::get_hc_state_name(host
->hc_state
));
822 puts(" test component information:");
823 // make a copy of the array containing component references
824 int n_components
= host
->n_components
;
825 component
*components
= (component
*)Malloc(n_components
*
827 memcpy(components
, host
->components
, n_components
*
829 // the host structure has to be released in order to get access
830 // to the component structures
831 MainController::release_data();
832 for (int component_index
= 0; component_index
< n_components
;
834 mctr::component_struct
*comp
= MainController::
835 get_component_data(components
[component_index
]);
836 // if the component has a name
837 if (comp
->comp_name
!= NULL
)
838 printf(" - name: %s, component reference: %d\n",
839 comp
->comp_name
, comp
->comp_ref
);
840 else printf(" - component reference: %d\n",
842 if (comp
->comp_type
.definition_name
!= NULL
) {
843 printf(" component type: ");
844 if (comp
->comp_type
.module_name
!= NULL
)
845 printf("%s.", comp
->comp_type
.module_name
);
846 printf("%s\n", comp
->comp_type
.definition_name
);
848 printf(" state: %s\n",
849 MainController::get_tc_state_name(comp
->tc_state
));
850 if (comp
->tc_fn_name
.definition_name
!= NULL
) {
851 printf(" executed %s: ",
852 comp
->comp_ref
== MTC_COMPREF
?
853 "test case" : "function");
854 if (comp
->tc_fn_name
.module_name
!= NULL
)
855 printf("%s.", comp
->tc_fn_name
.module_name
);
856 printf("%s\n", comp
->tc_fn_name
.definition_name
);
858 if (comp
->tc_state
== mctr::TC_EXITING
||
859 comp
->tc_state
== mctr::TC_EXITED
)
860 printf(" local verdict: %s\n",
861 verdict2str(comp
->local_verdict
));
862 MainController::release_data();
864 if (n_components
== 0) puts(" no components on this host");
867 MainController::release_data();
871 if (host_index
== 0) puts(" no HCs are connected");
872 printf(" pause function: %s\n", MainController::get_stop_after_testcase() ?
873 "enabled" : "disabled");
874 printf(" console logging: %s\n", loggingEnabled
?
875 "enabled" : "disabled");
879 //----------------------------------------------------------------------------
884 if (pthread_mutex_lock(&mutex
)) {
885 perror("Cli::lock: pthread_mutex_lock failed.");
892 if (pthread_mutex_unlock(&mutex
)) {
893 perror("Cli::unlock: pthread_mutex_unlock failed.");
900 if (pthread_cond_wait(&cond
, &mutex
)) {
901 perror("Cli::wait: pthread_cond_wait failed.");
908 if (pthread_cond_signal(&cond
)) {
909 perror("Cli::signal: pthread_cond_signal failed.");
914 void Cli::waitMCState(waitStateEnum newWaitState
)
917 if (newWaitState
!= WAIT_NOTHING
) {
918 if (conditionHolds(newWaitState
)) {
919 waitState
= WAIT_NOTHING
;
921 waitState
= newWaitState
;
925 fputs("Cli::waitMCState: invalid argument", stderr
);
931 boolean
Cli::conditionHolds(waitStateEnum askedState
)
933 switch (askedState
) {
934 case WAIT_HC_CONNECTED
:
935 if (MainController::get_state() == mctr::MC_HC_CONNECTED
) {
936 if (mycfg
.num_hcs
> 0) {
937 return MainController::get_nof_hosts() >= mycfg
.num_hcs
;
942 switch (MainController::get_state()) {
943 case mctr::MC_ACTIVE
: // normal case
944 case mctr::MC_HC_CONNECTED
: // error happened with config file
945 case mctr::MC_LISTENING
: // even more strange situations
950 case WAIT_MTC_CREATED
:
952 switch (MainController::get_state()) {
953 case mctr::MC_READY
: // normal case
954 case mctr::MC_ACTIVE
: // MTC crashed unexpectedly
955 case mctr::MC_LISTENING_CONFIGURED
: // MTC and all HCs are crashed
957 case mctr::MC_HC_CONNECTED
: // even more strange situations
962 case WAIT_MTC_TERMINATED
:
963 return MainController::get_state() == mctr::MC_ACTIVE
;
964 case WAIT_SHUTDOWN_COMPLETE
:
965 return MainController::get_state() == mctr::MC_INACTIVE
;
966 case WAIT_EXECUTE_LIST
:
967 if (MainController::get_state() == mctr::MC_READY
) {
968 if (++executeListIndex
< mycfg
.execute_list_len
) {
970 executeFromList(executeListIndex
);
973 puts("Execution of [EXECUTE] section finished.");
974 waitState
= WAIT_NOTHING
;
983 int Cli::getHostIndex(const char* hostname
)
985 int hostname_len
= strlen(hostname
);
986 int index
, found
= -1;
987 for (index
= 0; ; index
++) {
988 const mctr::host_struct
*host
=
989 MainController::get_host_data(index
);
991 if (!strncmp(host
->hostname
, hostname
, hostname_len
) ||
992 !strncmp(host
->hostname_local
, hostname
, hostname_len
)) {
993 MainController::release_data();
994 if (found
== -1) found
= index
;
996 printf("Hostname %s is ambiguous.\n", hostname
);
1000 } else MainController::release_data();
1002 MainController::release_data();
1003 if (found
== -1) printf("No such host: %s.\n", hostname
);
1010 void Cli::executeFromList(int index
)
1012 if (index
>= mycfg
.execute_list_len
) {
1013 fputs("Cli::executeFromList: invalid argument", stderr
);
1016 if (mycfg
.execute_list
[index
].testcase_name
== NULL
) {
1017 MainController::execute_control(mycfg
.execute_list
[index
].module_name
);
1018 } else if (!strcmp(mycfg
.execute_list
[index
].testcase_name
, "*")) {
1019 MainController::execute_testcase(mycfg
.execute_list
[index
].module_name
,
1022 MainController::execute_testcase(mycfg
.execute_list
[index
].module_name
,
1023 mycfg
.execute_list
[index
].testcase_name
);
1027 //----------------------------------------------------------------------------
1030 // indent-tabs-mode: nil
1031 // c-basic-offset: 2
1034 extern boolean error_flag
; // in config_read.y
1035 extern std::string
get_cfg_read_current_file(); // in config_read.y
1036 extern int config_read_lineno
; // in config_read.l
1037 extern char *config_read_text
; // in config_read.l
1039 void config_read_warning(const char *warning_str
, ...)
1041 fprintf(stderr
, "Warning: in configuration file `%s', line %d: ",
1042 get_cfg_read_current_file().c_str(), config_read_lineno
);
1044 va_start(pvar
, warning_str
);
1045 vfprintf(stderr
, warning_str
, pvar
);
1050 void config_read_error(const char *error_str
, ...)
1052 fprintf(stderr
, "Parse error in configuration file `%s': in line %d, "
1053 "at or before token `%s': ",
1054 get_cfg_read_current_file().c_str(), config_read_lineno
, config_read_text
);
1056 va_start(pvar
, error_str
);
1057 vfprintf(stderr
, error_str
, pvar
);
1063 void config_preproc_error(const char *error_str
, ...)
1065 fprintf(stderr
, "Parse error while pre-processing configuration file "
1066 "`%s': in line %d: ",
1067 get_cfg_preproc_current_file().c_str(),
1068 config_preproc_yylineno
);
1070 va_start(pvar
, error_str
);
1071 vfprintf(stderr
, error_str
, pvar
);
1077 // called by functions in path.c
1078 void path_error(const char *fmt
, ...)
1080 fprintf(stderr
, "File error: ");
1082 va_start(parameters
, fmt
);
1083 vfprintf(stderr
, fmt
, parameters
);