char *usr_cmd(int fd, t_history *histo, t_options options) { struct termios set; struct termios unset; char *str; char *cmd; int rev_c; int histo_pl; (void)options; if (init_termios(&set, &unset) == -1 || init_values(&histo_pl, &rev_c, &str, &cmd) == -1) return (unset_termios(&unset)); show_cmd(str[0], fd, cmd, rev_c); while (str[0] != 10 || str[1] != 0 || str[2] != 0) { if (read_cmd(fd, &str, &cmd, &rev_c) == -1) return (unset_termios(&unset)); if (histo_pl < length_of_history(histo) && chk_str(str, 27, 91, 65) == 0) if (take_cmd_from_history(++histo_pl, &rev_c, &cmd, histo) == -1) return (unset_termios(&unset)); if (histo_pl > 0 && chk_str(str, 27, 91, 66) == 0) if (take_cmd_from_history(--histo_pl, &rev_c, &cmd, histo) == -1) return (unset_termios(&unset)); show_cmd(str[0], fd, cmd, rev_c); } return (finish_usr_cmd(cmd, str, unset)); }
int run_program(int flags, const char *cmd, ...) { va_list ap; struct winsize win; int ret; WINDOW *actionwin = NULL; char *scmd; char **args; const char *errstr = NULL; va_start(ap, cmd); vasprintf(&scmd, cmd, ap); va_end(ap); if (scmd == NULL) err(1, "vasprintf(&scmd, \"%s\", ...)", cmd); args = make_argv(scmd); /* Make curses save tty settings */ def_prog_mode(); (void)ioctl(STDIN_FILENO, TIOCGWINSZ, &win); /* Apparently, we sometimes get 0x0 back, and that's not useful */ if (win.ws_row == 0) win.ws_row = 24; if (win.ws_col == 0) win.ws_col = 80; if ((flags & RUN_DISPLAY) != 0) { if (flags & RUN_FULLSCREEN) { wclear(stdscr); clearok(stdscr, 1); touchwin(stdscr); refresh(); actionwin = stdscr; } else actionwin = show_cmd(scmd, &win); } else win.ws_row -= 4; ret = launch_subwin(&actionwin, args, &win, flags, scmd, &errstr); fpurge(stdin); /* If the command failed, show command name */ if (actionwin == NULL && ret != 0 && !(flags & RUN_ERROR_OK)) actionwin = show_cmd(scmd, &win); if (actionwin != NULL) { int y, x; getyx(actionwin, y, x); if (actionwin != stdscr) mvaddstr(0, 4, msg_string(MSG_Status)); if (ret != 0) { if (actionwin == stdscr && x != 0) addstr("\n"); x = 1; /* force newline below */ standout(); addstr(errstr); standend(); } else { if (actionwin != stdscr) { standout(); addstr(msg_string(MSG_Finished)); standend(); } } clrtoeol(); refresh(); if ((ret != 0 && !(flags & RUN_ERROR_OK)) || (y + x != 0 && !(flags & RUN_PROGRESS))) { if (actionwin != stdscr) move(getbegy(actionwin) - 2, 5); else if (x != 0) addstr("\n"); addstr(msg_string(MSG_Hit_enter_to_continue)); refresh(); getchar(); } else { if (y + x != 0) { /* give user 1 second to see messages */ refresh(); sleep(1); } } } /* restore tty setting we saved earlier */ reset_prog_mode(); /* clean things up */ if (actionwin != NULL) { if (actionwin != stdscr) delwin(actionwin); if (errstr == 0 || !(flags & RUN_NO_CLEAR)) { wclear(stdscr); touchwin(stdscr); clearok(stdscr, 1); refresh(); } } free(scmd); free_argv(args); if (ret != 0 && flags & RUN_FATAL) exit(ret); return ret; }
/* * launch a program inside a subwindow, and report its return status when done */ static int launch_subwin(WINDOW **actionwin, char **args, struct winsize *win, int flags, const char *scmd, const char **errstr) { int n, i; int selectfailed; int status, master, slave; fd_set active_fd_set, read_fd_set; pid_t child, pid; char ibuf[MAXBUF]; char pktdata; char *cp, *ncp; struct termios rtt, tt; struct timeval tmo; static int do_tioccons = 2; (void)tcgetattr(STDIN_FILENO, &tt); if (openpty(&master, &slave, NULL, &tt, win) == -1) { *errstr = "openpty() failed"; return -1; } rtt = tt; /* ignore tty signals until we're done with subprocess setup */ ttysig_ignore = 1; ioctl(master, TIOCPKT, &ttysig_ignore); /* Try to get console output into our pipe */ if (do_tioccons) { if (ioctl(slave, TIOCCONS, &do_tioccons) == 0 && do_tioccons == 2) { /* test our output - we don't want it grabbed */ write(1, " \b", 2); ioctl(master, FIONREAD, &do_tioccons); if (do_tioccons != 0) { do_tioccons = 0; ioctl(slave, TIOCCONS, &do_tioccons); } else do_tioccons = 1; } } if (logfp) fflush(logfp); if (script) fflush(script); child = fork(); switch (child) { case -1: ttysig_ignore = 0; refresh(); *errstr = "fork() failed"; return -1; case 0: /* child */ (void)close(STDIN_FILENO); /* silently stop curses */ (void)close(STDOUT_FILENO); (void)open("/dev/null", O_RDWR, 0); dup2(STDIN_FILENO, STDOUT_FILENO); endwin(); (void)close(master); rtt = tt; rtt.c_lflag |= (ICANON|ECHO); (void)tcsetattr(slave, TCSANOW, &rtt); login_tty(slave); if (logfp) { fprintf(logfp, "executing: %s\n", scmd); fclose(logfp); logfp = NULL; } if (script) { fprintf(script, "%s\n", scmd); fclose(script); script = NULL; } if (strcmp(args[0], "cd") == 0 && strcmp(args[2], "&&") == 0) { target_chdir_or_die(args[1]); args += 3; } if (flags & RUN_XFER_DIR) target_chdir_or_die(xfer_dir); /* * If target_prefix == "", the chroot will fail, but * that's ok, since we don't need it then. */ if (flags & RUN_CHROOT && *target_prefix() && chroot(target_prefix()) != 0) warn("chroot(%s) for %s", target_prefix(), *args); else { execvp(*args, args); warn("execvp %s", *args); } _exit(EXIT_FAILURE); // break; /* end of child */ default: /* * parent: we've set up the subprocess. * forward tty signals to its process group. */ ttysig_forward = child; ttysig_ignore = 0; break; } /* * Now loop transferring program output to screen, and keyboard * input to the program. */ FD_ZERO(&active_fd_set); FD_SET(master, &active_fd_set); FD_SET(STDIN_FILENO, &active_fd_set); for (selectfailed = 0;;) { if (selectfailed) { const char mmsg[] = "select(2) failed but no child died?"; if (logfp) (void)fprintf(logfp, mmsg); errx(1, mmsg); } read_fd_set = active_fd_set; tmo.tv_sec = flags & RUN_SILENT ? 20 : 2; tmo.tv_usec = 0; i = select(FD_SETSIZE, &read_fd_set, NULL, NULL, &tmo); if (i == 0 && *actionwin == NULL && (flags & RUN_SILENT) == 0) *actionwin = show_cmd(scmd, win); if (i < 0) { if (errno != EINTR) { warn("select"); if (logfp) (void)fprintf(logfp, "select failure: %s\n", strerror(errno)); selectfailed = 1; } } else for (i = 0; i < FD_SETSIZE; ++i) { if (!FD_ISSET(i, &read_fd_set)) continue; n = read(i, ibuf, sizeof ibuf - 1); if (n <= 0) { if (n < 0) warn("read"); continue; } ibuf[n] = 0; cp = ibuf; if (i == STDIN_FILENO) { (void)write(master, ibuf, (size_t)n); if (!(rtt.c_lflag & ECHO)) continue; } else { pktdata = ibuf[0]; if (pktdata != 0) { if (pktdata & TIOCPKT_IOCTL) memcpy(&rtt, ibuf, sizeof(rtt)); continue; } cp += 1; } if (*cp == 0 || flags & RUN_SILENT) continue; if (logfp) { fprintf(logfp, "%s", cp); fflush(logfp); } if (*actionwin == NULL) *actionwin = show_cmd(scmd, win); /* posix curses is braindead wrt \r\n so... */ for (ncp = cp; (ncp = strstr(ncp, "\r\n")); ncp += 2) { ncp[0] = '\n'; ncp[1] = '\r'; } waddstr(*actionwin, cp); wrefresh(*actionwin); } pid = wait4(child, &status, WNOHANG, 0); if (pid == child && (WIFEXITED(status) || WIFSIGNALED(status))) break; } close(master); close(slave); if (logfp) fflush(logfp); /* from here on out, we take tty signals ourselves */ ttysig_forward = 0; reset_prog_mode(); if (WIFEXITED(status)) { *errstr = msg_string(MSG_Command_failed); return WEXITSTATUS(status); } if (WIFSIGNALED(status)) { *errstr = msg_string(MSG_Command_ended_on_signal); return WTERMSIG(status); } return 0; }
int main(int argc, char **argv) { struct videohub_data *data = &maindata; parse_options(data, argc, argv); set_log_io_errors(0); if (!test_data) { data->dev_fd = connect_client(SOCK_STREAM, data->dev_host, data->dev_port); if (data->dev_fd < 0) exit(EXIT_FAILURE); } reset_routed_to(&data->inputs); reset_routed_to(&data->outputs); reset_routed_to(&data->serial); reset_routed_to(&data->proc_units); reset_routed_to(&data->frames); read_device_command_stream(data); if (test_data) parse_text_buffer(data, test_data); if (!strlen(data->device.protocol_ver) || !strlen(data->device.model_name)) die("The device does not respond correctly. Is it Videohub?"); if (strstr(data->device.protocol_ver, "2.") != data->device.protocol_ver) q("WARNING: Device protocol is %s but this program is tested with 2.x only.\n", data->device.protocol_ver); if (!data->device.dev_present) { if (data->device.needs_fw_update) { die("Device reports that it needs firmware update."); } die("Device reports that it is not present."); } check_number_of_ports(&data->inputs); check_number_of_ports(&data->outputs); check_number_of_ports(&data->mon_outputs); check_number_of_ports(&data->serial); check_number_of_ports(&data->proc_units); check_number_of_ports(&data->frames); if (num_parsed_cmds) { unsigned int i; for (i = 0; i < ARRAY_SIZE(parsed_cmds.entry); i++) { struct vcmd_entry *ve = &parsed_cmds.entry[i]; if (!ve->p1.param) continue; prepare_cmd_entry(data, &parsed_cmds.entry[i]); } for (i = 0; i < ARRAY_SIZE(parsed_cmds.entry); i++) { char cmd_buffer[1024]; struct vcmd_entry *ve = &parsed_cmds.entry[i]; if (!ve->p1.param) continue; format_cmd_text(ve, cmd_buffer, sizeof(cmd_buffer)); if (strlen(cmd_buffer)) { show_cmd(data, ve); send_device_command(data, cmd_buffer); read_device_command_stream(data); } } // Show the result after commands if (test_data) print_device_full(data); } else if (show_monitor) { while (1) { int sleeps = 0; printf("\e[2J\e[H"); // Clear screen time_t now = time(NULL); struct tm *tm = localtime(&now); printf("Last update: %s\n", asctime(tm)); print_device_info(data); print_device_video_inputs(data); print_device_video_outputs(data); fflush(stdout); do { usleep(500000); if (++sleeps >= 20) send_device_command(data, "PING:\n\n"); } while (read_device_command_stream(data) == 0); } } else if (show_list) {