Ruby  2.5.0dev(2017-10-22revision60238)
pty.c
Go to the documentation of this file.
1 #include "ruby/config.h"
2 #ifdef RUBY_EXTCONF_H
3 #include RUBY_EXTCONF_H
4 #endif
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <sys/file.h>
10 #include <fcntl.h>
11 #include <errno.h>
12 #ifdef HAVE_PWD_H
13 #include <pwd.h>
14 #endif
15 #ifdef HAVE_SYS_IOCTL_H
16 #include <sys/ioctl.h>
17 #endif
18 #ifdef HAVE_LIBUTIL_H
19 #include <libutil.h>
20 #endif
21 #ifdef HAVE_UTIL_H
22 #include <util.h>
23 #endif
24 #ifdef HAVE_PTY_H
25 #include <pty.h>
26 #endif
27 #if defined(HAVE_SYS_PARAM_H)
28  /* for __FreeBSD_version */
29 # include <sys/param.h>
30 #endif
31 #ifdef HAVE_SYS_WAIT_H
32 #include <sys/wait.h>
33 #else
34 #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
35 #endif
36 #include <ctype.h>
37 
38 #include "internal.h"
39 #include "ruby/io.h"
40 #include "ruby/util.h"
41 
42 #include <signal.h>
43 #ifdef HAVE_SYS_STROPTS_H
44 #include <sys/stropts.h>
45 #endif
46 
47 #ifdef HAVE_UNISTD_H
48 #include <unistd.h>
49 #endif
50 
51 #define DEVICELEN 16
52 
53 #ifndef HAVE_SETEUID
54 # ifdef HAVE_SETREUID
55 # define seteuid(e) setreuid(-1, (e))
56 # else /* NOT HAVE_SETREUID */
57 # ifdef HAVE_SETRESUID
58 # define seteuid(e) setresuid(-1, (e), -1)
59 # else /* NOT HAVE_SETRESUID */
60  /* I can't set euid. (;_;) */
61 # endif /* HAVE_SETRESUID */
62 # endif /* HAVE_SETREUID */
63 #endif /* NO_SETEUID */
64 
65 static VALUE eChildExited;
66 
67 /* Returns the exit status of the child for which PTY#check
68  * raised this exception
69  */
70 static VALUE
71 echild_status(VALUE self)
72 {
73  return rb_ivar_get(self, rb_intern("status"));
74 }
75 
76 struct pty_info {
77  int fd;
78  rb_pid_t child_pid;
79 };
80 
81 static void getDevice(int*, int*, char [DEVICELEN], int);
82 
83 struct child_info {
84  int master, slave;
85  char *slavename;
87  struct rb_execarg *eargp;
88 };
89 
90 static int
91 chfunc(void *data, char *errbuf, size_t errbuf_len)
92 {
93  struct child_info *carg = data;
94  int master = carg->master;
95  int slave = carg->slave;
96 
97 #define ERROR_EXIT(str) do { \
98  strlcpy(errbuf, (str), errbuf_len); \
99  return -1; \
100  } while (0)
101 
102  /*
103  * Set free from process group and controlling terminal
104  */
105 #ifdef HAVE_SETSID
106  (void) setsid();
107 #else /* HAS_SETSID */
108 # ifdef HAVE_SETPGRP
109 # ifdef SETGRP_VOID
110  if (setpgrp() == -1)
111  ERROR_EXIT("setpgrp()");
112 # else /* SETGRP_VOID */
113  if (setpgrp(0, getpid()) == -1)
114  ERROR_EXIT("setpgrp()");
115  {
116  int i = rb_cloexec_open("/dev/tty", O_RDONLY, 0);
117  if (i < 0) ERROR_EXIT("/dev/tty");
118  rb_update_max_fd(i);
119  if (ioctl(i, TIOCNOTTY, (char *)0))
120  ERROR_EXIT("ioctl(TIOCNOTTY)");
121  close(i);
122  }
123 # endif /* SETGRP_VOID */
124 # endif /* HAVE_SETPGRP */
125 #endif /* HAS_SETSID */
126 
127  /*
128  * obtain new controlling terminal
129  */
130 #if defined(TIOCSCTTY)
131  close(master);
132  (void) ioctl(slave, TIOCSCTTY, (char *)0);
133  /* errors ignored for sun */
134 #else
135  close(slave);
136  slave = rb_cloexec_open(carg->slavename, O_RDWR, 0);
137  if (slave < 0) {
138  ERROR_EXIT("open: pty slave");
139  }
140  rb_update_max_fd(slave);
141  close(master);
142 #endif
143  dup2(slave,0);
144  dup2(slave,1);
145  dup2(slave,2);
146  close(slave);
147 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
148  if (seteuid(getuid())) ERROR_EXIT("seteuid()");
149 #endif
150 
151  return rb_exec_async_signal_safe(carg->eargp, errbuf, sizeof(errbuf_len));
152 #undef ERROR_EXIT
153 }
154 
155 static void
156 establishShell(int argc, VALUE *argv, struct pty_info *info,
157  char SlaveName[DEVICELEN])
158 {
159  int master, slave, status = 0;
160  rb_pid_t pid;
161  char *p, *getenv();
162  VALUE v;
163  struct child_info carg;
164  char errbuf[32];
165 
166  if (argc == 0) {
167  const char *shellname = "/bin/sh";
168 
169  if ((p = getenv("SHELL")) != NULL) {
170  shellname = p;
171  }
172  else {
173 #if defined HAVE_PWD_H
174  const char *username = getenv("USER");
175  struct passwd *pwent = getpwnam(username ? username : getlogin());
176  if (pwent && pwent->pw_shell)
177  shellname = pwent->pw_shell;
178 #endif
179  }
180  v = rb_str_new2(shellname);
181  argc = 1;
182  argv = &v;
183  }
184 
185  carg.execarg_obj = rb_execarg_new(argc, argv, 1);
186  carg.eargp = rb_execarg_get(carg.execarg_obj);
188 
189  getDevice(&master, &slave, SlaveName, 0);
190 
191  carg.master = master;
192  carg.slave = slave;
193  carg.slavename = SlaveName;
194  errbuf[0] = '\0';
195  pid = rb_fork_async_signal_safe(&status, chfunc, &carg, Qnil, errbuf, sizeof(errbuf));
196 
197  if (pid < 0) {
198  int e = errno;
199  close(master);
200  close(slave);
202  errno = e;
203  if (status) rb_jump_tag(status);
204  rb_sys_fail(errbuf[0] ? errbuf : "fork failed");
205  }
206 
207  close(slave);
209 
210  info->child_pid = pid;
211  info->fd = master;
212 
213  RB_GC_GUARD(carg.execarg_obj);
214 }
215 
216 #if defined(HAVE_POSIX_OPENPT) || defined(HAVE_OPENPTY) || defined(HAVE_PTSNAME)
217 static int
218 no_mesg(char *slavedevice, int nomesg)
219 {
220  if (nomesg)
221  return chmod(slavedevice, 0600);
222  else
223  return 0;
224 }
225 #endif
226 
227 static int
228 get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
229 {
230 #if defined(HAVE_POSIX_OPENPT)
231  /* Unix98 PTY */
232  int masterfd = -1, slavefd = -1;
233  char *slavedevice;
234  struct sigaction dfl, old;
235 
236  dfl.sa_handler = SIG_DFL;
237  dfl.sa_flags = 0;
238  sigemptyset(&dfl.sa_mask);
239 
240 #if defined(__sun) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
241  /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
242  /* FreeBSD 9.2 or later supports O_CLOEXEC
243  * http://www.freebsd.org/cgi/query-pr.cgi?pr=162374 */
244  if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
245  if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
246  if (grantpt(masterfd) == -1) goto grantpt_error;
247  rb_fd_fix_cloexec(masterfd);
248 #else
249  {
250  int flags = O_RDWR|O_NOCTTY;
251 # if defined(O_CLOEXEC)
252  /* glibc posix_openpt() in GNU/Linux calls open("/dev/ptmx", flags) internally.
253  * So version dependency on GNU/Linux is same as O_CLOEXEC with open().
254  * O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
255  flags |= O_CLOEXEC;
256 # endif
257  if ((masterfd = posix_openpt(flags)) == -1) goto error;
258  }
259  rb_fd_fix_cloexec(masterfd);
260  if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
261  if (grantpt(masterfd) == -1) goto grantpt_error;
262 #endif
263  if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
264  if (unlockpt(masterfd) == -1) goto error;
265  if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
266  if (no_mesg(slavedevice, nomesg) == -1) goto error;
267  if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
268  rb_update_max_fd(slavefd);
269 
270 #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
271  if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
272  if (ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
273  if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) goto error;
274 #endif
275 
276  *master = masterfd;
277  *slave = slavefd;
278  strlcpy(SlaveName, slavedevice, DEVICELEN);
279  return 0;
280 
281  grantpt_error:
282  sigaction(SIGCHLD, &old, NULL);
283  error:
284  if (slavefd != -1) close(slavefd);
285  if (masterfd != -1) close(masterfd);
286  if (fail) {
287  rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
288  }
289  return -1;
290 #elif defined HAVE_OPENPTY
291 /*
292  * Use openpty(3) of 4.3BSD Reno and later,
293  * or the same interface function.
294  */
295  if (openpty(master, slave, SlaveName,
296  (struct termios *)0, (struct winsize *)0) == -1) {
297  if (!fail) return -1;
298  rb_raise(rb_eRuntimeError, "openpty() failed");
299  }
300  rb_fd_fix_cloexec(*master);
301  rb_fd_fix_cloexec(*slave);
302  if (no_mesg(SlaveName, nomesg) == -1) {
303  if (!fail) return -1;
304  rb_raise(rb_eRuntimeError, "can't chmod slave pty");
305  }
306 
307  return 0;
308 
309 #elif defined HAVE__GETPTY
310  /* SGI IRIX */
311  char *name;
312  mode_t mode = nomesg ? 0600 : 0622;
313 
314  if (!(name = _getpty(master, O_RDWR, mode, 0))) {
315  if (!fail) return -1;
316  rb_raise(rb_eRuntimeError, "_getpty() failed");
317  }
318  rb_fd_fix_cloexec(*master);
319 
320  *slave = rb_cloexec_open(name, O_RDWR, 0);
321  /* error check? */
322  rb_update_max_fd(*slave);
323  strlcpy(SlaveName, name, DEVICELEN);
324 
325  return 0;
326 #elif defined(HAVE_PTSNAME)
327  /* System V */
328  int masterfd = -1, slavefd = -1;
329  char *slavedevice;
330  void (*s)();
331 
332  extern char *ptsname(int);
333  extern int unlockpt(int);
334  extern int grantpt(int);
335 
336 #if defined(__sun)
337  /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
338  if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
339  s = signal(SIGCHLD, SIG_DFL);
340  if(grantpt(masterfd) == -1) goto error;
341  rb_fd_fix_cloexec(masterfd);
342 #else
343  if((masterfd = rb_cloexec_open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
344  rb_update_max_fd(masterfd);
345  s = signal(SIGCHLD, SIG_DFL);
346  if(grantpt(masterfd) == -1) goto error;
347 #endif
348  signal(SIGCHLD, s);
349  if(unlockpt(masterfd) == -1) goto error;
350  if((slavedevice = ptsname(masterfd)) == NULL) goto error;
351  if (no_mesg(slavedevice, nomesg) == -1) goto error;
352  if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error;
353  rb_update_max_fd(slavefd);
354 #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
355  if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
356  if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
357  ioctl(slavefd, I_PUSH, "ttcompat");
358 #endif
359  *master = masterfd;
360  *slave = slavefd;
361  strlcpy(SlaveName, slavedevice, DEVICELEN);
362  return 0;
363 
364  error:
365  if (slavefd != -1) close(slavefd);
366  if (masterfd != -1) close(masterfd);
367  if (fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
368  return -1;
369 #else
370  /* BSD */
371  int masterfd = -1, slavefd = -1;
372  int i;
373  char MasterName[DEVICELEN];
374 
375 #define HEX1(c) \
376  c"0",c"1",c"2",c"3",c"4",c"5",c"6",c"7", \
377  c"8",c"9",c"a",c"b",c"c",c"d",c"e",c"f"
378 
379 #if defined(__hpux)
380  static const char MasterDevice[] = "/dev/ptym/pty%s";
381  static const char SlaveDevice[] = "/dev/pty/tty%s";
382  static const char deviceNo[][3] = {
383  HEX1("p"), HEX1("q"), HEX1("r"), HEX1("s"),
384  HEX1("t"), HEX1("u"), HEX1("v"), HEX1("w"),
385  };
386 #elif defined(_IBMESA) /* AIX/ESA */
387  static const char MasterDevice[] = "/dev/ptyp%s";
388  static const char SlaveDevice[] = "/dev/ttyp%s";
389  static const char deviceNo[][3] = {
390  HEX1("0"), HEX1("1"), HEX1("2"), HEX1("3"),
391  HEX1("4"), HEX1("5"), HEX1("6"), HEX1("7"),
392  HEX1("8"), HEX1("9"), HEX1("a"), HEX1("b"),
393  HEX1("c"), HEX1("d"), HEX1("e"), HEX1("f"),
394  };
395 #else /* 4.2BSD */
396  static const char MasterDevice[] = "/dev/pty%s";
397  static const char SlaveDevice[] = "/dev/tty%s";
398  static const char deviceNo[][3] = {
399  HEX1("p"), HEX1("q"), HEX1("r"), HEX1("s"),
400  };
401 #endif
402 #undef HEX1
403  for (i = 0; i < numberof(deviceNo); i++) {
404  const char *const devno = deviceNo[i];
405  snprintf(MasterName, sizeof MasterName, MasterDevice, devno);
406  if ((masterfd = rb_cloexec_open(MasterName,O_RDWR,0)) >= 0) {
407  rb_update_max_fd(masterfd);
408  *master = masterfd;
409  snprintf(SlaveName, DEVICELEN, SlaveDevice, devno);
410  if ((slavefd = rb_cloexec_open(SlaveName,O_RDWR,0)) >= 0) {
411  rb_update_max_fd(slavefd);
412  *slave = slavefd;
413  if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
414  if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
415  return 0;
416  }
417  close(masterfd);
418  }
419  }
420  error:
421  if (slavefd != -1) close(slavefd);
422  if (masterfd != -1) close(masterfd);
423  if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName);
424  return -1;
425 #endif
426 }
427 
428 static void
429 getDevice(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg)
430 {
431  if (get_device_once(master, slave, SlaveName, nomesg, 0)) {
432  rb_gc();
433  get_device_once(master, slave, SlaveName, nomesg, 1);
434  }
435 }
436 
437 static VALUE
438 pty_close_pty(VALUE assoc)
439 {
440  VALUE io;
441  int i;
442 
443  for (i = 0; i < 2; i++) {
444  io = rb_ary_entry(assoc, i);
445  if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
446  rb_io_close(io);
447  }
448  return Qnil;
449 }
450 
451 /*
452  * call-seq:
453  * PTY.open => [master_io, slave_file]
454  * PTY.open {|master_io, slave_file| ... } => block value
455  *
456  * Allocates a pty (pseudo-terminal).
457  *
458  * In the block form, yields two arguments <tt>master_io, slave_file</tt>
459  * and the value of the block is returned from +open+.
460  *
461  * The IO and File are both closed after the block completes if they haven't
462  * been already closed.
463  *
464  * PTY.open {|master, slave|
465  * p master #=> #<IO:masterpty:/dev/pts/1>
466  * p slave #=> #<File:/dev/pts/1>
467  * p slave.path #=> "/dev/pts/1"
468  * }
469  *
470  * In the non-block form, returns a two element array, <tt>[master_io,
471  * slave_file]</tt>.
472  *
473  * master, slave = PTY.open
474  * # do something with master for IO, or the slave file
475  *
476  * The arguments in both forms are:
477  *
478  * +master_io+:: the master of the pty, as an IO.
479  * +slave_file+:: the slave of the pty, as a File. The path to the
480  * terminal device is available via +slave_file.path+
481  *
482  * IO#raw! is usable to disable newline conversions:
483  *
484  * require 'io/console'
485  * PTY.open {|m, s|
486  * s.raw!
487  * ...
488  * }
489  *
490  */
491 static VALUE
492 pty_open(VALUE klass)
493 {
494  int master_fd, slave_fd;
495  char slavename[DEVICELEN];
496  VALUE master_io, slave_file;
497  rb_io_t *master_fptr, *slave_fptr;
498  VALUE assoc;
499 
500  getDevice(&master_fd, &slave_fd, slavename, 1);
501 
502  master_io = rb_obj_alloc(rb_cIO);
503  MakeOpenFile(master_io, master_fptr);
504  master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
505  master_fptr->fd = master_fd;
506  master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
507 
508  slave_file = rb_obj_alloc(rb_cFile);
509  MakeOpenFile(slave_file, slave_fptr);
511  slave_fptr->fd = slave_fd;
512  slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
513 
514  assoc = rb_assoc_new(master_io, slave_file);
515  if (rb_block_given_p()) {
516  return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
517  }
518  return assoc;
519 }
520 
521 static VALUE
522 pty_detach_process(struct pty_info *info)
523 {
524 #ifdef WNOHANG
525  int st;
526  if (rb_waitpid(info->child_pid, &st, WNOHANG) <= 0)
527  return Qnil;
528 #endif
530  return Qnil;
531 }
532 
533 /*
534  * call-seq:
535  * PTY.spawn(command_line) { |r, w, pid| ... }
536  * PTY.spawn(command_line) => [r, w, pid]
537  * PTY.spawn(command, arguments, ...) { |r, w, pid| ... }
538  * PTY.spawn(command, arguments, ...) => [r, w, pid]
539  *
540  * Spawns the specified command on a newly allocated pty. You can also use the
541  * alias ::getpty.
542  *
543  * The command's controlling tty is set to the slave device of the pty
544  * and its standard input/output/error is redirected to the slave device.
545  *
546  * +command+ and +command_line+ are the full commands to run, given a String.
547  * Any additional +arguments+ will be passed to the command.
548  *
549  * === Return values
550  *
551  * In the non-block form this returns an array of size three,
552  * <tt>[r, w, pid]</tt>.
553  *
554  * In the block form these same values will be yielded to the block:
555  *
556  * +r+:: A readable IO that contains the command's
557  * standard output and standard error
558  * +w+:: A writable IO that is the command's standard input
559  * +pid+:: The process identifier for the command.
560  */
561 static VALUE
562 pty_getpty(int argc, VALUE *argv, VALUE self)
563 {
564  VALUE res;
565  struct pty_info info;
566  rb_io_t *wfptr,*rfptr;
567  VALUE rport = rb_obj_alloc(rb_cFile);
568  VALUE wport = rb_obj_alloc(rb_cFile);
569  char SlaveName[DEVICELEN];
570 
571  MakeOpenFile(rport, rfptr);
572  MakeOpenFile(wport, wfptr);
573 
574  establishShell(argc, argv, &info, SlaveName);
575 
576  rfptr->mode = rb_io_modestr_fmode("r");
577  rfptr->fd = info.fd;
578  rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
579 
580  wfptr->mode = rb_io_modestr_fmode("w") | FMODE_SYNC;
581  wfptr->fd = rb_cloexec_dup(info.fd);
582  if (wfptr->fd == -1)
583  rb_sys_fail("dup()");
584  rb_update_max_fd(wfptr->fd);
585  wfptr->pathv = rfptr->pathv;
586 
587  res = rb_ary_new2(3);
588  rb_ary_store(res,0,(VALUE)rport);
589  rb_ary_store(res,1,(VALUE)wport);
590  rb_ary_store(res,2,PIDT2NUM(info.child_pid));
591 
592  if (rb_block_given_p()) {
593  rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
594  return Qnil;
595  }
596  return res;
597 }
598 
599 NORETURN(static void raise_from_check(rb_pid_t pid, int status));
600 static void
601 raise_from_check(rb_pid_t pid, int status)
602 {
603  const char *state;
604  VALUE msg;
605  VALUE exc;
606 
607 #if defined(WIFSTOPPED)
608 #elif defined(IF_STOPPED)
609 #define WIFSTOPPED(status) IF_STOPPED(status)
610 #else
611 ---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
612 #endif /* WIFSTOPPED | IF_STOPPED */
613  if (WIFSTOPPED(status)) { /* suspend */
614  state = "stopped";
615  }
616  else if (kill(pid, 0) == 0) {
617  state = "changed";
618  }
619  else {
620  state = "exited";
621  }
622  msg = rb_sprintf("pty - %s: %ld", state, (long)pid);
623  exc = rb_exc_new_str(eChildExited, msg);
624  rb_iv_set(exc, "status", rb_last_status_get());
625  rb_exc_raise(exc);
626 }
627 
628 /*
629  * call-seq:
630  * PTY.check(pid, raise = false) => Process::Status or nil
631  * PTY.check(pid, true) => nil or raises PTY::ChildExited
632  *
633  * Checks the status of the child process specified by +pid+.
634  * Returns +nil+ if the process is still alive.
635  *
636  * If the process is not alive, and +raise+ was true, a PTY::ChildExited
637  * exception will be raised. Otherwise it will return a Process::Status
638  * instance.
639  *
640  * +pid+:: The process id of the process to check
641  * +raise+:: If +true+ and the process identified by +pid+ is no longer
642  * alive a PTY::ChildExited is raised.
643  *
644  */
645 static VALUE
646 pty_check(int argc, VALUE *argv, VALUE self)
647 {
648  VALUE pid, exc;
649  rb_pid_t cpid;
650  int status;
651  const int flag =
652 #ifdef WNOHANG
653  WNOHANG|
654 #endif
655 #ifdef WUNTRACED
656  WUNTRACED|
657 #endif
658  0;
659 
660  rb_scan_args(argc, argv, "11", &pid, &exc);
661  cpid = rb_waitpid(NUM2PIDT(pid), &status, flag);
662  if (cpid == -1 || cpid == 0) return Qnil;
663 
664  if (!RTEST(exc)) return rb_last_status_get();
665  raise_from_check(cpid, status);
666 
667  UNREACHABLE;
668 }
669 
670 static VALUE cPTY;
671 
672 /*
673  * Document-class: PTY::ChildExited
674  *
675  * Thrown when PTY::check is called for a pid that represents a process that
676  * has exited.
677  */
678 
679 /*
680  * Document-class: PTY
681  *
682  * Creates and managed pseudo terminals (PTYs). See also
683  * http://en.wikipedia.org/wiki/Pseudo_terminal
684  *
685  * PTY allows you to allocate new terminals using ::open or ::spawn a new
686  * terminal with a specific command.
687  *
688  * == Example
689  *
690  * In this example we will change the buffering type in the +factor+ command,
691  * assuming that factor uses stdio for stdout buffering.
692  *
693  * If IO.pipe is used instead of PTY.open, this code deadlocks because factor's
694  * stdout is fully buffered.
695  *
696  * # start by requiring the standard library PTY
697  * require 'pty'
698  *
699  * master, slave = PTY.open
700  * read, write = IO.pipe
701  * pid = spawn("factor", :in=>read, :out=>slave)
702  * read.close # we dont need the read
703  * slave.close # or the slave
704  *
705  * # pipe "42" to the factor command
706  * write.puts "42"
707  * # output the response from factor
708  * p master.gets #=> "42: 2 3 7\n"
709  *
710  * # pipe "144" to factor and print out the response
711  * write.puts "144"
712  * p master.gets #=> "144: 2 2 2 2 3 3\n"
713  * write.close # close the pipe
714  *
715  * # The result of read operation when pty slave is closed is platform
716  * # dependent.
717  * ret = begin
718  * master.gets # FreeBSD returns nil.
719  * rescue Errno::EIO # GNU/Linux raises EIO.
720  * nil
721  * end
722  * p ret #=> nil
723  *
724  * == License
725  *
726  * C) Copyright 1998 by Akinori Ito.
727  *
728  * This software may be redistributed freely for this purpose, in full
729  * or in part, provided that this entire copyright notice is included
730  * on any copies of this software and applications and derivations thereof.
731  *
732  * This software is provided on an "as is" basis, without warranty of any
733  * kind, either expressed or implied, as to any matter including, but not
734  * limited to warranty of fitness of purpose, or merchantability, or
735  * results obtained from use of this software.
736  */
737 
738 void
739 Init_pty(void)
740 {
741  cPTY = rb_define_module("PTY");
742  /* :nodoc: */
743  rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
744  rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
745  rb_define_singleton_method(cPTY,"check",pty_check,-1);
746  rb_define_singleton_method(cPTY,"open",pty_open,0);
747 
748  eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
749  rb_define_method(eChildExited,"status",echild_status,0);
750 }
void rb_gc(void)
Definition: gc.c:6727
#define WNOHANG
Definition: win32.h:128
int slave
Definition: pty.c:84
int fd
Definition: pty.c:77
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1215
Definition: pty.c:83
VALUE rb_detach_process(rb_pid_t pid)
Definition: process.c:1097
int ioctl(int, int,...)
Definition: win32.c:2756
#define FMODE_READWRITE
Definition: io.h:104
void rb_update_max_fd(int fd)
Definition: io.c:191
#define WIFSTOPPED(status)
Definition: pty.c:34
rb_uid_t getuid(void)
Definition: win32.c:2710
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1716
int rb_block_given_p(void)
Determines if the current method is given a block.
Definition: eval.c:835
#define NUM2PIDT(v)
Definition: ruby.h:326
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Definition: io.c:257
int master
Definition: pty.c:84
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:2284
#define PIDT2NUM(v)
Definition: ruby.h:323
void rb_jump_tag(int tag)
Continues the exception caught by rb_protect() and rb_eval_string_protect().
Definition: eval.c:821
Definition: io.h:62
int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3150
#define UNREACHABLE
Definition: ruby.h:46
VALUE rb_cFile
Definition: file.c:139
int kill(int, int)
Definition: win32.c:4783
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:3095
VALUE execarg_obj
Definition: pty.c:86
int rb_io_modestr_fmode(const char *modestr)
Definition: io.c:5143
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:693
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1210
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Definition: error.c:848
#define RB_GC_GUARD(v)
Definition: ruby.h:552
#define FMODE_DUPLEX
Definition: io.h:108
VALUE rb_obj_alloc(VALUE)
Allocates an instance of klass.
Definition: object.c:2121
VALUE rb_execarg_new(int argc, const VALUE *argv, int accept_shell)
Definition: process.c:2257
Definition: pty.c:76
#define RFILE(obj)
Definition: ruby.h:1206
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
An equivalent to ensure clause.
Definition: eval.c:1035
#define rb_ary_new2
Definition: intern.h:90
int mode
Definition: io.h:65
struct rb_execarg * eargp
Definition: pty.c:87
#define RB_TYPE_P(obj, type)
Definition: ruby.h:527
#define fail()
#define O_CLOEXEC
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
Definition: process.c:2268
#define HEX1(c)
#define snprintf
Definition: subst.h:6
int chown(const char *, int, int)
Definition: win32.c:4757
int fd
Definition: io.h:64
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)
Definition: array.c:815
int argc
Definition: ruby.c:187
int seteuid(pid_t pid)
#define rb_str_new2
Definition: intern.h:835
#define numberof(array)
Definition: etc.c:618
void rb_sys_fail(const char *mesg)
Definition: error.c:2403
RUBY_EXTERN VALUE rb_cIO
Definition: ruby.h:1913
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1731
VALUE rb_yield(VALUE)
Definition: vm_eval.c:973
int errno
VALUE rb_obj_freeze(VALUE)
call-seq: obj.freeze -> obj
Definition: object.c:1331
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1452
void rb_execarg_parent_start(VALUE execarg_obj)
Definition: process.c:2457
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1908
rb_pid_t child_pid
Definition: pty.c:78
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:639
#define Qnil
Definition: ruby.h:438
void rb_exc_raise(VALUE mesg)
Raises an exception in the current thread.
Definition: eval.c:615
#define mode_t
Definition: win32.h:119
VALUE rb_io_close(VALUE)
Definition: io.c:4501
unsigned long VALUE
Definition: ruby.h:85
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
Definition: strlcpy.c:29
VALUE rb_str_new_cstr(const char *)
Definition: string.c:771
NORETURN(static void raise_from_check(rb_pid_t pid, int status))
#define getenv(name)
Definition: win32.c:71
char * slavename
Definition: pty.c:85
char * getlogin()
Definition: win32.c:867
void rb_fd_fix_cloexec(int fd)
Definition: io.c:233
VALUE rb_eRuntimeError
Definition: error.c:800
VALUE pathv
Definition: io.h:68
#define RTEST(v)
Definition: ruby.h:450
void Init_pty(void)
Definition: pty.c:739
#define ERROR_EXIT(str)
#define T_FILE
Definition: ruby.h:502
#define DEVICELEN
Definition: pty.c:51
const char * name
Definition: nkf.c:208
#define FMODE_SYNC
Definition: io.h:106
#define FMODE_TTY
Definition: io.h:107
#define MakeOpenFile(obj, fp)
Definition: io.h:122
RUBY_EXTERN int dup2(int, int)
Definition: dup2.c:27
int rb_cloexec_dup(int oldfd)
Definition: io.c:283
rb_gid_t getgid(void)
Definition: win32.c:2724
void rb_execarg_parent_end(VALUE execarg_obj)
Definition: process.c:2496
VALUE rb_define_module(const char *name)
Definition: class.c:768
#define rb_intern(str)
VALUE rb_last_status_get(void)
Definition: process.c:479
#define NULL
Definition: _sdbm.c:102
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Definition: process.c:902
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1515
char ** argv
Definition: ruby.c:188