• Main Page
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

ext/pty/pty.c

Go to the documentation of this file.
00001 #include        "ruby/config.h"
00002 #ifdef RUBY_EXTCONF_H
00003 #include RUBY_EXTCONF_H
00004 #endif
00005 #include        <stdlib.h>
00006 #include        <stdio.h>
00007 #include        <sys/types.h>
00008 #include        <sys/stat.h>
00009 #include        <sys/file.h>
00010 #include        <fcntl.h>
00011 #include        <errno.h>
00012 #include        <pwd.h>
00013 #ifdef HAVE_SYS_IOCTL_H
00014 #include        <sys/ioctl.h>
00015 #endif
00016 #ifdef HAVE_LIBUTIL_H
00017 #include        <libutil.h>
00018 #endif
00019 #ifdef HAVE_UTIL_H
00020 #include        <util.h>
00021 #endif
00022 #ifdef HAVE_PTY_H
00023 #include        <pty.h>
00024 #endif
00025 #ifdef HAVE_SYS_WAIT_H
00026 #include <sys/wait.h>
00027 #else
00028 #define WIFSTOPPED(status)    (((status) & 0xff) == 0x7f)
00029 #endif
00030 #include <ctype.h>
00031 
00032 #include "ruby/ruby.h"
00033 #include "ruby/io.h"
00034 #include "ruby/util.h"
00035 
00036 #include <signal.h>
00037 #ifdef HAVE_SYS_STROPTS_H
00038 #include <sys/stropts.h>
00039 #endif
00040 
00041 #ifdef HAVE_UNISTD_H
00042 #include <unistd.h>
00043 #endif
00044 
00045 #define DEVICELEN       16
00046 
00047 #if !defined(HAVE_OPENPTY)
00048 #if defined(__hpux)
00049 static const
00050 char    MasterDevice[] = "/dev/ptym/pty%s",
00051         SlaveDevice[] =  "/dev/pty/tty%s",
00052         *const deviceNo[] = {
00053                 "p0","p1","p2","p3","p4","p5","p6","p7",
00054                 "p8","p9","pa","pb","pc","pd","pe","pf",
00055                 "q0","q1","q2","q3","q4","q5","q6","q7",
00056                 "q8","q9","qa","qb","qc","qd","qe","qf",
00057                 "r0","r1","r2","r3","r4","r5","r6","r7",
00058                 "r8","r9","ra","rb","rc","rd","re","rf",
00059                 "s0","s1","s2","s3","s4","s5","s6","s7",
00060                 "s8","s9","sa","sb","sc","sd","se","sf",
00061                 "t0","t1","t2","t3","t4","t5","t6","t7",
00062                 "t8","t9","ta","tb","tc","td","te","tf",
00063                 "u0","u1","u2","u3","u4","u5","u6","u7",
00064                 "u8","u9","ua","ub","uc","ud","ue","uf",
00065                 "v0","v1","v2","v3","v4","v5","v6","v7",
00066                 "v8","v9","va","vb","vc","vd","ve","vf",
00067                 "w0","w1","w2","w3","w4","w5","w6","w7",
00068                 "w8","w9","wa","wb","wc","wd","we","wf",
00069                 0,
00070         };
00071 #elif defined(_IBMESA)  /* AIX/ESA */
00072 static const
00073 char    MasterDevice[] = "/dev/ptyp%s",
00074         SlaveDevice[] = "/dev/ttyp%s",
00075         *const deviceNo[] = {
00076 "00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f",
00077 "10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f",
00078 "20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f",
00079 "30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f",
00080 "40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f",
00081 "50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f",
00082 "60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f",
00083 "70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f",
00084 "80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f",
00085 "90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f",
00086 "a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af",
00087 "b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf",
00088 "c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf",
00089 "d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df",
00090 "e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef",
00091 "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff",
00092                 };
00093 #elif !defined(HAVE_PTSNAME)
00094 static const
00095 char    MasterDevice[] = "/dev/pty%s",
00096         SlaveDevice[] = "/dev/tty%s",
00097         *const deviceNo[] = {
00098                 "p0","p1","p2","p3","p4","p5","p6","p7",
00099                 "p8","p9","pa","pb","pc","pd","pe","pf",
00100                 "q0","q1","q2","q3","q4","q5","q6","q7",
00101                 "q8","q9","qa","qb","qc","qd","qe","qf",
00102                 "r0","r1","r2","r3","r4","r5","r6","r7",
00103                 "r8","r9","ra","rb","rc","rd","re","rf",
00104                 "s0","s1","s2","s3","s4","s5","s6","s7",
00105                 "s8","s9","sa","sb","sc","sd","se","sf",
00106                 0,
00107         };
00108 #endif
00109 #endif /* !defined(HAVE_OPENPTY) */
00110 
00111 #ifndef HAVE_SETEUID
00112 # ifdef HAVE_SETREUID
00113 #  define seteuid(e)    setreuid(-1, (e))
00114 # else /* NOT HAVE_SETREUID */
00115 #  ifdef HAVE_SETRESUID
00116 #   define seteuid(e)   setresuid(-1, (e), -1)
00117 #  else /* NOT HAVE_SETRESUID */
00118     /* I can't set euid. (;_;) */
00119 #  endif /* HAVE_SETRESUID */
00120 # endif /* HAVE_SETREUID */
00121 #endif /* NO_SETEUID */
00122 
00123 static VALUE eChildExited;
00124 
00125 static VALUE
00126 echild_status(VALUE self)
00127 {
00128     return rb_ivar_get(self, rb_intern("status"));
00129 }
00130 
00131 struct pty_info {
00132     int fd;
00133     rb_pid_t child_pid;
00134 };
00135 
00136 static void getDevice(int*, int*, char [DEVICELEN], int);
00137 
00138 struct exec_info {
00139     int argc;
00140     VALUE *argv;
00141 };
00142 
00143 static VALUE
00144 pty_exec(VALUE v)
00145 {
00146     struct exec_info *arg = (struct exec_info *)v;
00147     return rb_f_exec(arg->argc, arg->argv);
00148 }
00149 
00150 struct child_info {
00151     int master, slave;
00152     char *slavename;
00153     int argc;
00154     VALUE *argv;
00155 };
00156 
00157 static int
00158 chfunc(void *data)
00159 {
00160     struct child_info *carg = data;
00161     int master = carg->master;
00162     int slave = carg->slave;
00163     int argc = carg->argc;
00164     VALUE *argv = carg->argv;
00165 
00166     struct exec_info arg;
00167     int status;
00168 
00169     /*
00170      * Set free from process group and controlling terminal
00171      */
00172 #ifdef HAVE_SETSID
00173     (void) setsid();
00174 #else /* HAS_SETSID */
00175 # ifdef HAVE_SETPGRP
00176 #  ifdef SETGRP_VOID
00177     if (setpgrp() == -1)
00178         perror("setpgrp()");
00179 #  else /* SETGRP_VOID */
00180     if (setpgrp(0, getpid()) == -1)
00181         rb_sys_fail("setpgrp()");
00182     {
00183         int i = open("/dev/tty", O_RDONLY);
00184         if (i < 0) rb_sys_fail("/dev/tty");
00185         if (ioctl(i, TIOCNOTTY, (char *)0))
00186             perror("ioctl(TIOCNOTTY)");
00187         close(i);
00188     }
00189 #  endif /* SETGRP_VOID */
00190 # endif /* HAVE_SETPGRP */
00191 #endif /* HAS_SETSID */
00192 
00193     /*
00194      * obtain new controlling terminal
00195      */
00196 #if defined(TIOCSCTTY)
00197     close(master);
00198     (void) ioctl(slave, TIOCSCTTY, (char *)0);
00199     /* errors ignored for sun */
00200 #else
00201     close(slave);
00202     slave = open(carg->slavename, O_RDWR);
00203     if (slave < 0) {
00204         perror("open: pty slave");
00205         _exit(1);
00206     }
00207     close(master);
00208 #endif
00209     write(slave, "", 1);
00210     dup2(slave,0);
00211     dup2(slave,1);
00212     dup2(slave,2);
00213     close(slave);
00214 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
00215     seteuid(getuid());
00216 #endif
00217 
00218     arg.argc = argc;
00219     arg.argv = argv;
00220     rb_protect(pty_exec, (VALUE)&arg, &status);
00221     sleep(1);
00222     _exit(1);
00223 }
00224 
00225 static void
00226 establishShell(int argc, VALUE *argv, struct pty_info *info,
00227                char SlaveName[DEVICELEN])
00228 {
00229     int                 master,slave;
00230     rb_pid_t            pid;
00231     char                *p, tmp, *getenv();
00232     struct passwd       *pwent;
00233     VALUE               v;
00234     struct child_info   carg;
00235 
00236     if (argc == 0) {
00237         const char *shellname;
00238 
00239         if ((p = getenv("SHELL")) != NULL) {
00240             shellname = p;
00241         }
00242         else {
00243             pwent = getpwuid(getuid());
00244             if (pwent && pwent->pw_shell)
00245                 shellname = pwent->pw_shell;
00246             else
00247                 shellname = "/bin/sh";
00248         }
00249         v = rb_str_new2(shellname);
00250         argc = 1;
00251         argv = &v;
00252     }
00253 
00254     getDevice(&master, &slave, SlaveName, 0);
00255 
00256     carg.master = master;
00257     carg.slave = slave;
00258     carg.slavename = SlaveName;
00259     carg.argc = argc;
00260     carg.argv = argv;
00261     pid = rb_fork(0, chfunc, &carg, Qnil);
00262 
00263     if (pid < 0) {
00264         close(master);
00265         close(slave);
00266         rb_sys_fail("fork failed");
00267     }
00268 
00269     read(master, &tmp, 1);
00270     close(slave);
00271 
00272     info->child_pid = pid;
00273     info->fd = master;
00274 }
00275 
00276 static int
00277 no_mesg(char *slavedevice, int nomesg)
00278 {
00279     if (nomesg)
00280         return chmod(slavedevice, 0600);
00281     else
00282         return 0;
00283 }
00284 
00285 static int
00286 get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
00287 {
00288 #if defined(HAVE_POSIX_OPENPT)
00289     int masterfd = -1, slavefd = -1;
00290     char *slavedevice;
00291     struct sigaction dfl, old;
00292 
00293     dfl.sa_handler = SIG_DFL;
00294     dfl.sa_flags = 0;
00295     sigemptyset(&dfl.sa_mask);
00296 
00297     if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
00298     if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
00299     if (grantpt(masterfd) == -1) goto grantpt_error;
00300     if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
00301     if (unlockpt(masterfd) == -1) goto error;
00302     if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
00303     if (no_mesg(slavedevice, nomesg) == -1) goto error;
00304     if ((slavefd = open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
00305 
00306 #if defined I_PUSH && !defined linux
00307     if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
00308     if (ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
00309     if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) goto error;
00310 #endif
00311 
00312     *master = masterfd;
00313     *slave = slavefd;
00314     strlcpy(SlaveName, slavedevice, DEVICELEN);
00315     return 0;
00316 
00317   grantpt_error:
00318     sigaction(SIGCHLD, &old, NULL);
00319   error:
00320     if (slavefd != -1) close(slavefd);
00321     if (masterfd != -1) close(masterfd);
00322     if (fail) {
00323         rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
00324     }
00325     return -1;
00326 #elif defined HAVE_OPENPTY
00327 /*
00328  * Use openpty(3) of 4.3BSD Reno and later,
00329  * or the same interface function.
00330  */
00331     if (openpty(master, slave, SlaveName,
00332                 (struct termios *)0, (struct winsize *)0) == -1) {
00333         if (!fail) return -1;
00334         rb_raise(rb_eRuntimeError, "openpty() failed");
00335     }
00336     if (no_mesg(SlaveName, nomesg) == -1) {
00337         if (!fail) return -1;
00338         rb_raise(rb_eRuntimeError, "can't chmod slave pty");
00339     }
00340 
00341     return 0;
00342 
00343 #elif defined HAVE__GETPTY
00344     char *name;
00345     mode_t mode = nomesg ? 0600 : 0622;
00346 
00347     if (!(name = _getpty(master, O_RDWR, mode, 0))) {
00348         if (!fail) return -1;
00349         rb_raise(rb_eRuntimeError, "_getpty() failed");
00350     }
00351 
00352     *slave = open(name, O_RDWR);
00353     strlcpy(SlaveName, name, DEVICELEN);
00354 
00355     return 0;
00356 #elif defined(HAVE_PTSNAME)
00357     int  masterfd = -1, slavefd = -1;
00358     char *slavedevice;
00359     void (*s)();
00360 
00361     extern char *ptsname(int);
00362     extern int unlockpt(int);
00363     extern int grantpt(int);
00364 
00365     if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
00366     s = signal(SIGCHLD, SIG_DFL);
00367     if(grantpt(masterfd) == -1) goto error;
00368     signal(SIGCHLD, s);
00369     if(unlockpt(masterfd) == -1) goto error;
00370     if((slavedevice = ptsname(masterfd)) == NULL) goto error;
00371     if (no_mesg(slavedevice, nomesg) == -1) goto error;
00372     if((slavefd = open(slavedevice, O_RDWR, 0)) == -1) goto error;
00373 #if defined I_PUSH && !defined linux
00374     if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
00375     if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
00376     ioctl(slavefd, I_PUSH, "ttcompat");
00377 #endif
00378     *master = masterfd;
00379     *slave = slavefd;
00380     strlcpy(SlaveName, slavedevice, DEVICELEN);
00381     return 0;
00382 
00383   error:
00384     if (slavefd != -1) close(slavefd);
00385     if (masterfd != -1) close(masterfd);
00386     if (fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
00387     return -1;
00388 #else
00389     int  masterfd = -1, slavefd = -1;
00390     const char *const *p;
00391     char MasterName[DEVICELEN];
00392 
00393     for (p = deviceNo; *p != NULL; p++) {
00394         snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
00395         if ((masterfd = open(MasterName,O_RDWR,0)) >= 0) {
00396             *master = masterfd;
00397             snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
00398             if ((slavefd = open(SlaveName,O_RDWR,0)) >= 0) {
00399                 *slave = slavefd;
00400                 if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
00401                 if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
00402                 return 0;
00403             }
00404             close(masterfd);
00405         }
00406     }
00407   error:
00408     if (slavefd != -1) close(slavefd);
00409     if (masterfd != -1) close(masterfd);
00410     if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName);
00411     return -1;
00412 #endif
00413 }
00414 
00415 static void
00416 getDevice(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg)
00417 {
00418     if (get_device_once(master, slave, SlaveName, nomesg, 0)) {
00419         rb_gc();
00420         get_device_once(master, slave, SlaveName, nomesg, 1);
00421     }
00422 }
00423 
00424 static VALUE
00425 pty_close_pty(VALUE assoc)
00426 {
00427     VALUE io;
00428     int i;
00429 
00430     for (i = 0; i < 2; i++) {
00431         io = rb_ary_entry(assoc, i);
00432         if (TYPE(io) == T_FILE && 0 <= RFILE(io)->fptr->fd)
00433             rb_io_close(io);
00434     }
00435     return Qnil;
00436 }
00437 
00438 /*
00439  * call-seq:
00440  *   PTY.open   => [master_io, slave_file]
00441  *   PTY.open {|master_io, slave_file| ... }    => block value
00442  *
00443  * Allocates a pty (pseudo-terminal).
00444  *
00445  * It returns an array which contains an IO object and a File object.
00446  * The former is the master of the pty.
00447  * The latter is the slave of the pty.
00448  *
00449  * If a block is given, it yields the array instead of return.
00450  * The value of the block is returned.
00451  * master_io and slave_file is closed when return if they are not closed.
00452  *
00453  * The path name of the terminal device can be gotten by slave_file.path.
00454  *
00455  *   PTY.open {|m, s|
00456  *     p m      #=> #<IO:masterpty:/dev/pts/1>
00457  *     p s      #=> #<File:/dev/pts/1>
00458  *     p s.path #=> "/dev/pts/1"
00459  *   }
00460  *
00461  *   # Change the buffering type in factor command,
00462  *   # assuming that factor uses stdio for stdout buffering.
00463  *   # If IO.pipe is used instead of PTY.open,
00464  *   # this code deadlocks because factor's stdout is fully buffered.
00465  *   m, s = PTY.open
00466  *   system("stty raw", :in=>s) # disable newline conversion.
00467  *   r, w = IO.pipe
00468  *   pid = spawn("factor", :in=>r, :out=>s)
00469  *   r.close
00470  *   s.close
00471  *   w.puts "42"
00472  *   p m.gets #=> "42: 2 3 7\n"
00473  *   w.puts "144"
00474  *   p m.gets #=> "144: 2 2 2 2 3 3\n"
00475  *   w.close
00476  *   # The result of read operation when pty slave is closed is platform dependnet.
00477  *   ret = begin
00478  *           m.gets          # FreeBSD returns nil.
00479  *         rescue Errno::EIO # GNU/Linux raises EIO.
00480  *           nil
00481  *         end
00482  *   p ret #=> nil
00483  *
00484  */
00485 static VALUE
00486 pty_open(VALUE klass)
00487 {
00488     int master_fd, slave_fd;
00489     char slavename[DEVICELEN];
00490     VALUE master_io, slave_file;
00491     rb_io_t *master_fptr, *slave_fptr;
00492     VALUE assoc;
00493 
00494     getDevice(&master_fd, &slave_fd, slavename, 1);
00495 
00496     master_io = rb_obj_alloc(rb_cIO);
00497     MakeOpenFile(master_io, master_fptr);
00498     master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
00499     master_fptr->fd = master_fd;
00500     master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
00501 
00502     slave_file = rb_obj_alloc(rb_cFile);
00503     MakeOpenFile(slave_file, slave_fptr);
00504     slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
00505     slave_fptr->fd = slave_fd;
00506     slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
00507 
00508     assoc = rb_assoc_new(master_io, slave_file);
00509     if (rb_block_given_p()) {
00510         return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
00511     }
00512     return assoc;
00513 }
00514 
00515 static VALUE
00516 pty_detach_process(struct pty_info *info)
00517 {
00518     rb_detach_process(info->child_pid);
00519     return Qnil;
00520 }
00521 
00522 /*
00523  * call-seq:
00524  *   PTY.spawn(command...) {|r, w, pid| ... }   => nil
00525  *   PTY.spawn(command...)                      => r, w, pid
00526  *   PTY.getpty(command...) {|r, w, pid| ... }  => nil
00527  *   PTY.getpty(command...)                     => r, w, pid
00528  *
00529  * spawns the specified command on a newly allocated pty.
00530  *
00531  * The command's controlling tty is set to the slave device of the pty.
00532  * Also its standard input/output/error is redirected to the slave device.
00533  *
00534  * PTY.spawn returns two IO objects and PID.
00535  * PID is the process ID of the command.
00536  * The two IO objects are connected to the master device of the pty.
00537  * The first IO object is opened as read mode and
00538  * The second is opened as write mode.
00539  *
00540  * If a block is given, two IO objects and PID is yielded.
00541  *
00542  */
00543 static VALUE
00544 pty_getpty(int argc, VALUE *argv, VALUE self)
00545 {
00546     VALUE res;
00547     struct pty_info info;
00548     rb_io_t *wfptr,*rfptr;
00549     VALUE rport = rb_obj_alloc(rb_cFile);
00550     VALUE wport = rb_obj_alloc(rb_cFile);
00551     char SlaveName[DEVICELEN];
00552 
00553     MakeOpenFile(rport, rfptr);
00554     MakeOpenFile(wport, wfptr);
00555 
00556     establishShell(argc, argv, &info, SlaveName);
00557 
00558     rfptr->mode = rb_io_mode_flags("r");
00559     rfptr->fd = info.fd;
00560     rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
00561 
00562     wfptr->mode = rb_io_mode_flags("w") | FMODE_SYNC;
00563     wfptr->fd = dup(info.fd);
00564     if (wfptr->fd == -1)
00565         rb_sys_fail("dup()");
00566     wfptr->pathv = rfptr->pathv;
00567 
00568     res = rb_ary_new2(3);
00569     rb_ary_store(res,0,(VALUE)rport);
00570     rb_ary_store(res,1,(VALUE)wport);
00571     rb_ary_store(res,2,PIDT2NUM(info.child_pid));
00572 
00573     if (rb_block_given_p()) {
00574         rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
00575         return Qnil;
00576     }
00577     return res;
00578 }
00579 
00580 static void
00581 raise_from_check(pid_t pid, int status)
00582 {
00583     const char *state;
00584     char buf[1024];
00585     VALUE exc;
00586 
00587 #if defined(WIFSTOPPED)
00588 #elif defined(IF_STOPPED)
00589 #define WIFSTOPPED(status) IF_STOPPED(status)
00590 #else
00591 ---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
00592 #endif /* WIFSTOPPED | IF_STOPPED */
00593     if (WIFSTOPPED(status)) { /* suspend */
00594         state = "stopped";
00595     }
00596     else if (kill(pid, 0) == 0) {
00597         state = "changed";
00598     }
00599     else {
00600         state = "exited";
00601     }
00602     snprintf(buf, sizeof(buf), "pty - %s: %ld", state, (long)pid);
00603     exc = rb_exc_new2(eChildExited, buf);
00604     rb_iv_set(exc, "status", rb_last_status_get());
00605     rb_exc_raise(exc);
00606 }
00607 
00608 /*
00609  * call-seq:
00610  *   PTY.check(pid[, raise=false])   => Process::Status or nil
00611  *
00612  * checks the status of the child process specified by _pid_, and
00613  * returns +nil+ if the process is still alive and active.  Otherwise,
00614  * returns +Process::Status+ about the process if _raise_ is false, or
00615  * +PTY::ChildExited+ exception is raised.
00616  */
00617 static VALUE
00618 pty_check(int argc, VALUE *argv, VALUE self)
00619 {
00620     VALUE pid, exc;
00621     pid_t cpid;
00622     int status;
00623 
00624     rb_scan_args(argc, argv, "11", &pid, &exc);
00625     cpid = rb_waitpid(NUM2PIDT(pid), &status, WNOHANG|WUNTRACED);
00626     if (cpid == -1) return Qnil;
00627 
00628     if (!RTEST(exc)) return rb_last_status_get();
00629     raise_from_check(cpid, status);
00630     return Qnil;                /* not reached */
00631 }
00632 
00633 static VALUE cPTY;
00634 
00635 void
00636 Init_pty()
00637 {
00638     cPTY = rb_define_module("PTY");
00639     rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
00640     rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
00641     rb_define_singleton_method(cPTY,"check",pty_check,-1);
00642     rb_define_singleton_method(cPTY,"open",pty_open,0);
00643 
00644     eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
00645     rb_define_method(eChildExited,"status",echild_status,0);
00646 }
00647 

Generated on Wed Sep 8 2010 21:54:16 for Ruby by  doxygen 1.7.1