/* Create pty and fork/exec target process */ pid_t exec_target(int master_fd, char* argv[], int pty_alloc_only) { pid_t pid; pid = fork(); if (pid < 0) { perror("Failed to fork"); exit(EXIT_FAILURE); } if (pid == 0) { int slave_fd; int i; /* new session for obtain ctty */ if (setsid() < 0) { perror("Failed to setsid"); exit(EXIT_FAILURE); } slave_fd = open(ptsname(master_fd), O_RDWR); close(master_fd); if (slave_fd < 0) { perror("Failed to open slave pty"); exit(EXIT_FAILURE); } if (pty_alloc_only) set_tty_echo_on(slave_fd); for (i = 0; i < 3; i++) { if (slave_fd != i) { dup2(slave_fd, i); fcntl(i, F_SETFD, 0); } } if (slave_fd > 2) close(slave_fd); /* make new process group and make it foreground */ if (setpgid(0, 0) < 0) perror("Failed to setpgid"); if (tcsetpgrp(0, getpgid(getpid())) < 0) perror("Failed to change foreground pgid"); if (pty_alloc_only) /* do nothing. wait for kill */ select(0, NULL, NULL, NULL, NULL); else execvp(argv[0], argv); fprintf(stderr, "Failed to execute \"%s\": %s\n", argv[0], strerror(errno)); exit(EXIT_FAILURE); } return pid; }
int main(int argc, char* argv[]) { fd_set sel, sel0; int status; int pty_hold_mode = FALSE; char* newarg0; /* SIGINT and SIGBREAK are indistinctive under cygwin environment. */ /* Using Win32API to handle SIGINT. */ SetConsoleCtrlHandler(ctrl_handler, TRUE); if (argc < 1) { fputs("Unable to get arg[0].", stderr); exit(EXIT_FAILURE); } newarg0 = real_command_name(argv[0]); if (newarg0) argv[0] = newarg0; else if (argc >=2) argv++; else pty_hold_mode = TRUE; if (isatty(STDIN_FILENO) && !pty_hold_mode) { execvp(argv[0], argv); fprintf(stderr, "Failed to execute \"%s\": %s\n", argv[0], strerror(errno)); exit(EXIT_FAILURE); } masterfd = open_master_pty(); if (!pty_hold_mode) child_pid = exec_target(masterfd, argv); else set_tty_echo_on(masterfd); setup_signal_handlers(); FD_ZERO(&sel0); FD_SET(masterfd, &sel0); FD_SET(STDIN_FILENO, &sel0); /* communication loop */ while (1) { char buf[BUFSIZE]; int ret; if (sig_winch_caught == TRUE) { sig_winch_caught = FALSE; if (child_pid != -1 && resize_tty_window(masterfd, sig_window_size) == 0) kill(child_pid, SIGWINCH); } sel = sel0; if (select (FD_SETSIZE, &sel, NULL, NULL, NULL) <= 0) { if(errno == EINTR) continue; else break; } if (FD_ISSET(masterfd, &sel)) { ret = safe_read(masterfd, buf, BUFSIZE); if (ret > 0) { if (safe_write_full(STDOUT_FILENO, buf, ret) < 0) break; } else break; } else if (FD_ISSET(STDIN_FILENO, &sel)) { ret = safe_read(STDIN_FILENO, buf, BUFSIZE); if (ret > 0) { if (safe_write_full_checking_eof(masterfd, buf, ret) < 0) break; } else { FD_CLR(STDIN_FILENO, &sel0); close(masterfd); } } } if (pty_hold_mode) { status = 0; } else { while(waitpid(child_pid, &status, 0) < 0 && errno == EINTR) ; if (WIFEXITED(status)) status = WEXITSTATUS(status); else if(WIFSIGNALED(status)) /* ntemacs cannot distinct killed by signal */ status = 0x80 + WTERMSIG(status); } return status; }