Ruby  1.9.3p448(2013-06-27revision41675)
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 
36 #include <signal.h>
37 #ifdef HAVE_SYS_STROPTS_H
38 #include <sys/stropts.h>
39 #endif
40 
41 #ifdef HAVE_UNISTD_H
42 #include <unistd.h>
43 #endif
44 
45 #define DEVICELEN 16
46 
47 #if !defined(HAVE_OPENPTY)
48 #if defined(__hpux)
49 static const
50 char MasterDevice[] = "/dev/ptym/pty%s",
51  SlaveDevice[] = "/dev/pty/tty%s",
52  *const deviceNo[] = {
53  "p0","p1","p2","p3","p4","p5","p6","p7",
54  "p8","p9","pa","pb","pc","pd","pe","pf",
55  "q0","q1","q2","q3","q4","q5","q6","q7",
56  "q8","q9","qa","qb","qc","qd","qe","qf",
57  "r0","r1","r2","r3","r4","r5","r6","r7",
58  "r8","r9","ra","rb","rc","rd","re","rf",
59  "s0","s1","s2","s3","s4","s5","s6","s7",
60  "s8","s9","sa","sb","sc","sd","se","sf",
61  "t0","t1","t2","t3","t4","t5","t6","t7",
62  "t8","t9","ta","tb","tc","td","te","tf",
63  "u0","u1","u2","u3","u4","u5","u6","u7",
64  "u8","u9","ua","ub","uc","ud","ue","uf",
65  "v0","v1","v2","v3","v4","v5","v6","v7",
66  "v8","v9","va","vb","vc","vd","ve","vf",
67  "w0","w1","w2","w3","w4","w5","w6","w7",
68  "w8","w9","wa","wb","wc","wd","we","wf",
69  0,
70  };
71 #elif defined(_IBMESA) /* AIX/ESA */
72 static const
73 char MasterDevice[] = "/dev/ptyp%s",
74  SlaveDevice[] = "/dev/ttyp%s",
75  *const deviceNo[] = {
76 "00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f",
77 "10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f",
78 "20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f",
79 "30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f",
80 "40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f",
81 "50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f",
82 "60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f",
83 "70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f",
84 "80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f",
85 "90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f",
86 "a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af",
87 "b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf",
88 "c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf",
89 "d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df",
90 "e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef",
91 "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff",
92  };
93 #elif !defined(HAVE_PTSNAME)
94 static const
95 char MasterDevice[] = "/dev/pty%s",
96  SlaveDevice[] = "/dev/tty%s",
97  *const deviceNo[] = {
98  "p0","p1","p2","p3","p4","p5","p6","p7",
99  "p8","p9","pa","pb","pc","pd","pe","pf",
100  "q0","q1","q2","q3","q4","q5","q6","q7",
101  "q8","q9","qa","qb","qc","qd","qe","qf",
102  "r0","r1","r2","r3","r4","r5","r6","r7",
103  "r8","r9","ra","rb","rc","rd","re","rf",
104  "s0","s1","s2","s3","s4","s5","s6","s7",
105  "s8","s9","sa","sb","sc","sd","se","sf",
106  0,
107  };
108 #endif
109 #endif /* !defined(HAVE_OPENPTY) */
110 
111 #ifndef HAVE_SETEUID
112 # ifdef HAVE_SETREUID
113 # define seteuid(e) setreuid(-1, (e))
114 # else /* NOT HAVE_SETREUID */
115 # ifdef HAVE_SETRESUID
116 # define seteuid(e) setresuid(-1, (e), -1)
117 # else /* NOT HAVE_SETRESUID */
118  /* I can't set euid. (;_;) */
119 # endif /* HAVE_SETRESUID */
120 # endif /* HAVE_SETREUID */
121 #endif /* NO_SETEUID */
122 
124 
125 /* Returns the exit status of the child for which PTY#check
126  * raised this exception
127  */
128 static VALUE
130 {
131  return rb_ivar_get(self, rb_intern("status"));
132 }
133 
134 struct pty_info {
135  int fd;
136  rb_pid_t child_pid;
137 };
138 
139 static void getDevice(int*, int*, char [DEVICELEN], int);
140 
141 struct child_info {
142  int master, slave;
143  char *slavename;
144  int argc;
146 };
147 
148 static int
149 chfunc(void *data, char *errbuf, size_t errbuf_len)
150 {
151  struct child_info *carg = data;
152  int master = carg->master;
153  int slave = carg->slave;
154  int argc = carg->argc;
155  VALUE *argv = carg->argv;
156 
157 #define ERROR_EXIT(str) do { \
158  strlcpy(errbuf, (str), errbuf_len); \
159  return -1; \
160  } while (0)
161 
163 
164  /*
165  * Set free from process group and controlling terminal
166  */
167 #ifdef HAVE_SETSID
168  (void) setsid();
169 #else /* HAS_SETSID */
170 # ifdef HAVE_SETPGRP
171 # ifdef SETGRP_VOID
172  if (setpgrp() == -1)
173  ERROR_EXIT("setpgrp()");
174 # else /* SETGRP_VOID */
175  if (setpgrp(0, getpid()) == -1)
176  ERROR_EXIT("setpgrp()");
177  {
178  int i = open("/dev/tty", O_RDONLY);
179  if (i < 0) ERROR_EXIT("/dev/tty");
180  rb_update_max_fd(i);
181  if (ioctl(i, TIOCNOTTY, (char *)0))
182  ERROR_EXIT("ioctl(TIOCNOTTY)");
183  close(i);
184  }
185 # endif /* SETGRP_VOID */
186 # endif /* HAVE_SETPGRP */
187 #endif /* HAS_SETSID */
188 
189  /*
190  * obtain new controlling terminal
191  */
192 #if defined(TIOCSCTTY)
193  close(master);
194  (void) ioctl(slave, TIOCSCTTY, (char *)0);
195  /* errors ignored for sun */
196 #else
197  close(slave);
198  slave = open(carg->slavename, O_RDWR);
199  if (slave < 0) {
200  ERROR_EXIT("open: pty slave");
201  }
202  rb_update_max_fd(slave);
203  close(master);
204 #endif
205  dup2(slave,0);
206  dup2(slave,1);
207  dup2(slave,2);
208  close(slave);
209 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
210  seteuid(getuid());
211 #endif
212 
213  rb_f_exec(argc, argv);
214  return 0;
215 #undef ERROR_EXIT
216 }
217 
218 static void
219 establishShell(int argc, VALUE *argv, struct pty_info *info,
220  char SlaveName[DEVICELEN])
221 {
222  int master,slave;
223  rb_pid_t pid;
224  char *p, *getenv();
225  struct passwd *pwent;
226  VALUE v;
227  struct child_info carg;
228  char errbuf[32];
229 
230  if (argc == 0) {
231  const char *shellname;
232 
233  if ((p = getenv("SHELL")) != NULL) {
234  shellname = p;
235  }
236  else {
237  pwent = getpwuid(getuid());
238  if (pwent && pwent->pw_shell)
239  shellname = pwent->pw_shell;
240  else
241  shellname = "/bin/sh";
242  }
243  v = rb_str_new2(shellname);
244  argc = 1;
245  argv = &v;
246  }
247 
248  getDevice(&master, &slave, SlaveName, 0);
249 
250  carg.master = master;
251  carg.slave = slave;
252  carg.slavename = SlaveName;
253  carg.argc = argc;
254  carg.argv = argv;
255  errbuf[0] = '\0';
256  pid = rb_fork_err(0, chfunc, &carg, Qnil, errbuf, sizeof(errbuf));
257 
258  if (pid < 0) {
259  int e = errno;
260  close(master);
261  close(slave);
262  errno = e;
263  rb_sys_fail(errbuf[0] ? errbuf : "fork failed");
264  }
265 
266  close(slave);
267 
268  info->child_pid = pid;
269  info->fd = master;
270 }
271 
272 static int
273 no_mesg(char *slavedevice, int nomesg)
274 {
275  if (nomesg)
276  return chmod(slavedevice, 0600);
277  else
278  return 0;
279 }
280 
281 static int
282 get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
283 {
284 #if defined(HAVE_POSIX_OPENPT)
285  int masterfd = -1, slavefd = -1;
286  char *slavedevice;
287  struct sigaction dfl, old;
288 
289  dfl.sa_handler = SIG_DFL;
290  dfl.sa_flags = 0;
291  sigemptyset(&dfl.sa_mask);
292 
293  if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
294  rb_update_max_fd(masterfd);
295  if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
296  if (grantpt(masterfd) == -1) goto grantpt_error;
297  if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
298  if (unlockpt(masterfd) == -1) goto error;
299  if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
300  if (no_mesg(slavedevice, nomesg) == -1) goto error;
301  if ((slavefd = open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
302  rb_update_max_fd(slavefd);
303 
304 #if defined I_PUSH && !defined linux
305  if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
306  if (ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
307  if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) goto error;
308 #endif
309 
310  *master = masterfd;
311  *slave = slavefd;
312  strlcpy(SlaveName, slavedevice, DEVICELEN);
313  return 0;
314 
315  grantpt_error:
316  sigaction(SIGCHLD, &old, NULL);
317  error:
318  if (slavefd != -1) close(slavefd);
319  if (masterfd != -1) close(masterfd);
320  if (fail) {
321  rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
322  }
323  return -1;
324 #elif defined HAVE_OPENPTY
325 /*
326  * Use openpty(3) of 4.3BSD Reno and later,
327  * or the same interface function.
328  */
329  if (openpty(master, slave, SlaveName,
330  (struct termios *)0, (struct winsize *)0) == -1) {
331  if (!fail) return -1;
332  rb_raise(rb_eRuntimeError, "openpty() failed");
333  }
334  rb_update_max_fd(*master);
335  rb_update_max_fd(*slave);
336  if (no_mesg(SlaveName, nomesg) == -1) {
337  if (!fail) return -1;
338  rb_raise(rb_eRuntimeError, "can't chmod slave pty");
339  }
340 
341  return 0;
342 
343 #elif defined HAVE__GETPTY
344  char *name;
345  mode_t mode = nomesg ? 0600 : 0622;
346 
347  if (!(name = _getpty(master, O_RDWR, mode, 0))) {
348  if (!fail) return -1;
349  rb_raise(rb_eRuntimeError, "_getpty() failed");
350  }
351  rb_update_max_fd(*master);
352 
353  *slave = open(name, O_RDWR);
354  /* error check? */
355  rb_update_max_fd(*slave);
356  strlcpy(SlaveName, name, DEVICELEN);
357 
358  return 0;
359 #elif defined(HAVE_PTSNAME)
360  int masterfd = -1, slavefd = -1;
361  char *slavedevice;
362  void (*s)();
363 
364  extern char *ptsname(int);
365  extern int unlockpt(int);
366  extern int grantpt(int);
367 
368  if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
369  rb_update_max_fd(masterfd);
370  s = signal(SIGCHLD, SIG_DFL);
371  if(grantpt(masterfd) == -1) goto error;
372  signal(SIGCHLD, s);
373  if(unlockpt(masterfd) == -1) goto error;
374  if((slavedevice = ptsname(masterfd)) == NULL) goto error;
375  if (no_mesg(slavedevice, nomesg) == -1) goto error;
376  if((slavefd = open(slavedevice, O_RDWR, 0)) == -1) goto error;
377  rb_update_max_fd(slavefd);
378 #if defined I_PUSH && !defined linux
379  if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
380  if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
381  ioctl(slavefd, I_PUSH, "ttcompat");
382 #endif
383  *master = masterfd;
384  *slave = slavefd;
385  strlcpy(SlaveName, slavedevice, DEVICELEN);
386  return 0;
387 
388  error:
389  if (slavefd != -1) close(slavefd);
390  if (masterfd != -1) close(masterfd);
391  if (fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
392  return -1;
393 #else
394  int masterfd = -1, slavefd = -1;
395  const char *const *p;
396  char MasterName[DEVICELEN];
397 
398  for (p = deviceNo; *p != NULL; p++) {
399  snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
400  if ((masterfd = open(MasterName,O_RDWR,0)) >= 0) {
401  rb_update_max_fd(masterfd);
402  *master = masterfd;
403  snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
404  if ((slavefd = open(SlaveName,O_RDWR,0)) >= 0) {
405  rb_update_max_fd(slavefd);
406  *slave = slavefd;
407  if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
408  if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
409  return 0;
410  }
411  close(masterfd);
412  }
413  }
414  error:
415  if (slavefd != -1) close(slavefd);
416  if (masterfd != -1) close(masterfd);
417  if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName);
418  return -1;
419 #endif
420 }
421 
422 static void
423 getDevice(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg)
424 {
425  if (get_device_once(master, slave, SlaveName, nomesg, 0)) {
426  rb_gc();
427  get_device_once(master, slave, SlaveName, nomesg, 1);
428  }
429 }
430 
431 static VALUE
433 {
434  VALUE io;
435  int i;
436 
437  for (i = 0; i < 2; i++) {
438  io = rb_ary_entry(assoc, i);
439  if (TYPE(io) == T_FILE && 0 <= RFILE(io)->fptr->fd)
440  rb_io_close(io);
441  }
442  return Qnil;
443 }
444 
445 /*
446  * call-seq:
447  * PTY.open => [master_io, slave_file]
448  * PTY.open {|master_io, slave_file| ... } => block value
449  *
450  * Allocates a pty (pseudo-terminal).
451  *
452  * In the non-block form, returns a two element array, <tt>[master_io,
453  * slave_file]</tt>.
454  *
455  * In the block form, yields two arguments <tt>master_io, slave_file</tt>
456  * and the value of the block is returned from +open+.
457  *
458  * The IO and File are both closed after the block completes if they haven't
459  * been already closed.
460  *
461  * The arguments in both forms are:
462  *
463  * <tt>master_io</tt>:: the master of the pty, as an IO.
464  * <tt>slave_file</tt>:: the slave of the pty, as a File. The path to the
465  * terminal device is available via
466  * <tt>slave_file.path</tt>
467  *
468  * === Example
469  *
470  * PTY.open {|m, s|
471  * p m #=> #<IO:masterpty:/dev/pts/1>
472  * p s #=> #<File:/dev/pts/1>
473  * p s.path #=> "/dev/pts/1"
474  * }
475  *
476  * # Change the buffering type in factor command,
477  * # assuming that factor uses stdio for stdout buffering.
478  * # If IO.pipe is used instead of PTY.open,
479  * # this code deadlocks because factor's stdout is fully buffered.
480  * require 'io/console' # for IO#raw!
481  * m, s = PTY.open
482  * s.raw! # disable newline conversion.
483  * r, w = IO.pipe
484  * pid = spawn("factor", :in=>r, :out=>s)
485  * r.close
486  * s.close
487  * w.puts "42"
488  * p m.gets #=> "42: 2 3 7\n"
489  * w.puts "144"
490  * p m.gets #=> "144: 2 2 2 2 3 3\n"
491  * w.close
492  * # The result of read operation when pty slave is closed is platform
493  * # dependent.
494  * ret = begin
495  * m.gets # FreeBSD returns nil.
496  * rescue Errno::EIO # GNU/Linux raises EIO.
497  * nil
498  * end
499  * p ret #=> nil
500  *
501  */
502 static VALUE
504 {
505  int master_fd, slave_fd;
506  char slavename[DEVICELEN];
507  VALUE master_io, slave_file;
508  rb_io_t *master_fptr, *slave_fptr;
509  VALUE assoc;
510 
511  getDevice(&master_fd, &slave_fd, slavename, 1);
512 
513  master_io = rb_obj_alloc(rb_cIO);
514  MakeOpenFile(master_io, master_fptr);
515  master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
516  master_fptr->fd = master_fd;
517  master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
518 
519  slave_file = rb_obj_alloc(rb_cFile);
520  MakeOpenFile(slave_file, slave_fptr);
522  slave_fptr->fd = slave_fd;
523  slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
524 
525  assoc = rb_assoc_new(master_io, slave_file);
526  if (rb_block_given_p()) {
527  return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
528  }
529  return assoc;
530 }
531 
532 static VALUE
534 {
536  return Qnil;
537 }
538 
539 /*
540  * call-seq:
541  * PTY.spawn(command_line) { |r, w, pid| ... }
542  * PTY.spawn(command_line) => [r, w, pid]
543  * PTY.spawn(command, args, ...) { |r, w, pid| ... }
544  * PTY.spawn(command, args, ...) => [r, w, pid]
545  * PTY.getpty(command_line) { |r, w, pid| ... }
546  * PTY.getpty(command_line) => [r, w, pid]
547  * PTY.getpty(command, args, ...) { |r, w, pid| ... }
548  * PTY.getpty(command, args, ...) => [r, w, pid]
549  *
550  * Spawns the specified command on a newly allocated pty.
551  *
552  * The command's controlling tty is set to the slave device of the pty
553  * and its standard input/output/error is redirected to the slave device.
554  *
555  * <tt>command_line</tt>:: The full command line to run
556  * <tt>command</tt>:: The command to run, as a String.
557  * <tt>args</tt>:: Zero or more arguments, as Strings, representing
558  * the arguments to +command+
559  *
560  * In the non-block form this returns an array of size three,
561  * <tt>[r, w, pid]</tt>. In the block form the block will be called with
562  * these as arguments, <tt>|r,w,pid|</tt>:
563  *
564  * +r+:: An IO that can be read from that contains the command's
565  * standard output and standard error
566  * +w+:: An IO that can be written to that is the command's
567  * standard input
568  * +pid+:: The process identifier for the command.
569  */
570 static VALUE
572 {
573  VALUE res;
574  struct pty_info info;
575  rb_io_t *wfptr,*rfptr;
576  VALUE rport = rb_obj_alloc(rb_cFile);
577  VALUE wport = rb_obj_alloc(rb_cFile);
578  char SlaveName[DEVICELEN];
579 
580  MakeOpenFile(rport, rfptr);
581  MakeOpenFile(wport, wfptr);
582 
583  establishShell(argc, argv, &info, SlaveName);
584 
585  rfptr->mode = rb_io_mode_flags("r");
586  rfptr->fd = info.fd;
587  rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
588 
589  wfptr->mode = rb_io_mode_flags("w") | FMODE_SYNC;
590  wfptr->fd = dup(info.fd);
591  if (wfptr->fd == -1)
592  rb_sys_fail("dup()");
593  rb_update_max_fd(wfptr->fd);
594  wfptr->pathv = rfptr->pathv;
595 
596  res = rb_ary_new2(3);
597  rb_ary_store(res,0,(VALUE)rport);
598  rb_ary_store(res,1,(VALUE)wport);
599  rb_ary_store(res,2,PIDT2NUM(info.child_pid));
600 
601  if (rb_block_given_p()) {
603  return Qnil;
604  }
605  return res;
606 }
607 
608 static void
609 raise_from_check(pid_t pid, int status)
610 {
611  const char *state;
612  char buf[1024];
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  snprintf(buf, sizeof(buf), "pty - %s: %ld", state, (long)pid);
631  exc = rb_exc_new2(eChildExited, buf);
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. If the process
643  * is not alive, will return a <tt>Process::Status</tt> or raise
644  * a <tt>PTY::ChildExited</tt> (if +raise+ was true).
645  *
646  * +pid+:: The process id of the process to check
647  * +raise+:: If true and the process identified by +pid+ is no longer
648  * alive a <tt>PTY::ChildExited</tt> is raised.
649  *
650  * Returns nil or a <tt>Process::Status</tt> when +raise+ is false.
651  */
652 static VALUE
654 {
655  VALUE pid, exc;
656  pid_t cpid;
657  int status;
658 
659  rb_scan_args(argc, argv, "11", &pid, &exc);
660  cpid = rb_waitpid(NUM2PIDT(pid), &status, WNOHANG|WUNTRACED);
661  if (cpid == -1 || cpid == 0) return Qnil;
662 
663  if (!RTEST(exc)) return rb_last_status_get();
664  raise_from_check(cpid, status);
665  return Qnil; /* not reached */
666 }
667 
668 static VALUE cPTY;
669 
670 /*
671  * Document-class: PTY::ChildExited
672  *
673  * Thrown when PTY#check is called for a pid that represents a process that
674  * has exited.
675  */
676 
677 /*
678  * Document-class: PTY
679  *
680  * Creates and managed pseudo terminals (PTYs). See also
681  * http://en.wikipedia.org/wiki/Pseudo_terminal
682  */
683 
684 void
686 {
687  cPTY = rb_define_module("PTY");
692 
695 }
static const char *const deviceNo[]
Definition: pty.c:97
void rb_gc(void)
Definition: gc.c:3153
#define WNOHANG
Definition: win32.h:117
int slave
Definition: pty.c:142
void rb_thread_atfork_before_exec(void)
Definition: thread.c:3145
int fd
Definition: pty.c:135
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:956
VALUE rb_detach_process(rb_pid_t pid)
Definition: process.c:915
int ioctl(int, int,...)
Definition: win32.c:2319
#define FMODE_READWRITE
Definition: io.h:95
void rb_update_max_fd(int fd)
Definition: io.c:156
int i
Definition: win32ole.c:776
#define WIFSTOPPED(status)
Definition: pty.c:28
rb_uid_t getuid(void)
Definition: win32.c:2279
void rb_define_singleton_method(VALUE obj, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a singleton method for obj.
Definition: class.c:1342
static VALUE pty_check(int argc, VALUE *argv, VALUE self)
Definition: pty.c:653
#define NUM2PIDT(v)
Definition: ruby.h:315
int master
Definition: pty.c:142
#define PIDT2NUM(v)
Definition: ruby.h:312
static VALUE pty_close_pty(VALUE assoc)
Definition: pty.c:432
Definition: io.h:53
int argc
Definition: pty.c:144
VALUE rb_cFile
Definition: file.c:131
int kill(int, int)
Definition: win32.c:3808
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:514
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1574
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1026
static int get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
Definition: pty.c:282
#define FMODE_DUPLEX
Definition: io.h:99
static VALUE pty_open(VALUE klass)
Definition: pty.c:503
Definition: pty.c:134
#define RFILE(obj)
Definition: ruby.h:917
static void establishShell(int argc, VALUE *argv, struct pty_info *info, char SlaveName[DEVICELEN])
Definition: pty.c:219
static void getDevice(int *, int *, char[DEVICELEN], int)
Definition: pty.c:423
int mode
Definition: io.h:56
Win32OLEIDispatch * p
Definition: win32ole.c:778
void rb_exc_raise(VALUE mesg)
Definition: eval.c:460
static VALUE eChildExited
Definition: pty.c:123
#define fail()
int rb_block_given_p(void)
Definition: eval.c:604
VALUE rb_eRuntimeError
Definition: error.c:466
#define snprintf
Definition: subst.h:6
int chown(const char *, int, int)
Definition: win32.c:3796
static int no_mesg(char *slavedevice, int nomesg)
Definition: pty.c:273
int fd
Definition: io.h:54
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:635
static const char MasterDevice[]
Definition: pty.c:95
#define TYPE(x)
Definition: ruby.h:441
int argc
Definition: ruby.c:120
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1600
VALUE * argv
Definition: pty.c:145
static const char SlaveDevice[]
Definition: pty.c:96
rb_pid_t rb_fork_err(int *, int(*)(void *, char *, size_t), void *, VALUE, char *, size_t)
RUBY_EXTERN VALUE rb_cIO
Definition: ruby.h:1262
void rb_define_module_function(VALUE module, const char *name, VALUE(*func)(ANYARGS), int argc)
Defines a module function for module.
Definition: class.c:1357
VALUE rb_yield(VALUE)
Definition: vm_eval.c:781
int errno
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1203
static int chfunc(void *data, char *errbuf, size_t errbuf_len)
Definition: pty.c:149
static VALUE cPTY
Definition: pty.c:668
void Init_pty()
Definition: pty.c:685
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2228
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1415
rb_pid_t child_pid
Definition: pty.c:136
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:3913
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:460
#define NULL
#define Qnil
Definition: ruby.h:367
VALUE rb_exc_new2(VALUE etype, const char *s)
Definition: error.c:498
static void raise_from_check(pid_t pid, int status)
Definition: pty.c:609
VALUE rb_f_exec(int, VALUE *)
Definition: process.c:1898
#define mode_t
Definition: win32.h:102
VALUE rb_io_close(VALUE)
Definition: io.c:3878
unsigned long VALUE
Definition: ruby.h:88
char * getenv()
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:737
VALUE rb_str_new_cstr(const char *)
Definition: string.c:432
#define rb_io_mode_flags(modestr)
Definition: io.h:181
void rb_sys_fail(const char *mesg)
Definition: error.c:1671
char * slavename
Definition: pty.c:143
static VALUE pty_getpty(int argc, VALUE *argv, VALUE self)
Definition: pty.c:571
sighandler_t signal(int signum, sighandler_t handler)
VALUE pathv
Definition: io.h:59
#define RTEST(v)
Definition: ruby.h:373
#define ERROR_EXIT(str)
v
Definition: win32ole.c:790
#define T_FILE
Definition: ruby.h:424
#define DEVICELEN
Definition: pty.c:45
VALUE rb_ary_new2(long capa)
Definition: array.c:332
const char * name
Definition: nkf.c:208
static VALUE echild_status(VALUE self)
Definition: pty.c:129
#define FMODE_SYNC
Definition: io.h:97
#define FMODE_TTY
Definition: io.h:98
#define MakeOpenFile(obj, fp)
Definition: io.h:119
RUBY_EXTERN int dup2(int, int)
Definition: dup2.c:27
static VALUE pty_detach_process(struct pty_info *info)
Definition: pty.c:533
rb_gid_t getgid(void)
Definition: win32.c:2291
VALUE rb_obj_freeze(VALUE)
Definition: object.c:902
state
Definition: gb18030.c:213
VALUE rb_define_module(const char *name)
Definition: class.c:586
#define rb_intern(str)
VALUE rb_last_status_get(void)
Definition: process.c:208
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Definition: process.c:645
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1209
VALUE rb_str_new2(const char *)
char ** argv
Definition: ruby.c:121