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