16 #include <sys/ioctl.h>
17 #include <sys/signal.h>
18 #include <sys/types.h>
22 #define DPRINTF(format, args...)
25 bool WvPty::open_pty(
WvString &master,
int &master_fd,
28 const char *xvals =
"pqrstuvwxyzPQRST";
29 const char *yvals =
"0123456789abcdef";
30 char pty[] =
"/dev/ptyXY";
31 char tty[] =
"/dev/ttyXY";
33 for (
int i=0; xvals[i]; ++i)
35 pty[8] = tty[8] = xvals[i];
37 for (
int j=0; yvals[j]; ++j)
39 pty[9] = tty[9] = yvals[j];
41 master_fd = ::open(pty, O_RDWR);
43 slave_fd = ::open(tty, O_RDWR);
45 if (master_fd < 0 || slave_fd < 0)
47 int saved_errno = errno;
48 if (master_fd >= 0)
::close(master_fd);
49 if (slave_fd >= 0)
::close(slave_fd);
50 if (saved_errno == ENOENT)
52 DPRINTF(
"No more PTYs (ENOENT)\n");
58 DPRINTF(
"PTY is %s\n", (master =
WvString(pty)).edit());
59 DPRINTF(
"TTY is %s\n", (slave =
WvString(tty)).edit());
64 struct group *gr = ::getgrnam(
"tty");
65 ::fchown(slave_fd, ::getuid(), gr? gr->gr_gid: (gid_t)-1);
66 ::fchmod(slave_fd, S_IRUSR | S_IWUSR | S_IWGRP);
73 DPRINTF(
"No more PTYs\n");
77 WvPty::WvPty(
const char *program,
const char *
const *argv,
78 Callback _pre_exec_cb, Callback _post_exec_cb)
79 : _pid(-1), _exit_status(242),
80 pre_exec_cb(_pre_exec_cb), post_exec_cb(_post_exec_cb)
82 int master_fd, slave_fd;
83 if (!open_pty(_master, master_fd, _slave, slave_fd)
84 || (_pid = ::fork()) < 0)
93 static const int std_fds[] = {
94 STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, -1
98 if (::
close(master_fd) < 0)
100 DPRINTF(
"close(master_fd) failed: %s\n",
strerror(errno));
105 DPRINTF(
"setsid() failed: %s\n",
strerror(errno));
108 ::ioctl(slave_fd, TIOCSCTTY, NULL);
111 for (std_fd = std_fds; *std_fd != -1; ++std_fd)
113 if (::dup2(slave_fd, *std_fd) < 0)
115 DPRINTF(
"dup2(slave_fd, %s) failed: %s\n", *std_fd,
120 if (slave_fd > STDERR_FILENO && ::
close(slave_fd) < 0)
122 DPRINTF(
"close(slave_fd) failed: %s\n",
strerror(errno));
126 for (std_fd = std_fds; *std_fd != -1; ++std_fd)
128 if (::fcntl(*std_fd, F_SETFL,
129 fcntl(*std_fd, F_GETFL) & (O_APPEND|O_ASYNC)))
131 DPRINTF(
"fcntl(%s, F_SETFL) failed: %s\n", *std_fd,
137 if (pre_exec_cb && !pre_exec_cb(*
this))
goto _error;
138 execvp(program, (
char *
const *)argv);
139 if (post_exec_cb) post_exec_cb(*
this);
147 if (::
close(slave_fd) < 0)
149 DPRINTF(
"close(slave_fd) failed: %s\n",
strerror(errno));
156 void WvPty::kill(
int signum)
159 ::kill(_pid, signum);
162 void WvPty::monitor_child(
bool wait)
167 if (::waitpid(_pid, &status, wait? 0: WNOHANG) == _pid)
170 _exit_status = status;
175 bool WvPty::child_exited()
177 monitor_child(
false);
181 bool WvPty::child_killed()
183 monitor_child(
false);
184 return _pid == -1 && WIFSIGNALED(_exit_status);
190 return WEXITSTATUS(_exit_status);
193 int WvPty::exit_status()
195 monitor_child(
false);
199 return WTERMSIG(_exit_status);
201 return WEXITSTATUS(_exit_status);