/** * Run an interactive CLI in non-blocking mode. Does not allow * recursion - only one interactive CLI can be active at the same time. * This function will not return until the user exits the CLI. * * A CLI can only be started from the root mode. If a parser wants to * start a new CLI (for example, when parsing the command line * arguments, one of the arguments requests an interactive CLI), a * whole new TestBaseCli object should be created and the CLI started on * the new object, from the root context. */ rw_status_t TestBaseCli::interactive_nb() { if (editline_) { std::cerr << "CLI is already running" << std::endl; return RW_STATUS_FAILURE; } if (current_mode_ != root_mode_) { std::cerr << "Cannot start CLI outside of root mode context" << std::endl; return RW_STATUS_FAILURE; } editline_ = new CliEditline( *this, stdin, stdout, stderr ); editline_->nonblocking_mode(); int fd = fileno(stdin); fd_set fds = {0}; editline_->read_ready(); // Yes, gratuitous read_ready is needed while (!editline_->should_quit()) { editline_->read_ready(); FD_SET(fd, &fds); int nfds = select( fd+1, &fds, NULL, NULL, NULL ); if (nfds == 1) { RW_ASSERT(FD_ISSET(fd, &fds)); } else if(nfds == -1) { switch (errno) { case EINTR: continue; case EBADF: case EINVAL: default: std::cerr << "Unexpected errno " << errno << std::endl; editline_->quit(); } } else { RW_ASSERT_NOT_REACHED(); // nfds == 0? } } delete editline_; editline_ = NULL; mode_end_even_if_root(); return RW_STATUS_SUCCESS; }
rw_status_t rw_spawn_process(const char *filename, char *const argv[], int set_pgid, pid_t *child_pid) { pid_t pid; pid = fork(); if (pid < 0) { /* fork failed emit error and return */ perror(NULL); return RW_STATUS_SUCCESS; } else if (pid == 0) { /* child process */ fprintf(stdout, "filename: %s\n", filename); int i = 0; while (argv[i] != NULL) { fprintf(stdout, "argv[%d]: %s\n", i, argv[i]); i++; } execvp(filename, argv); /* should never reach here, unless execvp failed */ perror(NULL); RW_ASSERT_NOT_REACHED(); } else { /* This is the parent process */ if (set_pgid) { /* set the process group id of the child to parent's process group id */ if (setpgid(pid, getpgrp())) { fprintf(stdout, "Failed to set %s (%d) process group id\n", filename, pid); } } if (child_pid) { *child_pid = pid; } } return RW_STATUS_SUCCESS; }
/** * Handler for RW.CLI internal message */ static rw_status_t controller_handle_internal_msg( rwcli_controller_t* inst, rwcli_msg_type_t msg_type, rwcli_internal_req_t* req, rwcli_internal_rsp_t** rsp) { rw_status_t status = RW_STATUS_SUCCESS; switch(msg_type) { case RWCLI_MSG_TYPE_GET_TRANSPORT_STATUS: status = controller_handle_get_transport_status(inst); break; case RWCLI_MSG_TYPE_SET_CLI_TRANPORT: status = controller_set_cli_transport(inst, req->u.transport_mode); break; default: RW_ASSERT_NOT_REACHED(); } return status; }