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 #if defined(HAVE_SYS_PARAM_H)
00026
00027 # include <sys/param.h>
00028 #endif
00029 #ifdef HAVE_SYS_WAIT_H
00030 #include <sys/wait.h>
00031 #else
00032 #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
00033 #endif
00034 #include <ctype.h>
00035
00036 #include "ruby/ruby.h"
00037 #include "ruby/io.h"
00038 #include "ruby/util.h"
00039 #include "internal.h"
00040
00041 #include <signal.h>
00042 #ifdef HAVE_SYS_STROPTS_H
00043 #include <sys/stropts.h>
00044 #endif
00045
00046 #ifdef HAVE_UNISTD_H
00047 #include <unistd.h>
00048 #endif
00049
00050 #define DEVICELEN 16
00051
00052 #ifndef HAVE_SETEUID
00053 # ifdef HAVE_SETREUID
00054 # define seteuid(e) setreuid(-1, (e))
00055 # else
00056 # ifdef HAVE_SETRESUID
00057 # define seteuid(e) setresuid(-1, (e), -1)
00058 # else
00059
00060 # endif
00061 # endif
00062 #endif
00063
00064 static VALUE eChildExited;
00065
00066
00067
00068
00069 static VALUE
00070 echild_status(VALUE self)
00071 {
00072 return rb_ivar_get(self, rb_intern("status"));
00073 }
00074
00075 struct pty_info {
00076 int fd;
00077 rb_pid_t child_pid;
00078 };
00079
00080 static void getDevice(int*, int*, char [DEVICELEN], int);
00081
00082 struct child_info {
00083 int master, slave;
00084 char *slavename;
00085 VALUE execarg_obj;
00086 struct rb_execarg *eargp;
00087 };
00088
00089 static int
00090 chfunc(void *data, char *errbuf, size_t errbuf_len)
00091 {
00092 struct child_info *carg = data;
00093 int master = carg->master;
00094 int slave = carg->slave;
00095
00096 #define ERROR_EXIT(str) do { \
00097 strlcpy(errbuf, (str), errbuf_len); \
00098 return -1; \
00099 } while (0)
00100
00101
00102
00103
00104 #ifdef HAVE_SETSID
00105 (void) setsid();
00106 #else
00107 # ifdef HAVE_SETPGRP
00108 # ifdef SETGRP_VOID
00109 if (setpgrp() == -1)
00110 ERROR_EXIT("setpgrp()");
00111 # else
00112 if (setpgrp(0, getpid()) == -1)
00113 ERROR_EXIT("setpgrp()");
00114 {
00115 int i = rb_cloexec_open("/dev/tty", O_RDONLY, 0);
00116 if (i < 0) ERROR_EXIT("/dev/tty");
00117 rb_update_max_fd(i);
00118 if (ioctl(i, TIOCNOTTY, (char *)0))
00119 ERROR_EXIT("ioctl(TIOCNOTTY)");
00120 close(i);
00121 }
00122 # endif
00123 # endif
00124 #endif
00125
00126
00127
00128
00129 #if defined(TIOCSCTTY)
00130 close(master);
00131 (void) ioctl(slave, TIOCSCTTY, (char *)0);
00132
00133 #else
00134 close(slave);
00135 slave = rb_cloexec_open(carg->slavename, O_RDWR, 0);
00136 if (slave < 0) {
00137 ERROR_EXIT("open: pty slave");
00138 }
00139 rb_update_max_fd(slave);
00140 close(master);
00141 #endif
00142 dup2(slave,0);
00143 dup2(slave,1);
00144 dup2(slave,2);
00145 close(slave);
00146 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
00147 if (seteuid(getuid())) ERROR_EXIT("seteuid()");
00148 #endif
00149
00150 return rb_exec_async_signal_safe(carg->eargp, errbuf, sizeof(errbuf_len));
00151 #undef ERROR_EXIT
00152 }
00153
00154 static void
00155 establishShell(int argc, VALUE *argv, struct pty_info *info,
00156 char SlaveName[DEVICELEN])
00157 {
00158 int master, slave, status = 0;
00159 rb_pid_t pid;
00160 char *p, *getenv();
00161 struct passwd *pwent;
00162 VALUE v;
00163 struct child_info carg;
00164 char errbuf[32];
00165
00166 if (argc == 0) {
00167 const char *shellname;
00168
00169 if ((p = getenv("SHELL")) != NULL) {
00170 shellname = p;
00171 }
00172 else {
00173 pwent = getpwuid(getuid());
00174 if (pwent && pwent->pw_shell)
00175 shellname = pwent->pw_shell;
00176 else
00177 shellname = "/bin/sh";
00178 }
00179 v = rb_str_new2(shellname);
00180 argc = 1;
00181 argv = &v;
00182 }
00183
00184 carg.execarg_obj = rb_execarg_new(argc, argv, 1);
00185 carg.eargp = rb_execarg_get(carg.execarg_obj);
00186 rb_execarg_fixup(carg.execarg_obj);
00187
00188 getDevice(&master, &slave, SlaveName, 0);
00189
00190 carg.master = master;
00191 carg.slave = slave;
00192 carg.slavename = SlaveName;
00193 errbuf[0] = '\0';
00194 pid = rb_fork_async_signal_safe(&status, chfunc, &carg, Qnil, errbuf, sizeof(errbuf));
00195
00196 if (pid < 0) {
00197 int e = errno;
00198 close(master);
00199 close(slave);
00200 errno = e;
00201 if (status) rb_jump_tag(status);
00202 rb_sys_fail(errbuf[0] ? errbuf : "fork failed");
00203 }
00204
00205 close(slave);
00206
00207 info->child_pid = pid;
00208 info->fd = master;
00209
00210 RB_GC_GUARD(carg.execarg_obj);
00211 }
00212
00213 static int
00214 no_mesg(char *slavedevice, int nomesg)
00215 {
00216 if (nomesg)
00217 return chmod(slavedevice, 0600);
00218 else
00219 return 0;
00220 }
00221
00222 static int
00223 get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
00224 {
00225 #if defined(HAVE_POSIX_OPENPT)
00226
00227 int masterfd = -1, slavefd = -1;
00228 char *slavedevice;
00229 struct sigaction dfl, old;
00230
00231 dfl.sa_handler = SIG_DFL;
00232 dfl.sa_flags = 0;
00233 sigemptyset(&dfl.sa_mask);
00234
00235 #if defined(__sun) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
00236
00237
00238
00239 if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
00240 if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
00241 if (grantpt(masterfd) == -1) goto grantpt_error;
00242 rb_fd_fix_cloexec(masterfd);
00243 #else
00244 {
00245 int flags = O_RDWR|O_NOCTTY;
00246 # if defined(O_CLOEXEC)
00247
00248
00249
00250 flags |= O_CLOEXEC;
00251 # endif
00252 if ((masterfd = posix_openpt(flags)) == -1) goto error;
00253 }
00254 rb_fd_fix_cloexec(masterfd);
00255 if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
00256 if (grantpt(masterfd) == -1) goto grantpt_error;
00257 #endif
00258 if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
00259 if (unlockpt(masterfd) == -1) goto error;
00260 if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
00261 if (no_mesg(slavedevice, nomesg) == -1) goto error;
00262 if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
00263 rb_update_max_fd(slavefd);
00264
00265 #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
00266 if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
00267 if (ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
00268 if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) goto error;
00269 #endif
00270
00271 *master = masterfd;
00272 *slave = slavefd;
00273 strlcpy(SlaveName, slavedevice, DEVICELEN);
00274 return 0;
00275
00276 grantpt_error:
00277 sigaction(SIGCHLD, &old, NULL);
00278 error:
00279 if (slavefd != -1) close(slavefd);
00280 if (masterfd != -1) close(masterfd);
00281 if (fail) {
00282 rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
00283 }
00284 return -1;
00285 #elif defined HAVE_OPENPTY
00286
00287
00288
00289
00290 if (openpty(master, slave, SlaveName,
00291 (struct termios *)0, (struct winsize *)0) == -1) {
00292 if (!fail) return -1;
00293 rb_raise(rb_eRuntimeError, "openpty() failed");
00294 }
00295 rb_fd_fix_cloexec(*master);
00296 rb_fd_fix_cloexec(*slave);
00297 if (no_mesg(SlaveName, nomesg) == -1) {
00298 if (!fail) return -1;
00299 rb_raise(rb_eRuntimeError, "can't chmod slave pty");
00300 }
00301
00302 return 0;
00303
00304 #elif defined HAVE__GETPTY
00305
00306 char *name;
00307 mode_t mode = nomesg ? 0600 : 0622;
00308
00309 if (!(name = _getpty(master, O_RDWR, mode, 0))) {
00310 if (!fail) return -1;
00311 rb_raise(rb_eRuntimeError, "_getpty() failed");
00312 }
00313 rb_fd_fix_cloexec(*master);
00314
00315 *slave = rb_cloexec_open(name, O_RDWR, 0);
00316
00317 rb_update_max_fd(*slave);
00318 strlcpy(SlaveName, name, DEVICELEN);
00319
00320 return 0;
00321 #elif defined(HAVE_PTSNAME)
00322
00323 int masterfd = -1, slavefd = -1;
00324 char *slavedevice;
00325 void (*s)();
00326
00327 extern char *ptsname(int);
00328 extern int unlockpt(int);
00329 extern int grantpt(int);
00330
00331 #if defined(__sun)
00332
00333 if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
00334 s = signal(SIGCHLD, SIG_DFL);
00335 if(grantpt(masterfd) == -1) goto error;
00336 rb_fd_fix_cloexec(masterfd);
00337 #else
00338 if((masterfd = rb_cloexec_open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
00339 rb_update_max_fd(masterfd);
00340 s = signal(SIGCHLD, SIG_DFL);
00341 if(grantpt(masterfd) == -1) goto error;
00342 #endif
00343 signal(SIGCHLD, s);
00344 if(unlockpt(masterfd) == -1) goto error;
00345 if((slavedevice = ptsname(masterfd)) == NULL) goto error;
00346 if (no_mesg(slavedevice, nomesg) == -1) goto error;
00347 if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error;
00348 rb_update_max_fd(slavefd);
00349 #if defined(I_PUSH) && !defined(__linux__) && !defined(_AIX)
00350 if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
00351 if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
00352 ioctl(slavefd, I_PUSH, "ttcompat");
00353 #endif
00354 *master = masterfd;
00355 *slave = slavefd;
00356 strlcpy(SlaveName, slavedevice, DEVICELEN);
00357 return 0;
00358
00359 error:
00360 if (slavefd != -1) close(slavefd);
00361 if (masterfd != -1) close(masterfd);
00362 if (fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
00363 return -1;
00364 #else
00365
00366 int masterfd = -1, slavefd = -1;
00367 const char *const *p;
00368 char MasterName[DEVICELEN];
00369
00370 #if defined(__hpux)
00371 static const char MasterDevice[] = "/dev/ptym/pty%s";
00372 static const char SlaveDevice[] = "/dev/pty/tty%s";
00373 static const char *const deviceNo[] = {
00374 "p0","p1","p2","p3","p4","p5","p6","p7",
00375 "p8","p9","pa","pb","pc","pd","pe","pf",
00376 "q0","q1","q2","q3","q4","q5","q6","q7",
00377 "q8","q9","qa","qb","qc","qd","qe","qf",
00378 "r0","r1","r2","r3","r4","r5","r6","r7",
00379 "r8","r9","ra","rb","rc","rd","re","rf",
00380 "s0","s1","s2","s3","s4","s5","s6","s7",
00381 "s8","s9","sa","sb","sc","sd","se","sf",
00382 "t0","t1","t2","t3","t4","t5","t6","t7",
00383 "t8","t9","ta","tb","tc","td","te","tf",
00384 "u0","u1","u2","u3","u4","u5","u6","u7",
00385 "u8","u9","ua","ub","uc","ud","ue","uf",
00386 "v0","v1","v2","v3","v4","v5","v6","v7",
00387 "v8","v9","va","vb","vc","vd","ve","vf",
00388 "w0","w1","w2","w3","w4","w5","w6","w7",
00389 "w8","w9","wa","wb","wc","wd","we","wf",
00390 0
00391 };
00392 #elif defined(_IBMESA)
00393 static const char MasterDevice[] = "/dev/ptyp%s";
00394 static const char SlaveDevice[] = "/dev/ttyp%s";
00395 static const char *const deviceNo[] = {
00396 "00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f",
00397 "10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f",
00398 "20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f",
00399 "30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f",
00400 "40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f",
00401 "50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f",
00402 "60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f",
00403 "70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f",
00404 "80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f",
00405 "90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f",
00406 "a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af",
00407 "b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf",
00408 "c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf",
00409 "d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df",
00410 "e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef",
00411 "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff",
00412 0
00413 };
00414 #else
00415 static const char MasterDevice[] = "/dev/pty%s";
00416 static const char SlaveDevice[] = "/dev/tty%s";
00417 static const char *const deviceNo[] = {
00418 "p0","p1","p2","p3","p4","p5","p6","p7",
00419 "p8","p9","pa","pb","pc","pd","pe","pf",
00420 "q0","q1","q2","q3","q4","q5","q6","q7",
00421 "q8","q9","qa","qb","qc","qd","qe","qf",
00422 "r0","r1","r2","r3","r4","r5","r6","r7",
00423 "r8","r9","ra","rb","rc","rd","re","rf",
00424 "s0","s1","s2","s3","s4","s5","s6","s7",
00425 "s8","s9","sa","sb","sc","sd","se","sf",
00426 0
00427 };
00428 #endif
00429 for (p = deviceNo; *p != NULL; p++) {
00430 snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
00431 if ((masterfd = rb_cloexec_open(MasterName,O_RDWR,0)) >= 0) {
00432 rb_update_max_fd(masterfd);
00433 *master = masterfd;
00434 snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
00435 if ((slavefd = rb_cloexec_open(SlaveName,O_RDWR,0)) >= 0) {
00436 rb_update_max_fd(slavefd);
00437 *slave = slavefd;
00438 if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
00439 if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
00440 return 0;
00441 }
00442 close(masterfd);
00443 }
00444 }
00445 error:
00446 if (slavefd != -1) close(slavefd);
00447 if (masterfd != -1) close(masterfd);
00448 if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName);
00449 return -1;
00450 #endif
00451 }
00452
00453 static void
00454 getDevice(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg)
00455 {
00456 if (get_device_once(master, slave, SlaveName, nomesg, 0)) {
00457 rb_gc();
00458 get_device_once(master, slave, SlaveName, nomesg, 1);
00459 }
00460 }
00461
00462 static VALUE
00463 pty_close_pty(VALUE assoc)
00464 {
00465 VALUE io;
00466 int i;
00467
00468 for (i = 0; i < 2; i++) {
00469 io = rb_ary_entry(assoc, i);
00470 if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
00471 rb_io_close(io);
00472 }
00473 return Qnil;
00474 }
00475
00476
00477
00478
00479
00480
00481
00482
00483
00484
00485
00486
00487
00488
00489
00490
00491
00492
00493
00494
00495
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507
00508 static VALUE
00509 pty_open(VALUE klass)
00510 {
00511 int master_fd, slave_fd;
00512 char slavename[DEVICELEN];
00513 VALUE master_io, slave_file;
00514 rb_io_t *master_fptr, *slave_fptr;
00515 VALUE assoc;
00516
00517 getDevice(&master_fd, &slave_fd, slavename, 1);
00518
00519 master_io = rb_obj_alloc(rb_cIO);
00520 MakeOpenFile(master_io, master_fptr);
00521 master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
00522 master_fptr->fd = master_fd;
00523 master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
00524
00525 slave_file = rb_obj_alloc(rb_cFile);
00526 MakeOpenFile(slave_file, slave_fptr);
00527 slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
00528 slave_fptr->fd = slave_fd;
00529 slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
00530
00531 assoc = rb_assoc_new(master_io, slave_file);
00532 if (rb_block_given_p()) {
00533 return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
00534 }
00535 return assoc;
00536 }
00537
00538 static VALUE
00539 pty_detach_process(struct pty_info *info)
00540 {
00541 rb_detach_process(info->child_pid);
00542 return Qnil;
00543 }
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573 static VALUE
00574 pty_getpty(int argc, VALUE *argv, VALUE self)
00575 {
00576 VALUE res;
00577 struct pty_info info;
00578 rb_io_t *wfptr,*rfptr;
00579 VALUE rport = rb_obj_alloc(rb_cFile);
00580 VALUE wport = rb_obj_alloc(rb_cFile);
00581 char SlaveName[DEVICELEN];
00582
00583 MakeOpenFile(rport, rfptr);
00584 MakeOpenFile(wport, wfptr);
00585
00586 establishShell(argc, argv, &info, SlaveName);
00587
00588 rfptr->mode = rb_io_mode_flags("r");
00589 rfptr->fd = info.fd;
00590 rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
00591
00592 wfptr->mode = rb_io_mode_flags("w") | FMODE_SYNC;
00593 wfptr->fd = rb_cloexec_dup(info.fd);
00594 if (wfptr->fd == -1)
00595 rb_sys_fail("dup()");
00596 rb_update_max_fd(wfptr->fd);
00597 wfptr->pathv = rfptr->pathv;
00598
00599 res = rb_ary_new2(3);
00600 rb_ary_store(res,0,(VALUE)rport);
00601 rb_ary_store(res,1,(VALUE)wport);
00602 rb_ary_store(res,2,PIDT2NUM(info.child_pid));
00603
00604 if (rb_block_given_p()) {
00605 rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
00606 return Qnil;
00607 }
00608 return res;
00609 }
00610
00611 NORETURN(static void raise_from_check(rb_pid_t pid, int status));
00612 static void
00613 raise_from_check(rb_pid_t pid, int status)
00614 {
00615 const char *state;
00616 VALUE msg;
00617 VALUE exc;
00618
00619 #if defined(WIFSTOPPED)
00620 #elif defined(IF_STOPPED)
00621 #define WIFSTOPPED(status) IF_STOPPED(status)
00622 #else
00623 ---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
00624 #endif
00625 if (WIFSTOPPED(status)) {
00626 state = "stopped";
00627 }
00628 else if (kill(pid, 0) == 0) {
00629 state = "changed";
00630 }
00631 else {
00632 state = "exited";
00633 }
00634 msg = rb_sprintf("pty - %s: %ld", state, (long)pid);
00635 exc = rb_exc_new_str(eChildExited, msg);
00636 rb_iv_set(exc, "status", rb_last_status_get());
00637 rb_exc_raise(exc);
00638 }
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 static VALUE
00658 pty_check(int argc, VALUE *argv, VALUE self)
00659 {
00660 VALUE pid, exc;
00661 rb_pid_t cpid;
00662 int status;
00663
00664 rb_scan_args(argc, argv, "11", &pid, &exc);
00665 cpid = rb_waitpid(NUM2PIDT(pid), &status, WNOHANG|WUNTRACED);
00666 if (cpid == -1 || cpid == 0) return Qnil;
00667
00668 if (!RTEST(exc)) return rb_last_status_get();
00669 raise_from_check(cpid, status);
00670
00671 UNREACHABLE;
00672 }
00673
00674 static VALUE cPTY;
00675
00676
00677
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705
00706
00707
00708
00709
00710
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720
00721
00722
00723
00724
00725
00726
00727
00728
00729
00730
00731
00732
00733
00734
00735
00736
00737
00738
00739
00740
00741
00742 void
00743 Init_pty()
00744 {
00745 cPTY = rb_define_module("PTY");
00746
00747 rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
00748 rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
00749 rb_define_singleton_method(cPTY,"check",pty_check,-1);
00750 rb_define_singleton_method(cPTY,"open",pty_open,0);
00751
00752 eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
00753 rb_define_method(eChildExited,"status",echild_status,0);
00754 }
00755