Ruby  2.0.0p645(2015-04-13revision50299)
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 #ifdef HAVE_SYS_WAIT_H
26 #include <sys/wait.h>
27 #else
28 #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
29 #endif
30 #include <ctype.h>
31 
32 #include "ruby/ruby.h"
33 #include "ruby/io.h"
34 #include "ruby/util.h"
35 #include "internal.h"
36 
37 #include <signal.h>
38 #ifdef HAVE_SYS_STROPTS_H
39 #include <sys/stropts.h>
40 #endif
41 
42 #ifdef HAVE_UNISTD_H
43 #include <unistd.h>
44 #endif
45 
46 #define DEVICELEN 16
47 
48 #ifndef HAVE_SETEUID
49 # ifdef HAVE_SETREUID
50 # define seteuid(e) setreuid(-1, (e))
51 # else /* NOT HAVE_SETREUID */
52 # ifdef HAVE_SETRESUID
53 # define seteuid(e) setresuid(-1, (e), -1)
54 # else /* NOT HAVE_SETRESUID */
55  /* I can't set euid. (;_;) */
56 # endif /* HAVE_SETRESUID */
57 # endif /* HAVE_SETREUID */
58 #endif /* NO_SETEUID */
59 
61 
62 /* Returns the exit status of the child for which PTY#check
63  * raised this exception
64  */
65 static VALUE
67 {
68  return rb_ivar_get(self, rb_intern("status"));
69 }
70 
71 struct pty_info {
72  int fd;
73  rb_pid_t child_pid;
74 };
75 
76 static void getDevice(int*, int*, char [DEVICELEN], int);
77 
78 struct child_info {
79  int master, slave;
80  char *slavename;
82  struct rb_execarg *eargp;
83 };
84 
85 static int
86 chfunc(void *data, char *errbuf, size_t errbuf_len)
87 {
88  struct child_info *carg = data;
89  int master = carg->master;
90  int slave = carg->slave;
91 
92 #define ERROR_EXIT(str) do { \
93  strlcpy(errbuf, (str), errbuf_len); \
94  return -1; \
95  } while (0)
96 
97  /*
98  * Set free from process group and controlling terminal
99  */
100 #ifdef HAVE_SETSID
101  (void) setsid();
102 #else /* HAS_SETSID */
103 # ifdef HAVE_SETPGRP
104 # ifdef SETGRP_VOID
105  if (setpgrp() == -1)
106  ERROR_EXIT("setpgrp()");
107 # else /* SETGRP_VOID */
108  if (setpgrp(0, getpid()) == -1)
109  ERROR_EXIT("setpgrp()");
110  {
111  int i = rb_cloexec_open("/dev/tty", O_RDONLY, 0);
112  if (i < 0) ERROR_EXIT("/dev/tty");
113  rb_update_max_fd(i);
114  if (ioctl(i, TIOCNOTTY, (char *)0))
115  ERROR_EXIT("ioctl(TIOCNOTTY)");
116  close(i);
117  }
118 # endif /* SETGRP_VOID */
119 # endif /* HAVE_SETPGRP */
120 #endif /* HAS_SETSID */
121 
122  /*
123  * obtain new controlling terminal
124  */
125 #if defined(TIOCSCTTY)
126  close(master);
127  (void) ioctl(slave, TIOCSCTTY, (char *)0);
128  /* errors ignored for sun */
129 #else
130  close(slave);
131  slave = rb_cloexec_open(carg->slavename, O_RDWR, 0);
132  if (slave < 0) {
133  ERROR_EXIT("open: pty slave");
134  }
135  rb_update_max_fd(slave);
136  close(master);
137 #endif
138  dup2(slave,0);
139  dup2(slave,1);
140  dup2(slave,2);
141  close(slave);
142 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
143  seteuid(getuid());
144 #endif
145 
146  return rb_exec_async_signal_safe(carg->eargp, errbuf, sizeof(errbuf_len));
147 #undef ERROR_EXIT
148 }
149 
150 static void
152  char SlaveName[DEVICELEN])
153 {
154  int master, slave, status = 0;
155  rb_pid_t pid;
156  char *p, *getenv();
157  struct passwd *pwent;
158  VALUE v;
159  struct child_info carg;
160  char errbuf[32];
161 
162  if (argc == 0) {
163  const char *shellname;
164 
165  if ((p = getenv("SHELL")) != NULL) {
166  shellname = p;
167  }
168  else {
169  pwent = getpwuid(getuid());
170  if (pwent && pwent->pw_shell)
171  shellname = pwent->pw_shell;
172  else
173  shellname = "/bin/sh";
174  }
175  v = rb_str_new2(shellname);
176  argc = 1;
177  argv = &v;
178  }
179 
180  carg.execarg_obj = rb_execarg_new(argc, argv, 1);
181  carg.eargp = rb_execarg_get(carg.execarg_obj);
183 
184  getDevice(&master, &slave, SlaveName, 0);
185 
186  carg.master = master;
187  carg.slave = slave;
188  carg.slavename = SlaveName;
189  errbuf[0] = '\0';
190  pid = rb_fork_async_signal_safe(&status, chfunc, &carg, Qnil, errbuf, sizeof(errbuf));
191 
192  if (pid < 0) {
193  int e = errno;
194  close(master);
195  close(slave);
196  errno = e;
197  if (status) rb_jump_tag(status);
198  rb_sys_fail(errbuf[0] ? errbuf : "fork failed");
199  }
200 
201  close(slave);
202 
203  info->child_pid = pid;
204  info->fd = master;
205 
206  RB_GC_GUARD(carg.execarg_obj);
207 }
208 
209 static int
210 no_mesg(char *slavedevice, int nomesg)
211 {
212  if (nomesg)
213  return chmod(slavedevice, 0600);
214  else
215  return 0;
216 }
217 
218 static int
219 get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
220 {
221 #if defined(HAVE_POSIX_OPENPT)
222  /* Unix98 PTY */
223  int masterfd = -1, slavefd = -1;
224  char *slavedevice;
225  struct sigaction dfl, old;
226 
227  dfl.sa_handler = SIG_DFL;
228  dfl.sa_flags = 0;
229  sigemptyset(&dfl.sa_mask);
230 
231 #if defined(__sun) || defined(__FreeBSD__)
232  /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
233  /* FreeBSD 8 supported O_CLOEXEC for posix_openpt, but FreeBSD 9 removed it.
234  * http://www.freebsd.org/cgi/query-pr.cgi?pr=162374 */
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;
238  rb_fd_fix_cloexec(masterfd);
239 #else
240  {
241  int flags = O_RDWR|O_NOCTTY;
242 # if defined(O_CLOEXEC)
243  /* glibc posix_openpt() in GNU/Linux calls open("/dev/ptmx", flags) internally.
244  * So version dependency on GNU/Linux is same as O_CLOEXEC with open().
245  * O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
246  flags |= O_CLOEXEC;
247 # endif
248  if ((masterfd = posix_openpt(flags)) == -1) goto error;
249  }
250  rb_fd_fix_cloexec(masterfd);
251  if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
252  if (grantpt(masterfd) == -1) goto grantpt_error;
253 #endif
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;
259  rb_update_max_fd(slavefd);
260 
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;
265 #endif
266 
267  *master = masterfd;
268  *slave = slavefd;
269  strlcpy(SlaveName, slavedevice, DEVICELEN);
270  return 0;
271 
272  grantpt_error:
273  sigaction(SIGCHLD, &old, NULL);
274  error:
275  if (slavefd != -1) close(slavefd);
276  if (masterfd != -1) close(masterfd);
277  if (fail) {
278  rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
279  }
280  return -1;
281 #elif defined HAVE_OPENPTY
282 /*
283  * Use openpty(3) of 4.3BSD Reno and later,
284  * or the same interface function.
285  */
286  if (openpty(master, slave, SlaveName,
287  (struct termios *)0, (struct winsize *)0) == -1) {
288  if (!fail) return -1;
289  rb_raise(rb_eRuntimeError, "openpty() failed");
290  }
291  rb_fd_fix_cloexec(*master);
292  rb_fd_fix_cloexec(*slave);
293  if (no_mesg(SlaveName, nomesg) == -1) {
294  if (!fail) return -1;
295  rb_raise(rb_eRuntimeError, "can't chmod slave pty");
296  }
297 
298  return 0;
299 
300 #elif defined HAVE__GETPTY
301  /* SGI IRIX */
302  char *name;
303  mode_t mode = nomesg ? 0600 : 0622;
304 
305  if (!(name = _getpty(master, O_RDWR, mode, 0))) {
306  if (!fail) return -1;
307  rb_raise(rb_eRuntimeError, "_getpty() failed");
308  }
309  rb_fd_fix_cloexec(*master);
310 
311  *slave = rb_cloexec_open(name, O_RDWR, 0);
312  /* error check? */
313  rb_update_max_fd(*slave);
314  strlcpy(SlaveName, name, DEVICELEN);
315 
316  return 0;
317 #elif defined(HAVE_PTSNAME)
318  /* System V */
319  int masterfd = -1, slavefd = -1;
320  char *slavedevice;
321  void (*s)();
322 
323  extern char *ptsname(int);
324  extern int unlockpt(int);
325  extern int grantpt(int);
326 
327 #if defined(__sun)
328  /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
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;
332  rb_fd_fix_cloexec(masterfd);
333 #else
334  if((masterfd = rb_cloexec_open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
335  rb_update_max_fd(masterfd);
336  s = signal(SIGCHLD, SIG_DFL);
337  if(grantpt(masterfd) == -1) goto error;
338 #endif
339  signal(SIGCHLD, s);
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;
344  rb_update_max_fd(slavefd);
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");
349 #endif
350  *master = masterfd;
351  *slave = slavefd;
352  strlcpy(SlaveName, slavedevice, DEVICELEN);
353  return 0;
354 
355  error:
356  if (slavefd != -1) close(slavefd);
357  if (masterfd != -1) close(masterfd);
358  if (fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
359  return -1;
360 #else
361  /* BSD */
362  int masterfd = -1, slavefd = -1;
363  const char *const *p;
364  char MasterName[DEVICELEN];
365 
366 #if defined(__hpux)
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",
386  0
387  };
388 #elif defined(_IBMESA) /* AIX/ESA */
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",
408  0
409  };
410 #else /* 4.2BSD */
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",
422  0
423  };
424 #endif
425  for (p = deviceNo; *p != NULL; p++) {
426  snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
427  if ((masterfd = rb_cloexec_open(MasterName,O_RDWR,0)) >= 0) {
428  rb_update_max_fd(masterfd);
429  *master = masterfd;
430  snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
431  if ((slavefd = rb_cloexec_open(SlaveName,O_RDWR,0)) >= 0) {
432  rb_update_max_fd(slavefd);
433  *slave = slavefd;
434  if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
435  if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
436  return 0;
437  }
438  close(masterfd);
439  }
440  }
441  error:
442  if (slavefd != -1) close(slavefd);
443  if (masterfd != -1) close(masterfd);
444  if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName);
445  return -1;
446 #endif
447 }
448 
449 static void
450 getDevice(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg)
451 {
452  if (get_device_once(master, slave, SlaveName, nomesg, 0)) {
453  rb_gc();
454  get_device_once(master, slave, SlaveName, nomesg, 1);
455  }
456 }
457 
458 static VALUE
460 {
461  VALUE io;
462  int i;
463 
464  for (i = 0; i < 2; i++) {
465  io = rb_ary_entry(assoc, i);
466  if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
467  rb_io_close(io);
468  }
469  return Qnil;
470 }
471 
472 /*
473  * call-seq:
474  * PTY.open => [master_io, slave_file]
475  * PTY.open {|master_io, slave_file| ... } => block value
476  *
477  * Allocates a pty (pseudo-terminal).
478  *
479  * In the block form, yields two arguments <tt>master_io, slave_file</tt>
480  * and the value of the block is returned from +open+.
481  *
482  * The IO and File are both closed after the block completes if they haven't
483  * been already closed.
484  *
485  * PTY.open {|master, slave|
486  * p master #=> #<IO:masterpty:/dev/pts/1>
487  * p slave #=> #<File:/dev/pts/1>
488  * p slave.path #=> "/dev/pts/1"
489  * }
490  *
491  * In the non-block form, returns a two element array, <tt>[master_io,
492  * slave_file]</tt>.
493  *
494  * master, slave = PTY.open
495  * # do something with master for IO, or the slave file
496  *
497  * The arguments in both forms are:
498  *
499  * +master_io+:: the master of the pty, as an IO.
500  * +slave_file+:: the slave of the pty, as a File. The path to the
501  * terminal device is available via +slave_file.path+
502  *
503  */
504 static VALUE
506 {
507  int master_fd, slave_fd;
508  char slavename[DEVICELEN];
509  VALUE master_io, slave_file;
510  rb_io_t *master_fptr, *slave_fptr;
511  VALUE assoc;
512 
513  getDevice(&master_fd, &slave_fd, slavename, 1);
514 
515  master_io = rb_obj_alloc(rb_cIO);
516  MakeOpenFile(master_io, master_fptr);
517  master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
518  master_fptr->fd = master_fd;
519  master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
520 
521  slave_file = rb_obj_alloc(rb_cFile);
522  MakeOpenFile(slave_file, slave_fptr);
524  slave_fptr->fd = slave_fd;
525  slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
526 
527  assoc = rb_assoc_new(master_io, slave_file);
528  if (rb_block_given_p()) {
529  return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
530  }
531  return assoc;
532 }
533 
534 static VALUE
536 {
538  return Qnil;
539 }
540 
541 /*
542  * call-seq:
543  * PTY.spawn(command_line) { |r, w, pid| ... }
544  * PTY.spawn(command_line) => [r, w, pid]
545  * PTY.spawn(command, arguments, ...) { |r, w, pid| ... }
546  * PTY.spawn(command, arguments, ...) => [r, w, pid]
547  *
548  * Spawns the specified command on a newly allocated pty. You can also use the
549  * alias ::getpty.
550  *
551  * The command's controlling tty is set to the slave device of the pty
552  * and its standard input/output/error is redirected to the slave device.
553  *
554  * +command+ and +command_line+ are the full commands to run, given a String.
555  * Any additional +arguments+ will be passed to the command.
556  *
557  * === Return values
558  *
559  * In the non-block form this returns an array of size three,
560  * <tt>[r, w, pid]</tt>.
561  *
562  * In the block form these same values will be yielded to the block:
563  *
564  * +r+:: A readable IO that that contains the command's
565  * standard output and standard error
566  * +w+:: A writable IO that is the command's standard input
567  * +pid+:: The process identifier for the command.
568  */
569 static VALUE
571 {
572  VALUE res;
573  struct pty_info info;
574  rb_io_t *wfptr,*rfptr;
575  VALUE rport = rb_obj_alloc(rb_cFile);
576  VALUE wport = rb_obj_alloc(rb_cFile);
577  char SlaveName[DEVICELEN];
578 
579  MakeOpenFile(rport, rfptr);
580  MakeOpenFile(wport, wfptr);
581 
582  establishShell(argc, argv, &info, SlaveName);
583 
584  rfptr->mode = rb_io_mode_flags("r");
585  rfptr->fd = info.fd;
586  rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
587 
588  wfptr->mode = rb_io_mode_flags("w") | FMODE_SYNC;
589  wfptr->fd = rb_cloexec_dup(info.fd);
590  if (wfptr->fd == -1)
591  rb_sys_fail("dup()");
592  rb_update_max_fd(wfptr->fd);
593  wfptr->pathv = rfptr->pathv;
594 
595  res = rb_ary_new2(3);
596  rb_ary_store(res,0,(VALUE)rport);
597  rb_ary_store(res,1,(VALUE)wport);
598  rb_ary_store(res,2,PIDT2NUM(info.child_pid));
599 
600  if (rb_block_given_p()) {
602  return Qnil;
603  }
604  return res;
605 }
606 
607 NORETURN(static void raise_from_check(pid_t pid, int status));
608 static void
609 raise_from_check(pid_t pid, int status)
610 {
611  const char *state;
612  VALUE msg;
613  VALUE exc;
614 
615 #if defined(WIFSTOPPED)
616 #elif defined(IF_STOPPED)
617 #define WIFSTOPPED(status) IF_STOPPED(status)
618 #else
619 ---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
620 #endif /* WIFSTOPPED | IF_STOPPED */
621  if (WIFSTOPPED(status)) { /* suspend */
622  state = "stopped";
623  }
624  else if (kill(pid, 0) == 0) {
625  state = "changed";
626  }
627  else {
628  state = "exited";
629  }
630  msg = rb_sprintf("pty - %s: %ld", state, (long)pid);
631  exc = rb_exc_new3(eChildExited, msg);
632  rb_iv_set(exc, "status", rb_last_status_get());
633  rb_exc_raise(exc);
634 }
635 
636 /*
637  * call-seq:
638  * PTY.check(pid, raise = false) => Process::Status or nil
639  * PTY.check(pid, true) => nil or raises PTY::ChildExited
640  *
641  * Checks the status of the child process specified by +pid+.
642  * Returns +nil+ if the process is still alive.
643  *
644  * If the process is not alive, and +raise+ was true, a PTY::ChildExited
645  * exception will be raised. Otherwise it will return a Process::Status
646  * instance.
647  *
648  * +pid+:: The process id of the process to check
649  * +raise+:: If +true+ and the process identified by +pid+ is no longer
650  * alive a PTY::ChildExited is raised.
651  *
652  */
653 static VALUE
655 {
656  VALUE pid, exc;
657  pid_t cpid;
658  int status;
659 
660  rb_scan_args(argc, argv, "11", &pid, &exc);
661  cpid = rb_waitpid(NUM2PIDT(pid), &status, WNOHANG|WUNTRACED);
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  * m.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
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 
750 }
VALUE data
Definition: tcltklib.c:3367
#define RB_TYPE_P(obj, type)
#define WNOHANG
Definition: win32.h:109
int slave
Definition: pty.c:79
int fd
Definition: pty.c:72
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1088
Definition: pty.c:78
int ioctl(int, int,...)
Definition: win32.c:2444
#define FMODE_READWRITE
Definition: io.h:105
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)
Win32OLEIDispatch * p
Definition: win32ole.c:786
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2594
VALUE rb_last_status_get(void)
Definition: process.c:309
#define WIFSTOPPED(status)
Definition: pty.c:28
rb_uid_t getuid(void)
Definition: win32.c:2398
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1497
static VALUE pty_check(int argc, VALUE *argv, VALUE self)
Definition: pty.c:654
#define NUM2PIDT(v)
Definition: ruby.h:332
int master
Definition: pty.c:79
#define PIDT2NUM(v)
Definition: ruby.h:329
static VALUE pty_close_pty(VALUE assoc)
Definition: pty.c:459
ssize_t i
Definition: bigdecimal.c:5676
Definition: io.h:63
Tcl_CmdInfo * info
Definition: tcltklib.c:1462
VALUE rb_str_new_cstr(const char *)
Definition: string.c:447
int status
Definition: tcltklib.c:2196
VALUE rb_obj_freeze(VALUE)
Definition: object.c:1012
#define UNREACHABLE
Definition: ruby.h:40
void rb_update_max_fd(int fd)
Definition: io.c:164
VALUE exc
Definition: tcltklib.c:3095
int kill(int, int)
Definition: win32.c:4089
#define RFILE(obj)
VALUE execarg_obj
Definition: pty.c:81
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:534
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1788
VALUE rb_execarg_new(int argc, VALUE *argv, int accept_shell)
Definition: process.c:2227
static int get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
Definition: pty.c:219
#define T_FILE
#define FMODE_DUPLEX
Definition: io.h:109
static VALUE pty_open(VALUE klass)
Definition: pty.c:505
Definition: pty.c:71
#define rb_str_new2
static void establishShell(int argc, VALUE *argv, struct pty_info *info, char SlaveName[DEVICELEN])
Definition: pty.c:151
int rb_cloexec_dup(int oldfd)
Definition: io.c:225
int state
Definition: tcltklib.c:1461
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1116
static void getDevice(int *, int *, char[DEVICELEN], int)
Definition: pty.c:450
void rb_fd_fix_cloexec(int fd)
Definition: io.c:202
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
int mode
Definition: io.h:66
struct rb_execarg * eargp
Definition: pty.c:82
#define NORETURN(x)
Definition: ruby.h:31
void rb_exc_raise(VALUE mesg)
Definition: eval.c:527
static VALUE eChildExited
Definition: pty.c:60
#define fail()
#define O_CLOEXEC
void rb_gc(void)
Definition: gc.c:3110
int rb_block_given_p(void)
Definition: eval.c:672
#define Qnil
Definition: tcltklib.c:1895
VALUE rb_eRuntimeError
Definition: error.c:515
VALUE rb_detach_process(rb_pid_t pid)
Definition: process.c:1015
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
Definition: process.c:2238
int flags
Definition: tcltklib.c:3022
int chown(const char *, int, int)
Definition: win32.c:4075
static int no_mesg(char *slavedevice, int nomesg)
Definition: pty.c:210
int fd
Definition: io.h:64
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:719
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Definition: process.c:746
int seteuid(pid_t pid)
Tcl_Interp * slave
Definition: tcltklib.c:5601
static VALUE VALUE assoc
Definition: tkutil.c:545
VALUE * argv
Definition: tcltklib.c:1970
VALUE rb_yield(VALUE)
Definition: vm_eval.c:933
#define RTEST(v)
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1512
int errno
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1275
static int chfunc(void *data, char *errbuf, size_t errbuf_len)
Definition: pty.c:86
static VALUE cPTY
Definition: pty.c:670
void Init_pty()
Definition: pty.c:739
register char * s
Definition: os2.c:56
VP_EXPORT void
Definition: bigdecimal.c:5104
VALUE mode
Definition: tcltklib.c:1663
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
rb_pid_t child_pid
Definition: pty.c:73
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:545
static void raise_from_check(pid_t pid, int status)
Definition: pty.c:609
int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3056
#define RB_GC_GUARD(v)
#define mode_t
Definition: win32.h:100
int argc
Definition: tcltklib.c:1969
char * getenv()
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:804
#define rb_io_mode_flags(modestr)
Definition: io.h:192
void rb_sys_fail(const char *mesg)
Definition: error.c:1907
void rb_jump_tag(int tag)
Definition: eval.c:666
RUBY_EXTERN VALUE rb_cIO
Definition: ripper.y:1442
VALUE msg
Definition: tcltklib.c:846
RUBY_EXTERN VALUE rb_cFile
Definition: ripper.y:1437
char * slavename
Definition: pty.c:80
static VALUE pty_getpty(int argc, VALUE *argv, VALUE self)
Definition: pty.c:570
sighandler_t signal(int signum, sighandler_t handler)
VALUE rb_exc_new3(VALUE etype, VALUE str)
Definition: error.c:553
VALUE pathv
Definition: io.h:69
klass
Definition: tcltklib.c:3503
#define ERROR_EXIT(str)
RUBY_EXTERN int dup2(int, int)
Definition: dup2.c:27
gz io
Definition: zlib.c:2261
#define DEVICELEN
Definition: pty.c:46
VALUE rb_ary_new2(long capa)
Definition: array.c:417
Real * res
Definition: bigdecimal.c:1247
static VALUE echild_status(VALUE self)
Definition: pty.c:66
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1740
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Definition: io.c:209
#define FMODE_SYNC
Definition: io.h:107
#define FMODE_TTY
Definition: io.h:108
#define MakeOpenFile(obj, fp)
Definition: io.h:129
VALUE rb_io_close(VALUE)
Definition: io.c:4233
static VALUE pty_detach_process(struct pty_info *info)
Definition: pty.c:535
BDIGIT e
Definition: bigdecimal.c:5106
unsigned long VALUE
Definition: ripper.y:104
rb_gid_t getgid(void)
Definition: win32.c:2412
#define snprintf
VALUE rb_define_module(const char *name)
Definition: class.c:606
#define rb_intern(str)
BDIGIT v
Definition: bigdecimal.c:5677
#define NULL
Definition: _sdbm.c:102
const char * name
Definition: nkf.c:208
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
static VALUE VALUE master
Definition: tcltklib.c:6541
void rb_execarg_fixup(VALUE execarg_obj)
Definition: process.c:2291