|
Ruby 1.9.2p290(2011-07-09revision32553)
|
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 rb_thread_atfork_before_exec(); 00170 00171 /* 00172 * Set free from process group and controlling terminal 00173 */ 00174 #ifdef HAVE_SETSID 00175 (void) setsid(); 00176 #else /* HAS_SETSID */ 00177 # ifdef HAVE_SETPGRP 00178 # ifdef SETGRP_VOID 00179 if (setpgrp() == -1) 00180 perror("setpgrp()"); 00181 # else /* SETGRP_VOID */ 00182 if (setpgrp(0, getpid()) == -1) 00183 rb_sys_fail("setpgrp()"); 00184 { 00185 int i = open("/dev/tty", O_RDONLY); 00186 if (i < 0) rb_sys_fail("/dev/tty"); 00187 if (ioctl(i, TIOCNOTTY, (char *)0)) 00188 perror("ioctl(TIOCNOTTY)"); 00189 close(i); 00190 } 00191 # endif /* SETGRP_VOID */ 00192 # endif /* HAVE_SETPGRP */ 00193 #endif /* HAS_SETSID */ 00194 00195 /* 00196 * obtain new controlling terminal 00197 */ 00198 #if defined(TIOCSCTTY) 00199 close(master); 00200 (void) ioctl(slave, TIOCSCTTY, (char *)0); 00201 /* errors ignored for sun */ 00202 #else 00203 close(slave); 00204 slave = open(carg->slavename, O_RDWR); 00205 if (slave < 0) { 00206 perror("open: pty slave"); 00207 _exit(1); 00208 } 00209 close(master); 00210 #endif 00211 write(slave, "", 1); 00212 dup2(slave,0); 00213 dup2(slave,1); 00214 dup2(slave,2); 00215 close(slave); 00216 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID) 00217 seteuid(getuid()); 00218 #endif 00219 00220 arg.argc = argc; 00221 arg.argv = argv; 00222 rb_protect(pty_exec, (VALUE)&arg, &status); 00223 sleep(1); 00224 _exit(1); 00225 } 00226 00227 static void 00228 establishShell(int argc, VALUE *argv, struct pty_info *info, 00229 char SlaveName[DEVICELEN]) 00230 { 00231 int master,slave; 00232 rb_pid_t pid; 00233 char *p, tmp, *getenv(); 00234 struct passwd *pwent; 00235 VALUE v; 00236 struct child_info carg; 00237 00238 if (argc == 0) { 00239 const char *shellname; 00240 00241 if ((p = getenv("SHELL")) != NULL) { 00242 shellname = p; 00243 } 00244 else { 00245 pwent = getpwuid(getuid()); 00246 if (pwent && pwent->pw_shell) 00247 shellname = pwent->pw_shell; 00248 else 00249 shellname = "/bin/sh"; 00250 } 00251 v = rb_str_new2(shellname); 00252 argc = 1; 00253 argv = &v; 00254 } 00255 00256 getDevice(&master, &slave, SlaveName, 0); 00257 00258 carg.master = master; 00259 carg.slave = slave; 00260 carg.slavename = SlaveName; 00261 carg.argc = argc; 00262 carg.argv = argv; 00263 pid = rb_fork(0, chfunc, &carg, Qnil); 00264 00265 if (pid < 0) { 00266 close(master); 00267 close(slave); 00268 rb_sys_fail("fork failed"); 00269 } 00270 00271 read(master, &tmp, 1); 00272 close(slave); 00273 00274 info->child_pid = pid; 00275 info->fd = master; 00276 } 00277 00278 static int 00279 no_mesg(char *slavedevice, int nomesg) 00280 { 00281 if (nomesg) 00282 return chmod(slavedevice, 0600); 00283 else 00284 return 0; 00285 } 00286 00287 static int 00288 get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail) 00289 { 00290 #if defined(HAVE_POSIX_OPENPT) 00291 int masterfd = -1, slavefd = -1; 00292 char *slavedevice; 00293 struct sigaction dfl, old; 00294 00295 dfl.sa_handler = SIG_DFL; 00296 dfl.sa_flags = 0; 00297 sigemptyset(&dfl.sa_mask); 00298 00299 if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error; 00300 if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error; 00301 if (grantpt(masterfd) == -1) goto grantpt_error; 00302 if (sigaction(SIGCHLD, &old, NULL) == -1) goto error; 00303 if (unlockpt(masterfd) == -1) goto error; 00304 if ((slavedevice = ptsname(masterfd)) == NULL) goto error; 00305 if (no_mesg(slavedevice, nomesg) == -1) goto error; 00306 if ((slavefd = open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error; 00307 00308 #if defined I_PUSH && !defined linux 00309 if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error; 00310 if (ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error; 00311 if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) goto error; 00312 #endif 00313 00314 *master = masterfd; 00315 *slave = slavefd; 00316 strlcpy(SlaveName, slavedevice, DEVICELEN); 00317 return 0; 00318 00319 grantpt_error: 00320 sigaction(SIGCHLD, &old, NULL); 00321 error: 00322 if (slavefd != -1) close(slavefd); 00323 if (masterfd != -1) close(masterfd); 00324 if (fail) { 00325 rb_raise(rb_eRuntimeError, "can't get Master/Slave device"); 00326 } 00327 return -1; 00328 #elif defined HAVE_OPENPTY 00329 /* 00330 * Use openpty(3) of 4.3BSD Reno and later, 00331 * or the same interface function. 00332 */ 00333 if (openpty(master, slave, SlaveName, 00334 (struct termios *)0, (struct winsize *)0) == -1) { 00335 if (!fail) return -1; 00336 rb_raise(rb_eRuntimeError, "openpty() failed"); 00337 } 00338 if (no_mesg(SlaveName, nomesg) == -1) { 00339 if (!fail) return -1; 00340 rb_raise(rb_eRuntimeError, "can't chmod slave pty"); 00341 } 00342 00343 return 0; 00344 00345 #elif defined HAVE__GETPTY 00346 char *name; 00347 mode_t mode = nomesg ? 0600 : 0622; 00348 00349 if (!(name = _getpty(master, O_RDWR, mode, 0))) { 00350 if (!fail) return -1; 00351 rb_raise(rb_eRuntimeError, "_getpty() failed"); 00352 } 00353 00354 *slave = open(name, O_RDWR); 00355 strlcpy(SlaveName, name, DEVICELEN); 00356 00357 return 0; 00358 #elif defined(HAVE_PTSNAME) 00359 int masterfd = -1, slavefd = -1; 00360 char *slavedevice; 00361 void (*s)(); 00362 00363 extern char *ptsname(int); 00364 extern int unlockpt(int); 00365 extern int grantpt(int); 00366 00367 if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error; 00368 s = signal(SIGCHLD, SIG_DFL); 00369 if(grantpt(masterfd) == -1) goto error; 00370 signal(SIGCHLD, s); 00371 if(unlockpt(masterfd) == -1) goto error; 00372 if((slavedevice = ptsname(masterfd)) == NULL) goto error; 00373 if (no_mesg(slavedevice, nomesg) == -1) goto error; 00374 if((slavefd = open(slavedevice, O_RDWR, 0)) == -1) goto error; 00375 #if defined I_PUSH && !defined linux 00376 if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error; 00377 if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error; 00378 ioctl(slavefd, I_PUSH, "ttcompat"); 00379 #endif 00380 *master = masterfd; 00381 *slave = slavefd; 00382 strlcpy(SlaveName, slavedevice, DEVICELEN); 00383 return 0; 00384 00385 error: 00386 if (slavefd != -1) close(slavefd); 00387 if (masterfd != -1) close(masterfd); 00388 if (fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device"); 00389 return -1; 00390 #else 00391 int masterfd = -1, slavefd = -1; 00392 const char *const *p; 00393 char MasterName[DEVICELEN]; 00394 00395 for (p = deviceNo; *p != NULL; p++) { 00396 snprintf(MasterName, sizeof MasterName, MasterDevice, *p); 00397 if ((masterfd = open(MasterName,O_RDWR,0)) >= 0) { 00398 *master = masterfd; 00399 snprintf(SlaveName, DEVICELEN, SlaveDevice, *p); 00400 if ((slavefd = open(SlaveName,O_RDWR,0)) >= 0) { 00401 *slave = slavefd; 00402 if (chown(SlaveName, getuid(), getgid()) != 0) goto error; 00403 if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error; 00404 return 0; 00405 } 00406 close(masterfd); 00407 } 00408 } 00409 error: 00410 if (slavefd != -1) close(slavefd); 00411 if (masterfd != -1) close(masterfd); 00412 if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName); 00413 return -1; 00414 #endif 00415 } 00416 00417 static void 00418 getDevice(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg) 00419 { 00420 if (get_device_once(master, slave, SlaveName, nomesg, 0)) { 00421 rb_gc(); 00422 get_device_once(master, slave, SlaveName, nomesg, 1); 00423 } 00424 } 00425 00426 static VALUE 00427 pty_close_pty(VALUE assoc) 00428 { 00429 VALUE io; 00430 int i; 00431 00432 for (i = 0; i < 2; i++) { 00433 io = rb_ary_entry(assoc, i); 00434 if (TYPE(io) == T_FILE && 0 <= RFILE(io)->fptr->fd) 00435 rb_io_close(io); 00436 } 00437 return Qnil; 00438 } 00439 00440 /* 00441 * call-seq: 00442 * PTY.open => [master_io, slave_file] 00443 * PTY.open {|master_io, slave_file| ... } => block value 00444 * 00445 * Allocates a pty (pseudo-terminal). 00446 * 00447 * It returns an array which contains an IO object and a File object. 00448 * The former is the master of the pty. 00449 * The latter is the slave of the pty. 00450 * 00451 * If a block is given, it yields the array instead of return. 00452 * The value of the block is returned. 00453 * master_io and slave_file is closed when return if they are not closed. 00454 * 00455 * The path name of the terminal device can be gotten by slave_file.path. 00456 * 00457 * PTY.open {|m, s| 00458 * p m #=> #<IO:masterpty:/dev/pts/1> 00459 * p s #=> #<File:/dev/pts/1> 00460 * p s.path #=> "/dev/pts/1" 00461 * } 00462 * 00463 * # Change the buffering type in factor command, 00464 * # assuming that factor uses stdio for stdout buffering. 00465 * # If IO.pipe is used instead of PTY.open, 00466 * # this code deadlocks because factor's stdout is fully buffered. 00467 * m, s = PTY.open 00468 * system("stty raw", :in=>s) # disable newline conversion. 00469 * r, w = IO.pipe 00470 * pid = spawn("factor", :in=>r, :out=>s) 00471 * r.close 00472 * s.close 00473 * w.puts "42" 00474 * p m.gets #=> "42: 2 3 7\n" 00475 * w.puts "144" 00476 * p m.gets #=> "144: 2 2 2 2 3 3\n" 00477 * w.close 00478 * # The result of read operation when pty slave is closed is platform dependnet. 00479 * ret = begin 00480 * m.gets # FreeBSD returns nil. 00481 * rescue Errno::EIO # GNU/Linux raises EIO. 00482 * nil 00483 * end 00484 * p ret #=> nil 00485 * 00486 */ 00487 static VALUE 00488 pty_open(VALUE klass) 00489 { 00490 int master_fd, slave_fd; 00491 char slavename[DEVICELEN]; 00492 VALUE master_io, slave_file; 00493 rb_io_t *master_fptr, *slave_fptr; 00494 VALUE assoc; 00495 00496 getDevice(&master_fd, &slave_fd, slavename, 1); 00497 00498 master_io = rb_obj_alloc(rb_cIO); 00499 MakeOpenFile(master_io, master_fptr); 00500 master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX; 00501 master_fptr->fd = master_fd; 00502 master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename)); 00503 00504 slave_file = rb_obj_alloc(rb_cFile); 00505 MakeOpenFile(slave_file, slave_fptr); 00506 slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY; 00507 slave_fptr->fd = slave_fd; 00508 slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename)); 00509 00510 assoc = rb_assoc_new(master_io, slave_file); 00511 if (rb_block_given_p()) { 00512 return rb_ensure(rb_yield, assoc, pty_close_pty, assoc); 00513 } 00514 return assoc; 00515 } 00516 00517 static VALUE 00518 pty_detach_process(struct pty_info *info) 00519 { 00520 rb_detach_process(info->child_pid); 00521 return Qnil; 00522 } 00523 00524 /* 00525 * call-seq: 00526 * PTY.spawn(command...) {|r, w, pid| ... } => nil 00527 * PTY.spawn(command...) => r, w, pid 00528 * PTY.getpty(command...) {|r, w, pid| ... } => nil 00529 * PTY.getpty(command...) => r, w, pid 00530 * 00531 * spawns the specified command on a newly allocated pty. 00532 * 00533 * The command's controlling tty is set to the slave device of the pty. 00534 * Also its standard input/output/error is redirected to the slave device. 00535 * 00536 * PTY.spawn returns two IO objects and PID. 00537 * PID is the process ID of the command. 00538 * The two IO objects are connected to the master device of the pty. 00539 * The first IO object is opened as read mode and 00540 * The second is opened as write mode. 00541 * 00542 * If a block is given, two IO objects and PID is yielded. 00543 * 00544 */ 00545 static VALUE 00546 pty_getpty(int argc, VALUE *argv, VALUE self) 00547 { 00548 VALUE res; 00549 struct pty_info info; 00550 rb_io_t *wfptr,*rfptr; 00551 VALUE rport = rb_obj_alloc(rb_cFile); 00552 VALUE wport = rb_obj_alloc(rb_cFile); 00553 char SlaveName[DEVICELEN]; 00554 00555 MakeOpenFile(rport, rfptr); 00556 MakeOpenFile(wport, wfptr); 00557 00558 establishShell(argc, argv, &info, SlaveName); 00559 00560 rfptr->mode = rb_io_mode_flags("r"); 00561 rfptr->fd = info.fd; 00562 rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName)); 00563 00564 wfptr->mode = rb_io_mode_flags("w") | FMODE_SYNC; 00565 wfptr->fd = dup(info.fd); 00566 if (wfptr->fd == -1) 00567 rb_sys_fail("dup()"); 00568 wfptr->pathv = rfptr->pathv; 00569 00570 res = rb_ary_new2(3); 00571 rb_ary_store(res,0,(VALUE)rport); 00572 rb_ary_store(res,1,(VALUE)wport); 00573 rb_ary_store(res,2,PIDT2NUM(info.child_pid)); 00574 00575 if (rb_block_given_p()) { 00576 rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info); 00577 return Qnil; 00578 } 00579 return res; 00580 } 00581 00582 static void 00583 raise_from_check(pid_t pid, int status) 00584 { 00585 const char *state; 00586 char buf[1024]; 00587 VALUE exc; 00588 00589 #if defined(WIFSTOPPED) 00590 #elif defined(IF_STOPPED) 00591 #define WIFSTOPPED(status) IF_STOPPED(status) 00592 #else 00593 ---->> Either IF_STOPPED or WIFSTOPPED is needed <<---- 00594 #endif /* WIFSTOPPED | IF_STOPPED */ 00595 if (WIFSTOPPED(status)) { /* suspend */ 00596 state = "stopped"; 00597 } 00598 else if (kill(pid, 0) == 0) { 00599 state = "changed"; 00600 } 00601 else { 00602 state = "exited"; 00603 } 00604 snprintf(buf, sizeof(buf), "pty - %s: %ld", state, (long)pid); 00605 exc = rb_exc_new2(eChildExited, buf); 00606 rb_iv_set(exc, "status", rb_last_status_get()); 00607 rb_exc_raise(exc); 00608 } 00609 00610 /* 00611 * call-seq: 00612 * PTY.check(pid[, raise=false]) => Process::Status or nil 00613 * 00614 * checks the status of the child process specified by _pid_, and 00615 * returns +nil+ if the process is still alive and active. Otherwise, 00616 * returns +Process::Status+ about the process if _raise_ is false, or 00617 * +PTY::ChildExited+ exception is raised. 00618 */ 00619 static VALUE 00620 pty_check(int argc, VALUE *argv, VALUE self) 00621 { 00622 VALUE pid, exc; 00623 pid_t cpid; 00624 int status; 00625 00626 rb_scan_args(argc, argv, "11", &pid, &exc); 00627 cpid = rb_waitpid(NUM2PIDT(pid), &status, WNOHANG|WUNTRACED); 00628 if (cpid == -1) return Qnil; 00629 00630 if (!RTEST(exc)) return rb_last_status_get(); 00631 raise_from_check(cpid, status); 00632 return Qnil; /* not reached */ 00633 } 00634 00635 static VALUE cPTY; 00636 00637 void 00638 Init_pty() 00639 { 00640 cPTY = rb_define_module("PTY"); 00641 rb_define_module_function(cPTY,"getpty",pty_getpty,-1); 00642 rb_define_module_function(cPTY,"spawn",pty_getpty,-1); 00643 rb_define_singleton_method(cPTY,"check",pty_check,-1); 00644 rb_define_singleton_method(cPTY,"open",pty_open,0); 00645 00646 eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError); 00647 rb_define_method(eChildExited,"status",echild_status,0); 00648 } 00649
1.7.3