summaryrefslogtreecommitdiff
path: root/ext/pty/pty.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pty/pty.c')
-rw-r--r--ext/pty/pty.c171
1 files changed, 113 insertions, 58 deletions
diff --git a/ext/pty/pty.c b/ext/pty/pty.c
index 155d215942..5ca55e41d6 100644
--- a/ext/pty/pty.c
+++ b/ext/pty/pty.c
@@ -92,9 +92,13 @@ struct pty_info {
static void getDevice(int*, int*, char [DEVICELEN], int);
+static int start_new_session(char *errbuf, size_t errbuf_len);
+static int obtain_ctty(int master, int slave, const char *slavename, char *errbuf, size_t errbuf_len);
+static int drop_privilige(char *errbuf, size_t errbuf_len);
+
struct child_info {
int master, slave;
- char *slavename;
+ const char *slavename;
VALUE execarg_obj;
struct rb_execarg *eargp;
};
@@ -102,26 +106,42 @@ struct child_info {
static int
chfunc(void *data, char *errbuf, size_t errbuf_len)
{
- struct child_info *carg = data;
+ const struct child_info *carg = data;
int master = carg->master;
int slave = carg->slave;
+ const char *slavename = carg->slavename;
+
+ if (start_new_session(errbuf, errbuf_len))
+ return -1;
+
+ if (obtain_ctty(master, slave, slavename, errbuf, errbuf_len))
+ return -1;
+
+ if (drop_privilige(errbuf, errbuf_len))
+ return -1;
+
+ return rb_exec_async_signal_safe(carg->eargp, errbuf, errbuf_len);
+}
#define ERROR_EXIT(str) do { \
strlcpy(errbuf, (str), errbuf_len); \
return -1; \
} while (0)
- /*
- * Set free from process group and controlling terminal
- */
+/*
+ * Set free from process group and controlling terminal
+ */
+static int
+start_new_session(char *errbuf, size_t errbuf_len)
+{
#ifdef HAVE_SETSID
(void) setsid();
#else /* HAS_SETSID */
# ifdef HAVE_SETPGRP
-# ifdef SETGRP_VOID
+# ifdef SETPGRP_VOID
if (setpgrp() == -1)
ERROR_EXIT("setpgrp()");
-# else /* SETGRP_VOID */
+# else /* SETPGRP_VOID */
if (setpgrp(0, getpid()) == -1)
ERROR_EXIT("setpgrp()");
{
@@ -132,20 +152,25 @@ chfunc(void *data, char *errbuf, size_t errbuf_len)
ERROR_EXIT("ioctl(TIOCNOTTY)");
close(i);
}
-# endif /* SETGRP_VOID */
+# endif /* SETPGRP_VOID */
# endif /* HAVE_SETPGRP */
#endif /* HAS_SETSID */
+ return 0;
+}
- /*
- * obtain new controlling terminal
- */
+/*
+ * obtain new controlling terminal
+ */
+static int
+obtain_ctty(int master, int slave, const char *slavename, char *errbuf, size_t errbuf_len)
+{
#if defined(TIOCSCTTY)
close(master);
(void) ioctl(slave, TIOCSCTTY, (char *)0);
/* errors ignored for sun */
#else
close(slave);
- slave = rb_cloexec_open(carg->slavename, O_RDWR, 0);
+ slave = rb_cloexec_open(slavename, O_RDWR, 0);
if (slave < 0) {
ERROR_EXIT("open: pty slave");
}
@@ -156,13 +181,19 @@ chfunc(void *data, char *errbuf, size_t errbuf_len)
dup2(slave,1);
dup2(slave,2);
if (slave < 0 || slave > 2) (void)!close(slave);
+ return 0;
+}
+
+static int
+drop_privilige(char *errbuf, size_t errbuf_len)
+{
#if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
if (seteuid(getuid())) ERROR_EXIT("seteuid()");
#endif
+ return 0;
+}
- return rb_exec_async_signal_safe(carg->eargp, errbuf, sizeof(errbuf_len));
#undef ERROR_EXIT
-}
static void
establishShell(int argc, VALUE *argv, struct pty_info *info,
@@ -170,7 +201,7 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
{
int master, slave, status = 0;
rb_pid_t pid;
- char *p, *getenv();
+ char *p;
VALUE v;
struct child_info carg;
char errbuf[32];
@@ -225,7 +256,21 @@ establishShell(int argc, VALUE *argv, struct pty_info *info,
RB_GC_GUARD(carg.execarg_obj);
}
-#if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME)
+#if (defined(HAVE_POSIX_OPENPT) || defined(HAVE_PTSNAME)) && !defined(HAVE_PTSNAME_R)
+/* glibc only, not obsolete interface on Tru64 or HP-UX */
+static int
+ptsname_r(int fd, char *buf, size_t buflen)
+{
+ extern char *ptsname(int);
+ char *name = ptsname(fd);
+ if (!name) return -1;
+ strlcpy(buf, name, buflen);
+ return 0;
+}
+# define HAVE_PTSNAME_R 1
+#endif
+
+#if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME_R)
static int
no_mesg(char *slavedevice, int nomesg)
{
@@ -258,13 +303,19 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
/* Unix98 PTY */
int masterfd = -1, slavefd = -1;
char *slavedevice;
+ struct sigaction dfl, old;
+
+ dfl.sa_handler = SIG_DFL;
+ dfl.sa_flags = 0;
+ sigemptyset(&dfl.sa_mask);
#if defined(__sun) || defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
/* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
/* FreeBSD 9.2 or later supports O_CLOEXEC
* http://www.freebsd.org/cgi/query-pr.cgi?pr=162374 */
if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
- if (rb_grantpt(masterfd) == -1) goto error;
+ if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
+ if (grantpt(masterfd) == -1) goto grantpt_error;
rb_fd_fix_cloexec(masterfd);
#else
{
@@ -278,10 +329,13 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
if ((masterfd = posix_openpt(flags)) == -1) goto error;
}
rb_fd_fix_cloexec(masterfd);
- if (rb_grantpt(masterfd) == -1) goto error;
+ if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
+ if (grantpt(masterfd) == -1) goto grantpt_error;
#endif
+ if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
if (unlockpt(masterfd) == -1) goto error;
- if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
+ if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
+ slavedevice = SlaveName;
if (no_mesg(slavedevice, nomesg) == -1) goto error;
if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
rb_update_max_fd(slavefd);
@@ -294,9 +348,10 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
*master = masterfd;
*slave = slavefd;
- strlcpy(SlaveName, slavedevice, DEVICELEN);
return 0;
+ grantpt_error:
+ sigaction(SIGCHLD, &old, NULL);
error:
if (slavefd != -1) close(slavefd);
if (masterfd != -1) close(masterfd);
@@ -346,21 +401,25 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
char *slavedevice;
void (*s)();
- extern char *ptsname(int);
extern int unlockpt(int);
+ extern int grantpt(int);
#if defined(__sun)
/* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
- if(rb_grantpt(masterfd) == -1) goto error;
+ s = signal(SIGCHLD, SIG_DFL);
+ if(grantpt(masterfd) == -1) goto error;
rb_fd_fix_cloexec(masterfd);
#else
if((masterfd = rb_cloexec_open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
rb_update_max_fd(masterfd);
- if(rb_grantpt(masterfd) == -1) goto error;
+ s = signal(SIGCHLD, SIG_DFL);
+ if(grantpt(masterfd) == -1) goto error;
#endif
+ signal(SIGCHLD, s);
if(unlockpt(masterfd) == -1) goto error;
- if((slavedevice = ptsname(masterfd)) == NULL) goto error;
+ if (ptsname_r(masterfd, SlaveName, DEVICELEN) != 0) goto error;
+ slavedevice = SlaveName;
if (no_mesg(slavedevice, nomesg) == -1) goto error;
if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error;
rb_update_max_fd(slavefd);
@@ -371,7 +430,6 @@ get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg,
#endif
*master = masterfd;
*slave = slavefd;
- strlcpy(SlaveName, slavedevice, DEVICELEN);
return 0;
error:
@@ -448,8 +506,10 @@ pty_close_pty(VALUE assoc)
for (i = 0; i < 2; i++) {
io = rb_ary_entry(assoc, i);
- if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
+ if (RB_TYPE_P(io, T_FILE)) {
+ /* it's OK to call rb_io_close again even if it's already closed */
rb_io_close(io);
+ }
}
return Qnil;
}
@@ -499,28 +559,21 @@ pty_open(VALUE klass)
{
int master_fd, slave_fd;
char slavename[DEVICELEN];
- VALUE master_io, slave_file;
- rb_io_t *master_fptr, *slave_fptr;
- VALUE assoc;
getDevice(&master_fd, &slave_fd, slavename, 1);
- master_io = rb_obj_alloc(rb_cIO);
- MakeOpenFile(master_io, master_fptr);
- master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
- master_fptr->fd = master_fd;
- master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
+ VALUE master_path = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
+ VALUE master_io = rb_io_open_descriptor(rb_cIO, master_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX, master_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
+
+ VALUE slave_path = rb_obj_freeze(rb_str_new_cstr(slavename));
+ VALUE slave_file = rb_io_open_descriptor(rb_cFile, slave_fd, FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY, slave_path, RUBY_IO_TIMEOUT_DEFAULT, NULL);
- slave_file = rb_obj_alloc(rb_cFile);
- MakeOpenFile(slave_file, slave_fptr);
- slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
- slave_fptr->fd = slave_fd;
- slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
+ VALUE assoc = rb_assoc_new(master_io, slave_file);
- assoc = rb_assoc_new(master_io, slave_file);
if (rb_block_given_p()) {
return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
}
+
return assoc;
}
@@ -577,30 +630,27 @@ pty_getpty(int argc, VALUE *argv, VALUE self)
{
VALUE res;
struct pty_info info;
- rb_io_t *wfptr,*rfptr;
- VALUE rport = rb_obj_alloc(rb_cFile);
- VALUE wport = rb_obj_alloc(rb_cFile);
char SlaveName[DEVICELEN];
- MakeOpenFile(rport, rfptr);
- MakeOpenFile(wport, wfptr);
-
establishShell(argc, argv, &info, SlaveName);
- rfptr->mode = rb_io_modestr_fmode("r");
- rfptr->fd = info.fd;
- rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
+ VALUE pty_path = rb_obj_freeze(rb_str_new_cstr(SlaveName));
+ VALUE rport = rb_io_open_descriptor(
+ rb_cFile, info.fd, FMODE_READABLE, pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
+ );
- wfptr->mode = rb_io_modestr_fmode("w") | FMODE_SYNC;
- wfptr->fd = rb_cloexec_dup(info.fd);
- if (wfptr->fd == -1)
+ int wpty_fd = rb_cloexec_dup(info.fd);
+ if (wpty_fd == -1) {
rb_sys_fail("dup()");
- rb_update_max_fd(wfptr->fd);
- wfptr->pathv = rfptr->pathv;
+ }
+ VALUE wport = rb_io_open_descriptor(
+ rb_cFile, wpty_fd, FMODE_WRITABLE | FMODE_TRUNC | FMODE_CREATE | FMODE_SYNC,
+ pty_path, RUBY_IO_TIMEOUT_DEFAULT, NULL
+ );
res = rb_ary_new2(3);
- rb_ary_store(res,0,(VALUE)rport);
- rb_ary_store(res,1,(VALUE)wport);
+ rb_ary_store(res, 0, rport);
+ rb_ary_store(res, 1, wport);
rb_ary_store(res,2,PIDT2NUM(info.child_pid));
if (rb_block_given_p()) {
@@ -753,8 +803,13 @@ void
Init_pty(void)
{
cPTY = rb_define_module("PTY");
- /* :nodoc: */
- rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
+#if 1
+ rb_define_module_function(cPTY,"get""pty",pty_getpty,-1);
+#else /* for RDoc */
+ /* show getpty as an alias of spawn */
+ VALUE sPTY = rb_singleton_class(cPTY);
+ rb_define_alias(sPTY, "getpty", "spawn");
+#endif
rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
rb_define_singleton_method(cPTY,"check",pty_check,-1);
rb_define_singleton_method(cPTY,"open",pty_open,0);