1 #include "ruby/config.h"
3 #include RUBY_EXTCONF_H
13 #ifdef HAVE_SYS_IOCTL_H
14 #include <sys/ioctl.h>
25 #if defined(HAVE_SYS_PARAM_H)
27 # include <sys/param.h>
29 #ifdef HAVE_SYS_WAIT_H
32 #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
42 #ifdef HAVE_SYS_STROPTS_H
43 #include <sys/stropts.h>
54 # define seteuid(e) setreuid(-1, (e))
56 # ifdef HAVE_SETRESUID
57 # define seteuid(e) setresuid(-1, (e), -1)
96 #define ERROR_EXIT(str) do { \
97 strlcpy(errbuf, (str), errbuf_len); \
112 if (setpgrp(0, getpid()) == -1)
118 if (
ioctl(i, TIOCNOTTY, (
char *)0))
129 #if defined(TIOCSCTTY)
131 (
void)
ioctl(slave, TIOCSCTTY, (
char *)0);
146 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
161 struct passwd *pwent;
167 const char *shellname;
173 pwent = getpwuid(
getuid());
174 if (pwent && pwent->pw_shell)
175 shellname = pwent->pw_shell;
177 shellname =
"/bin/sh";
188 getDevice(&master, &slave, SlaveName, 0);
217 return chmod(slavedevice, 0600);
225 #if defined(HAVE_POSIX_OPENPT)
227 int masterfd = -1, slavefd = -1;
229 struct sigaction dfl, old;
231 dfl.sa_handler = SIG_DFL;
233 sigemptyset(&dfl.sa_mask);
235 #if defined(__sun) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
239 if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1)
goto error;
240 if (sigaction(SIGCHLD, &dfl, &old) == -1)
goto error;
241 if (grantpt(masterfd) == -1)
goto grantpt_error;
245 int flags = O_RDWR|O_NOCTTY;
246 # if defined(O_CLOEXEC)
252 if ((masterfd = posix_openpt(flags)) == -1)
goto error;
255 if (sigaction(SIGCHLD, &dfl, &old) == -1)
goto error;
256 if (grantpt(masterfd) == -1)
goto grantpt_error;
258 if (sigaction(SIGCHLD, &old,
NULL) == -1)
goto error;
259 if (unlockpt(masterfd) == -1)
goto error;
260 if ((slavedevice = ptsname(masterfd)) ==
NULL)
goto error;
261 if (
no_mesg(slavedevice, nomesg) == -1)
goto error;
262 if ((slavefd =
rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1)
goto error;
265 #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
266 if (
ioctl(slavefd, I_PUSH,
"ptem") == -1)
goto error;
267 if (
ioctl(slavefd, I_PUSH,
"ldterm") == -1)
goto error;
268 if (
ioctl(slavefd, I_PUSH,
"ttcompat") == -1)
goto error;
273 strlcpy(SlaveName, slavedevice, DEVICELEN);
277 sigaction(SIGCHLD, &old,
NULL);
279 if (slavefd != -1) close(slavefd);
280 if (masterfd != -1) close(masterfd);
285 #elif defined HAVE_OPENPTY
290 if (openpty(master, slave, SlaveName,
291 (
struct termios *)0, (
struct winsize *)0) == -1) {
292 if (!fail)
return -1;
297 if (
no_mesg(SlaveName, nomesg) == -1) {
298 if (!fail)
return -1;
304 #elif defined HAVE__GETPTY
309 if (!(name = _getpty(master, O_RDWR, mode, 0))) {
310 if (!fail)
return -1;
318 strlcpy(SlaveName, name, DEVICELEN);
321 #elif defined(HAVE_PTSNAME)
323 int masterfd = -1, slavefd = -1;
327 extern char *ptsname(
int);
328 extern int unlockpt(
int);
329 extern int grantpt(
int);
333 if((masterfd = open(
"/dev/ptmx", O_RDWR, 0)) == -1)
goto error;
335 if(grantpt(masterfd) == -1)
goto error;
338 if((masterfd =
rb_cloexec_open(
"/dev/ptmx", O_RDWR, 0)) == -1)
goto error;
341 if(grantpt(masterfd) == -1)
goto error;
344 if(unlockpt(masterfd) == -1)
goto error;
345 if((slavedevice = ptsname(masterfd)) ==
NULL)
goto error;
346 if (
no_mesg(slavedevice, nomesg) == -1)
goto error;
347 if((slavefd =
rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1)
goto error;
349 #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
350 if(
ioctl(slavefd, I_PUSH,
"ptem") == -1)
goto error;
351 if(
ioctl(slavefd, I_PUSH,
"ldterm") == -1)
goto error;
352 ioctl(slavefd, I_PUSH,
"ttcompat");
356 strlcpy(SlaveName, slavedevice, DEVICELEN);
360 if (slavefd != -1) close(slavefd);
361 if (masterfd != -1) close(masterfd);
366 int masterfd = -1, slavefd = -1;
367 const char *
const *
p;
371 static const char MasterDevice[] =
"/dev/ptym/pty%s";
372 static const char SlaveDevice[] =
"/dev/pty/tty%s";
373 static const char *
const deviceNo[] = {
374 "p0",
"p1",
"p2",
"p3",
"p4",
"p5",
"p6",
"p7",
375 "p8",
"p9",
"pa",
"pb",
"pc",
"pd",
"pe",
"pf",
376 "q0",
"q1",
"q2",
"q3",
"q4",
"q5",
"q6",
"q7",
377 "q8",
"q9",
"qa",
"qb",
"qc",
"qd",
"qe",
"qf",
378 "r0",
"r1",
"r2",
"r3",
"r4",
"r5",
"r6",
"r7",
379 "r8",
"r9",
"ra",
"rb",
"rc",
"rd",
"re",
"rf",
380 "s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
381 "s8",
"s9",
"sa",
"sb",
"sc",
"sd",
"se",
"sf",
382 "t0",
"t1",
"t2",
"t3",
"t4",
"t5",
"t6",
"t7",
383 "t8",
"t9",
"ta",
"tb",
"tc",
"td",
"te",
"tf",
384 "u0",
"u1",
"u2",
"u3",
"u4",
"u5",
"u6",
"u7",
385 "u8",
"u9",
"ua",
"ub",
"uc",
"ud",
"ue",
"uf",
386 "v0",
"v1",
"v2",
"v3",
"v4",
"v5",
"v6",
"v7",
387 "v8",
"v9",
"va",
"vb",
"vc",
"vd",
"ve",
"vf",
388 "w0",
"w1",
"w2",
"w3",
"w4",
"w5",
"w6",
"w7",
389 "w8",
"w9",
"wa",
"wb",
"wc",
"wd",
"we",
"wf",
392 #elif defined(_IBMESA)
393 static const char MasterDevice[] =
"/dev/ptyp%s";
394 static const char SlaveDevice[] =
"/dev/ttyp%s";
395 static const char *
const deviceNo[] = {
396 "00",
"01",
"02",
"03",
"04",
"05",
"06",
"07",
"08",
"09",
"0a",
"0b",
"0c",
"0d",
"0e",
"0f",
397 "10",
"11",
"12",
"13",
"14",
"15",
"16",
"17",
"18",
"19",
"1a",
"1b",
"1c",
"1d",
"1e",
"1f",
398 "20",
"21",
"22",
"23",
"24",
"25",
"26",
"27",
"28",
"29",
"2a",
"2b",
"2c",
"2d",
"2e",
"2f",
399 "30",
"31",
"32",
"33",
"34",
"35",
"36",
"37",
"38",
"39",
"3a",
"3b",
"3c",
"3d",
"3e",
"3f",
400 "40",
"41",
"42",
"43",
"44",
"45",
"46",
"47",
"48",
"49",
"4a",
"4b",
"4c",
"4d",
"4e",
"4f",
401 "50",
"51",
"52",
"53",
"54",
"55",
"56",
"57",
"58",
"59",
"5a",
"5b",
"5c",
"5d",
"5e",
"5f",
402 "60",
"61",
"62",
"63",
"64",
"65",
"66",
"67",
"68",
"69",
"6a",
"6b",
"6c",
"6d",
"6e",
"6f",
403 "70",
"71",
"72",
"73",
"74",
"75",
"76",
"77",
"78",
"79",
"7a",
"7b",
"7c",
"7d",
"7e",
"7f",
404 "80",
"81",
"82",
"83",
"84",
"85",
"86",
"87",
"88",
"89",
"8a",
"8b",
"8c",
"8d",
"8e",
"8f",
405 "90",
"91",
"92",
"93",
"94",
"95",
"96",
"97",
"98",
"99",
"9a",
"9b",
"9c",
"9d",
"9e",
"9f",
406 "a0",
"a1",
"a2",
"a3",
"a4",
"a5",
"a6",
"a7",
"a8",
"a9",
"aa",
"ab",
"ac",
"ad",
"ae",
"af",
407 "b0",
"b1",
"b2",
"b3",
"b4",
"b5",
"b6",
"b7",
"b8",
"b9",
"ba",
"bb",
"bc",
"bd",
"be",
"bf",
408 "c0",
"c1",
"c2",
"c3",
"c4",
"c5",
"c6",
"c7",
"c8",
"c9",
"ca",
"cb",
"cc",
"cd",
"ce",
"cf",
409 "d0",
"d1",
"d2",
"d3",
"d4",
"d5",
"d6",
"d7",
"d8",
"d9",
"da",
"db",
"dc",
"dd",
"de",
"df",
410 "e0",
"e1",
"e2",
"e3",
"e4",
"e5",
"e6",
"e7",
"e8",
"e9",
"ea",
"eb",
"ec",
"ed",
"ee",
"ef",
411 "f0",
"f1",
"f2",
"f3",
"f4",
"f5",
"f6",
"f7",
"f8",
"f9",
"fa",
"fb",
"fc",
"fd",
"fe",
"ff",
415 static const char MasterDevice[] =
"/dev/pty%s";
416 static const char SlaveDevice[] =
"/dev/tty%s";
417 static const char *
const deviceNo[] = {
418 "p0",
"p1",
"p2",
"p3",
"p4",
"p5",
"p6",
"p7",
419 "p8",
"p9",
"pa",
"pb",
"pc",
"pd",
"pe",
"pf",
420 "q0",
"q1",
"q2",
"q3",
"q4",
"q5",
"q6",
"q7",
421 "q8",
"q9",
"qa",
"qb",
"qc",
"qd",
"qe",
"qf",
422 "r0",
"r1",
"r2",
"r3",
"r4",
"r5",
"r6",
"r7",
423 "r8",
"r9",
"ra",
"rb",
"rc",
"rd",
"re",
"rf",
424 "s0",
"s1",
"s2",
"s3",
"s4",
"s5",
"s6",
"s7",
425 "s8",
"s9",
"sa",
"sb",
"sc",
"sd",
"se",
"sf",
429 for (p = deviceNo; *p !=
NULL; p++) {
430 snprintf(MasterName,
sizeof MasterName, MasterDevice, *p);
434 snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
439 if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0)
goto error;
446 if (slavefd != -1) close(slavefd);
447 if (masterfd != -1) close(masterfd);
468 for (i = 0; i < 2; i++) {
511 int master_fd, slave_fd;
513 VALUE master_io, slave_file;
514 rb_io_t *master_fptr, *slave_fptr;
517 getDevice(&master_fd, &slave_fd, slavename, 1);
522 master_fptr->
fd = master_fd;
528 slave_fptr->
fd = slave_fd;
597 wfptr->pathv = rfptr->pathv;
619 #if defined(WIFSTOPPED)
620 #elif defined(IF_STOPPED)
621 #define WIFSTOPPED(status) IF_STOPPED(status)
623 ---->> Either IF_STOPPED or
WIFSTOPPED is needed <<----
628 else if (
kill(pid, 0) == 0) {
634 msg =
rb_sprintf(
"pty - %s: %ld", state, (
long)pid);
666 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_exc_new_str(VALUE etype, VALUE str)
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)
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
static VALUE pty_getpty(int argc, VALUE *argv, VALUE self)
sighandler_t signal(int signum, sighandler_t handler)
RUBY_EXTERN int dup2(int, int)
static void raise_from_check(rb_pid_t pid, int status)
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)
static VALUE VALUE master
void rb_execarg_fixup(VALUE execarg_obj)