1 #include "ruby/config.h"
3 #include RUBY_EXTCONF_H
13 #ifdef HAVE_SYS_IOCTL_H
14 #include <sys/ioctl.h>
25 #ifdef HAVE_SYS_WAIT_H
28 #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
38 #ifdef HAVE_SYS_STROPTS_H
39 #include <sys/stropts.h>
50 # define seteuid(e) setreuid(-1, (e))
52 # ifdef HAVE_SETRESUID
53 # define seteuid(e) setresuid(-1, (e), -1)
86 chfunc(
void *data,
char *errbuf,
size_t errbuf_len)
92 #define ERROR_EXIT(str) do { \
93 strlcpy(errbuf, (str), errbuf_len); \
108 if (setpgrp(0, getpid()) == -1)
114 if (
ioctl(i, TIOCNOTTY, (
char *)0))
125 #if defined(TIOCSCTTY)
127 (void)
ioctl(slave, TIOCSCTTY, (
char *)0);
142 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
157 struct passwd *pwent;
163 const char *shellname;
169 pwent = getpwuid(
getuid());
170 if (pwent && pwent->pw_shell)
171 shellname = pwent->pw_shell;
173 shellname =
"/bin/sh";
184 getDevice(&master, &slave, SlaveName, 0);
213 return chmod(slavedevice, 0600);
221 #if defined(HAVE_POSIX_OPENPT)
223 int masterfd = -1, slavefd = -1;
225 struct sigaction dfl, old;
227 dfl.sa_handler = SIG_DFL;
229 sigemptyset(&dfl.sa_mask);
231 #if defined(__sun) || defined(__FreeBSD__)
235 if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1)
goto error;
236 if (sigaction(SIGCHLD, &dfl, &old) == -1)
goto error;
237 if (grantpt(masterfd) == -1)
goto grantpt_error;
241 int flags = O_RDWR|O_NOCTTY;
242 # if defined(O_CLOEXEC)
248 if ((masterfd = posix_openpt(flags)) == -1)
goto error;
251 if (sigaction(SIGCHLD, &dfl, &old) == -1)
goto error;
252 if (grantpt(masterfd) == -1)
goto grantpt_error;
254 if (sigaction(SIGCHLD, &old,
NULL) == -1)
goto error;
255 if (unlockpt(masterfd) == -1)
goto error;
256 if ((slavedevice = ptsname(masterfd)) ==
NULL)
goto error;
257 if (
no_mesg(slavedevice, nomesg) == -1)
goto error;
258 if ((slavefd =
rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1)
goto error;
261 #if defined(I_PUSH) && !defined(__linux__)
262 if (
ioctl(slavefd, I_PUSH,
"ptem") == -1)
goto error;
263 if (
ioctl(slavefd, I_PUSH,
"ldterm") == -1)
goto error;
264 if (
ioctl(slavefd, I_PUSH,
"ttcompat") == -1)
goto error;
269 strlcpy(SlaveName, slavedevice, DEVICELEN);
273 sigaction(SIGCHLD, &old,
NULL);
275 if (slavefd != -1) close(slavefd);
276 if (masterfd != -1) close(masterfd);
281 #elif defined HAVE_OPENPTY
286 if (openpty(master, slave, SlaveName,
287 (
struct termios *)0, (
struct winsize *)0) == -1) {
288 if (!fail)
return -1;
293 if (
no_mesg(SlaveName, nomesg) == -1) {
294 if (!fail)
return -1;
300 #elif defined HAVE__GETPTY
303 mode_t mode = nomesg ? 0600 : 0622;
305 if (!(name = _getpty(master, O_RDWR, mode, 0))) {
306 if (!fail)
return -1;
314 strlcpy(SlaveName, name, DEVICELEN);
317 #elif defined(HAVE_PTSNAME)
319 int masterfd = -1, slavefd = -1;
323 extern char *ptsname(
int);
324 extern int unlockpt(
int);
325 extern int grantpt(
int);
329 if((masterfd = open(
"/dev/ptmx", O_RDWR, 0)) == -1)
goto error;
330 s =
signal(SIGCHLD, SIG_DFL);
331 if(grantpt(masterfd) == -1)
goto error;
334 if((masterfd =
rb_cloexec_open(
"/dev/ptmx", O_RDWR, 0)) == -1)
goto error;
336 s =
signal(SIGCHLD, SIG_DFL);
337 if(grantpt(masterfd) == -1)
goto error;
340 if(unlockpt(masterfd) == -1)
goto error;
341 if((slavedevice = ptsname(masterfd)) ==
NULL)
goto error;
342 if (
no_mesg(slavedevice, nomesg) == -1)
goto error;
343 if((slavefd =
rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1)
goto error;
345 #if defined(I_PUSH) && !defined(__linux__)
346 if(
ioctl(slavefd, I_PUSH,
"ptem") == -1)
goto error;
347 if(
ioctl(slavefd, I_PUSH,
"ldterm") == -1)
goto error;
348 ioctl(slavefd, I_PUSH,
"ttcompat");
352 strlcpy(SlaveName, slavedevice, DEVICELEN);
356 if (slavefd != -1) close(slavefd);
357 if (masterfd != -1) close(masterfd);
362 int masterfd = -1, slavefd = -1;
363 const char *
const *
p;
367 static const char MasterDevice[] =
"/dev/ptym/pty%s";
368 static const char SlaveDevice[] =
"/dev/pty/tty%s";
369 static const char *
const deviceNo[] = {
370 "p0",
"p1",
"p2",
"p3",
"p4",
"p5",
"p6",
"p7",
371 "p8",
"p9",
"pa",
"pb",
"pc",
"pd",
"pe",
"pf",
372 "q0",
"q1",
"q2",
"q3",
"q4",
"q5",
"q6",
"q7",
373 "q8",
"q9",
"qa",
"qb",
"qc",
"qd",
"qe",
"qf",
374 "r0",
"r1",
"r2",
"r3",
"r4",
"r5",
"r6",
"r7",
375 "r8",
"r9",
"ra",
"rb",
"rc",
"rd",
"re",
"rf",
376 "s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
377 "s8",
"s9",
"sa",
"sb",
"sc",
"sd",
"se",
"sf",
378 "t0",
"t1",
"t2",
"t3",
"t4",
"t5",
"t6",
"t7",
379 "t8",
"t9",
"ta",
"tb",
"tc",
"td",
"te",
"tf",
380 "u0",
"u1",
"u2",
"u3",
"u4",
"u5",
"u6",
"u7",
381 "u8",
"u9",
"ua",
"ub",
"uc",
"ud",
"ue",
"uf",
382 "v0",
"v1",
"v2",
"v3",
"v4",
"v5",
"v6",
"v7",
383 "v8",
"v9",
"va",
"vb",
"vc",
"vd",
"ve",
"vf",
384 "w0",
"w1",
"w2",
"w3",
"w4",
"w5",
"w6",
"w7",
385 "w8",
"w9",
"wa",
"wb",
"wc",
"wd",
"we",
"wf",
388 #elif defined(_IBMESA)
389 static const char MasterDevice[] =
"/dev/ptyp%s";
390 static const char SlaveDevice[] =
"/dev/ttyp%s";
391 static const char *
const deviceNo[] = {
392 "00",
"01",
"02",
"03",
"04",
"05",
"06",
"07",
"08",
"09",
"0a",
"0b",
"0c",
"0d",
"0e",
"0f",
393 "10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"1a",
"1b",
"1c",
"1d",
"1e",
"1f",
394 "20",
"21",
"22",
"23",
"24",
"25",
"26",
"27",
"28",
"29",
"2a",
"2b",
"2c",
"2d",
"2e",
"2f",
395 "30",
"31",
"32",
"33",
"34",
"35",
"36",
"37",
"38",
"39",
"3a",
"3b",
"3c",
"3d",
"3e",
"3f",
396 "40",
"41",
"42",
"43",
"44",
"45",
"46",
"47",
"48",
"49",
"4a",
"4b",
"4c",
"4d",
"4e",
"4f",
397 "50",
"51",
"52",
"53",
"54",
"55",
"56",
"57",
"58",
"59",
"5a",
"5b",
"5c",
"5d",
"5e",
"5f",
398 "60",
"61",
"62",
"63",
"64",
"65",
"66",
"67",
"68",
"69",
"6a",
"6b",
"6c",
"6d",
"6e",
"6f",
399 "70",
"71",
"72",
"73",
"74",
"75",
"76",
"77",
"78",
"79",
"7a",
"7b",
"7c",
"7d",
"7e",
"7f",
400 "80",
"81",
"82",
"83",
"84",
"85",
"86",
"87",
"88",
"89",
"8a",
"8b",
"8c",
"8d",
"8e",
"8f",
401 "90",
"91",
"92",
"93",
"94",
"95",
"96",
"97",
"98",
"99",
"9a",
"9b",
"9c",
"9d",
"9e",
"9f",
402 "a0",
"a1",
"a2",
"a3",
"a4",
"a5",
"a6",
"a7",
"a8",
"a9",
"aa",
"ab",
"ac",
"ad",
"ae",
"af",
403 "b0",
"b1",
"b2",
"b3",
"b4",
"b5",
"b6",
"b7",
"b8",
"b9",
"ba",
"bb",
"bc",
"bd",
"be",
"bf",
404 "c0",
"c1",
"c2",
"c3",
"c4",
"c5",
"c6",
"c7",
"c8",
"c9",
"ca",
"cb",
"cc",
"cd",
"ce",
"cf",
405 "d0",
"d1",
"d2",
"d3",
"d4",
"d5",
"d6",
"d7",
"d8",
"d9",
"da",
"db",
"dc",
"dd",
"de",
"df",
406 "e0",
"e1",
"e2",
"e3",
"e4",
"e5",
"e6",
"e7",
"e8",
"e9",
"ea",
"eb",
"ec",
"ed",
"ee",
"ef",
407 "f0",
"f1",
"f2",
"f3",
"f4",
"f5",
"f6",
"f7",
"f8",
"f9",
"fa",
"fb",
"fc",
"fd",
"fe",
"ff",
411 static const char MasterDevice[] =
"/dev/pty%s";
412 static const char SlaveDevice[] =
"/dev/tty%s";
413 static const char *
const deviceNo[] = {
414 "p0",
"p1",
"p2",
"p3",
"p4",
"p5",
"p6",
"p7",
415 "p8",
"p9",
"pa",
"pb",
"pc",
"pd",
"pe",
"pf",
416 "q0",
"q1",
"q2",
"q3",
"q4",
"q5",
"q6",
"q7",
417 "q8",
"q9",
"qa",
"qb",
"qc",
"qd",
"qe",
"qf",
418 "r0",
"r1",
"r2",
"r3",
"r4",
"r5",
"r6",
"r7",
419 "r8",
"r9",
"ra",
"rb",
"rc",
"rd",
"re",
"rf",
420 "s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
421 "s8",
"s9",
"sa",
"sb",
"sc",
"sd",
"se",
"sf",
425 for (p = deviceNo; *p !=
NULL; p++) {
426 snprintf(MasterName,
sizeof MasterName, MasterDevice, *p);
430 snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
435 if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0)
goto error;
442 if (slavefd != -1) close(slavefd);
443 if (masterfd != -1) close(masterfd);
464 for (i = 0; i < 2; i++) {
507 int master_fd, slave_fd;
509 VALUE master_io, slave_file;
510 rb_io_t *master_fptr, *slave_fptr;
513 getDevice(&master_fd, &slave_fd, slavename, 1);
518 master_fptr->
fd = master_fd;
524 slave_fptr->
fd = slave_fd;
593 wfptr->pathv = rfptr->pathv;
615 #if defined(WIFSTOPPED)
616 #elif defined(IF_STOPPED)
617 #define WIFSTOPPED(status) IF_STOPPED(status)
619 ---->> Either IF_STOPPED or
WIFSTOPPED is needed <<----
624 else if (
kill(pid, 0) == 0) {
630 snprintf(buf,
sizeof(buf),
"pty - %s: %ld", state, (
long)pid);
662 if (cpid == -1 || cpid == 0)
return Qnil;
VALUE rb_ary_entry(VALUE ary, long offset)
VALUE rb_detach_process(rb_pid_t pid)
void rb_update_max_fd(int fd)
#define WIFSTOPPED(status)
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
static VALUE pty_check(int argc, VALUE *argv, VALUE self)
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
static VALUE pty_close_pty(VALUE assoc)
int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen)
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
void rb_raise(VALUE exc, const char *fmt,...)
VALUE rb_ivar_get(VALUE, ID)
static int get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
static VALUE pty_open(VALUE klass)
static void establishShell(int argc, VALUE *argv, struct pty_info *info, char SlaveName[DEVICELEN])
static void getDevice(int *, int *, char[DEVICELEN], int)
struct rb_execarg * eargp
void rb_exc_raise(VALUE mesg)
#define RB_TYPE_P(obj, type)
static VALUE eChildExited
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
int rb_block_given_p(void)
int chown(const char *, int, int)
static int no_mesg(char *slavedevice, int nomesg)
rb_pid_t rb_fork_async_signal_safe(int *status, int(*chfunc)(void *, char *, size_t), void *charg, VALUE fds, char *errmsg, size_t errmsg_buflen)
void rb_ary_store(VALUE ary, long idx, VALUE val)
VALUE rb_obj_alloc(VALUE)
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
VALUE rb_sprintf(const char *format,...)
static int chfunc(void *data, char *errbuf, size_t errbuf_len)
void rb_execarg_fixup(VALUE execarg_obj)
VALUE rb_iv_set(VALUE, const char *, VALUE)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
unsigned char buf[MIME_BUF_SIZE]
VALUE rb_assoc_new(VALUE car, VALUE cdr)
VALUE rb_exc_new2(VALUE etype, const char *s)
static void raise_from_check(pid_t pid, int status)
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
VALUE rb_str_new_cstr(const char *)
#define rb_io_mode_flags(modestr)
void rb_sys_fail(const char *mesg)
void rb_jump_tag(int tag)
NORETURN(static void raise_from_check(pid_t pid, int status))
static VALUE pty_getpty(int argc, VALUE *argv, VALUE self)
sighandler_t signal(int signum, sighandler_t handler)
void rb_fd_fix_cloexec(int fd)
VALUE rb_ary_new2(long capa)
static VALUE echild_status(VALUE self)
#define MakeOpenFile(obj, fp)
RUBY_EXTERN int dup2(int, int)
static VALUE pty_detach_process(struct pty_info *info)
int rb_cloexec_dup(int oldfd)
VALUE rb_execarg_new(int argc, VALUE *argv, int accept_shell)
VALUE rb_obj_freeze(VALUE)
VALUE rb_define_module(const char *name)
VALUE rb_last_status_get(void)
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
VALUE rb_str_new2(const char *)