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 msg =
rb_sprintf(
"pty - %s: %ld", state, (
long)pid);
662 if (cpid == -1 || cpid == 0)
return Qnil;
#define RB_TYPE_P(obj, type)
VALUE rb_ary_entry(VALUE ary, long offset)
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)
VALUE rb_iv_set(VALUE, const char *, VALUE)
VALUE rb_last_status_get(void)
#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)
static VALUE pty_close_pty(VALUE assoc)
VALUE rb_str_new_cstr(const char *)
VALUE rb_obj_freeze(VALUE)
void rb_update_max_fd(int fd)
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_execarg_new(int argc, VALUE *argv, int accept_shell)
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])
int rb_cloexec_dup(int oldfd)
VALUE rb_ivar_get(VALUE, ID)
static void getDevice(int *, int *, char[DEVICELEN], int)
void rb_fd_fix_cloexec(int fd)
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
struct rb_execarg * eargp
void rb_exc_raise(VALUE mesg)
static VALUE eChildExited
int rb_block_given_p(void)
VALUE rb_detach_process(rb_pid_t pid)
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
int chown(const char *, int, int)
static int no_mesg(char *slavedevice, int nomesg)
void rb_ary_store(VALUE ary, long idx, VALUE val)
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
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)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
VALUE rb_assoc_new(VALUE car, VALUE cdr)
static void raise_from_check(pid_t pid, int status)
int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen)
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
#define rb_io_mode_flags(modestr)
void rb_sys_fail(const char *mesg)
void rb_jump_tag(int tag)
RUBY_EXTERN VALUE rb_cFile
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)
VALUE rb_exc_new3(VALUE etype, VALUE str)
RUBY_EXTERN int dup2(int, int)
VALUE rb_ary_new2(long capa)
static VALUE echild_status(VALUE self)
VALUE rb_obj_alloc(VALUE)
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
#define MakeOpenFile(obj, fp)
static VALUE pty_detach_process(struct pty_info *info)
VALUE rb_define_module(const char *name)
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
void rb_execarg_fixup(VALUE execarg_obj)