1#include "ruby/config.h"
4# include RUBY_EXTCONF_H
22#ifdef HAVE_SYS_IOCTL_H
23# include <sys/ioctl.h>
38#if defined(HAVE_SYS_PARAM_H)
40# include <sys/param.h>
46# define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
49#ifdef HAVE_SYS_STROPTS_H
50#include <sys/stropts.h>
67# define seteuid(e) setreuid(-1, (e))
70# define seteuid(e) setresuid(-1, (e), -1)
77static VALUE eChildExited;
83echild_status(
VALUE self)
93static void getDevice(
int*,
int*,
char [
DEVICELEN],
int);
103chfunc(
void *data,
char *errbuf,
size_t errbuf_len)
109#define ERROR_EXIT(str) do { \
110 strlcpy(errbuf, (str), errbuf_len); \
125 if (setpgrp(0, getpid()) == -1)
131 if (
ioctl(i, TIOCNOTTY, (
char *)0))
142#if defined(TIOCSCTTY)
158 if (slave < 0 || slave > 2) (void)!close(
slave);
159#if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
179 const char *shellname =
"/bin/sh";
185#if defined HAVE_PWD_H
186 const char *username =
getenv(
"USER");
187 struct passwd *pwent = getpwnam(username ? username :
getlogin());
188 if (pwent && pwent->pw_shell)
189 shellname = pwent->pw_shell;
201 getDevice(&master, &slave, SlaveName, 0);
228#if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME)
230no_mesg(
char *slavedevice,
int nomesg)
233 return chmod(slavedevice, 0600);
239#if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
241ioctl_I_PUSH(
int fd,
const char *
const name)
255get_device_once(
int *master,
int *slave,
char SlaveName[
DEVICELEN],
int nomesg,
int fail)
257#if defined(HAVE_POSIX_OPENPT)
259 int masterfd = -1, slavefd = -1;
262#if defined(__sun) || defined(__OpenBSD__) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
266 if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1)
goto error;
271 int flags = O_RDWR|O_NOCTTY;
272# if defined(O_CLOEXEC)
278 if ((masterfd = posix_openpt(flags)) == -1)
goto error;
283 if (unlockpt(masterfd) == -1)
goto error;
284 if ((slavedevice = ptsname(masterfd)) ==
NULL)
goto error;
285 if (no_mesg(slavedevice, nomesg) == -1)
goto error;
289#if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
290 if (ioctl_I_PUSH(slavefd,
"ptem") == -1)
goto error;
291 if (ioctl_I_PUSH(slavefd,
"ldterm") == -1)
goto error;
292 if (ioctl_I_PUSH(slavefd,
"ttcompat") == -1)
goto error;
301 if (slavefd != -1) close(slavefd);
302 if (masterfd != -1) close(masterfd);
307#elif defined HAVE_OPENPTY
312 if (openpty(master, slave, SlaveName,
313 (
struct termios *)0, (
struct winsize *)0) == -1) {
314 if (!
fail)
return -1;
319 if (no_mesg(SlaveName, nomesg) == -1) {
320 if (!
fail)
return -1;
326#elif defined HAVE__GETPTY
331 if (!(
name = _getpty(master, O_RDWR,
mode, 0))) {
332 if (!
fail)
return -1;
343#elif defined(HAVE_PTSNAME)
345 int masterfd = -1, slavefd = -1;
349 extern char *ptsname(
int);
350 extern int unlockpt(
int);
354 if((masterfd = open(
"/dev/ptmx", O_RDWR, 0)) == -1)
goto error;
362 if(unlockpt(masterfd) == -1)
goto error;
363 if((slavedevice = ptsname(masterfd)) ==
NULL)
goto error;
364 if (no_mesg(slavedevice, nomesg) == -1)
goto error;
367#if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
368 if(ioctl_I_PUSH(slavefd,
"ptem") == -1)
goto error;
369 if(ioctl_I_PUSH(slavefd,
"ldterm") == -1)
goto error;
370 ioctl_I_PUSH(slavefd,
"ttcompat");
378 if (slavefd != -1) close(slavefd);
379 if (masterfd != -1) close(masterfd);
384 int masterfd = -1, slavefd = -1;
389 c"0",c"1",c"2",c"3",c"4",c"5",c"6",c"7", \
390 c"8",c"9",c"a",c"b",c"c",c"d",c"e",c"f"
393 static const char MasterDevice[] =
"/dev/ptym/pty%s";
394 static const char SlaveDevice[] =
"/dev/pty/tty%s";
395 static const char deviceNo[][3] = {
399#elif defined(_IBMESA)
400 static const char MasterDevice[] =
"/dev/ptyp%s";
401 static const char SlaveDevice[] =
"/dev/ttyp%s";
402 static const char deviceNo[][3] = {
409 static const char MasterDevice[] =
"/dev/pty%s";
410 static const char SlaveDevice[] =
"/dev/tty%s";
411 static const char deviceNo[][3] = {
416 for (i = 0; i <
numberof(deviceNo); i++) {
417 const char *
const devno = deviceNo[i];
418 snprintf(MasterName,
sizeof MasterName, MasterDevice, devno);
427 if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0)
goto error;
434 if (slavefd != -1) close(slavefd);
435 if (masterfd != -1) close(masterfd);
442getDevice(
int *master,
int *slave,
char SlaveName[
DEVICELEN],
int nomesg)
444 if (get_device_once(master, slave, SlaveName, nomesg, 0)) {
446 get_device_once(master, slave, SlaveName, nomesg, 1);
451pty_close_pty(
VALUE assoc)
456 for (i = 0; i < 2; i++) {
458 if (RB_TYPE_P(io,
T_FILE) && 0 <=
RFILE(io)->fptr->fd)
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;
535pty_detach_process(
VALUE v)
588 establishShell(
argc,
argv, &info, SlaveName);
599 wfptr->pathv = rfptr->pathv;
613NORETURN(
static void raise_from_check(rb_pid_t pid,
int status));
615raise_from_check(rb_pid_t pid,
int status)
621#if defined(WIFSTOPPED)
622#elif defined(IF_STOPPED)
623#define WIFSTOPPED(status) IF_STOPPED(status)
625---->> Either IF_STOPPED or
WIFSTOPPED is needed <<----
630 else if (
kill(pid, 0) == 0) {
676 if (cpid == -1 || cpid == 0)
return Qnil;
679 raise_from_check(cpid, status);
void rb_ary_store(VALUE ary, long idx, VALUE val)
VALUE rb_ary_entry(VALUE ary, long offset)
VALUE rb_assoc_new(VALUE car, VALUE cdr)
#define UNREACHABLE_RETURN
Our own, locale independent, character handling routines.
#define rb_define_method(klass, mid, func, arity)
Defines klass#mid.
#define rb_define_singleton_method(klass, mid, func, arity)
Defines klass.mid.
#define rb_define_module_function(klass, mid, func, arity)
Defines klass#mid and makes it a module function.
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
VALUE rb_define_module(const char *name)
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
int rb_block_given_p(void)
Determines if the current method is given a block.
void rb_raise(VALUE exc, const char *fmt,...)
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
VALUE rb_exc_new_str(VALUE etype, VALUE str)
VALUE rb_ensure(VALUE(*b_proc)(VALUE), VALUE data1, VALUE(*e_proc)(VALUE), VALUE data2)
An equivalent to ensure clause.
void rb_jump_tag(int tag)
Continues the exception caught by rb_protect() and rb_eval_string_protect().
void rb_sys_fail(const char *mesg)
VALUE rb_obj_alloc(VALUE)
Allocates an instance of klass.
VALUE rb_obj_freeze(VALUE)
Make the object unmodifiable.
void rb_update_max_fd(int fd)
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
void rb_fd_fix_cloexec(int fd)
int rb_cloexec_dup(int oldfd)
VALUE rb_last_status_get(void)
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
VALUE rb_detach_process(rb_pid_t pid)
#define rb_str_new_cstr(str)
VALUE rb_ivar_get(VALUE, ID)
ID rb_intern(const char *)
VALUE rb_iv_set(VALUE, const char *, VALUE)
int rb_io_modestr_fmode(const char *modestr)
size_t strlcpy(char *, const char *, size_t)
Internal header for Process.
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
void rb_execarg_parent_end(VALUE execarg_obj)
int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen)
VALUE rb_execarg_new(int argc, const VALUE *argv, int accept_shell, int allow_exc_opt)
void rb_execarg_parent_start(VALUE execarg_obj)
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)
Internal header for SignalException.
Internal header corresponding util.c.
#define WIFSTOPPED(status)
VALUE rb_sprintf(const char *,...)
struct rb_execarg * eargp
void error(const char *msg)
int chown(const char *, int, int)