Ruby 2.0.0p353(2013-11-22revision43784)

- Main Page
- Modules
- Data Structures
- Files

- File List
- Globals

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
60 static VALUE eChildExited;
61
62 /* Returns the exit status of the child for which PTY#check
63 * raised this exception
64 */
65 static VALUE
66 echild_status(VALUE self)
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;
81 VALUE execarg_obj;
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
151 establishShell(int argc, VALUE *argv, struct pty_info *info,
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);
182 rb_execarg_fixup(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
459 pty_close_pty(VALUE assoc)
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
505 pty_open(VALUE klass)
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);
523 slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
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
535 pty_detach_process(struct pty_info *info)
536 {
537 rb_detach_process(info->child_pid);
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
570 pty_getpty(int argc, VALUE *argv, VALUE self)
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()) {
601 rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
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 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.
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
654 pty_check(int argc, VALUE *argv, VALUE self)
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
739 Init_pty()
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
748 eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
749 rb_define_method(eChildExited,"status",echild_status,0);
750 }
data
VALUE data
Definition: tcltklib.c:3368
RB_TYPE_P
#define RB_TYPE_P(obj, type)
WNOHANG
#define WNOHANG
Definition: win32.h:109
child_info::slave
int slave
Definition: pty.c:79
pty_info::fd
int fd
Definition: pty.c:72
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1101
child_info
Definition: pty.c:78
ioctl
int ioctl(int, int,...)
Definition: win32.c:2438
FMODE_READWRITE
#define FMODE_READWRITE
Definition: io.h:105
rb_fork_async_signal_safe
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)
p
Win32OLEIDispatch * p
Definition: win32ole.c:786
rb_iv_set
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2591
rb_last_status_get
VALUE rb_last_status_get(void)
Definition: process.c:270
WIFSTOPPED
#define WIFSTOPPED(status)
Definition: pty.c:28
getuid
rb_uid_t getuid(void)
Definition: win32.c:2392
rb_define_singleton_method
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
pty_check
static VALUE pty_check(int argc, VALUE *argv, VALUE self)
Definition: pty.c:654
ruby.h
NUM2PIDT
#define NUM2PIDT(v)
Definition: ruby.h:332
child_info::master
int master
Definition: pty.c:79
PIDT2NUM
#define PIDT2NUM(v)
Definition: ruby.h:329
pty_close_pty
static VALUE pty_close_pty(VALUE assoc)
Definition: pty.c:459
i
ssize_t i
Definition: bigdecimal.c:5655
rb_io_t
Definition: io.h:63
info
Tcl_CmdInfo * info
Definition: tcltklib.c:1463
rb_str_new_cstr
VALUE rb_str_new_cstr(const char *)
Definition: string.c:447
status
int status
Definition: tcltklib.c:2197
rb_obj_freeze
VALUE rb_obj_freeze(VALUE)
Definition: object.c:989
UNREACHABLE
#define UNREACHABLE
Definition: ruby.h:40
rb_update_max_fd
void rb_update_max_fd(int fd)
Definition: io.c:164
exc
VALUE exc
Definition: tcltklib.c:3096
kill
int kill(int, int)
Definition: win32.c:4079
RFILE
#define RFILE(obj)
child_info::execarg_obj
VALUE execarg_obj
Definition: pty.c:81
rb_define_class_under
VALUE rb_define_class_under(VALUE outer, const char *name, VALUE super)
Defines a class under the namespace of outer.
Definition: class.c:545
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1780
rb_execarg_new
VALUE rb_execarg_new(int argc, VALUE *argv, int accept_shell)
Definition: process.c:2190
get_device_once
static int get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
Definition: pty.c:219
T_FILE
#define T_FILE
FMODE_DUPLEX
#define FMODE_DUPLEX
Definition: io.h:109
pty_open
static VALUE pty_open(VALUE klass)
Definition: pty.c:505
pty_info
Definition: pty.c:71
rb_str_new2
#define rb_str_new2
establishShell
static void establishShell(int argc, VALUE *argv, struct pty_info *info, char SlaveName[DEVICELEN])
Definition: pty.c:151
rb_cloexec_dup
int rb_cloexec_dup(int oldfd)
Definition: io.c:225
state
int state
Definition: tcltklib.c:1462
io.h
rb_ivar_get
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1116
getDevice
static void getDevice(int *, int *, char[DEVICELEN], int)
Definition: pty.c:450
rb_fd_fix_cloexec
void rb_fd_fix_cloexec(int fd)
Definition: io.c:202
strlcpy
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
rb_io_t::mode
int mode
Definition: io.h:66
child_info::eargp
struct rb_execarg * eargp
Definition: pty.c:82
NORETURN
#define NORETURN(x)
Definition: ruby.h:31
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Definition: eval.c:527
eChildExited
static VALUE eChildExited
Definition: pty.c:60
fail
#define fail()
Definition: date_strptime.c:118
O_CLOEXEC
#define O_CLOEXEC
rb_gc
void rb_gc(void)
Definition: gc.c:3108
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:672
Qnil
#define Qnil
Definition: tcltklib.c:1896
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:510
rb_detach_process
VALUE rb_detach_process(rb_pid_t pid)
Definition: process.c:976
rb_execarg_get
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
Definition: process.c:2201
flags
int flags
Definition: tcltklib.c:3023
chown
int chown(const char *, int, int)
Definition: win32.c:4065
no_mesg
static int no_mesg(char *slavedevice, int nomesg)
Definition: pty.c:210
rb_io_t::fd
int fd
Definition: io.h:64
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:719
unistd.h
signal.h
rb_waitpid
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Definition: process.c:707
seteuid
int seteuid(pid_t pid)
buf
unsigned char buf[MIME_BUF_SIZE]
Definition: nkf.c:4308
slave
Tcl_Interp * slave
Definition: tcltklib.c:5602
assoc
static VALUE VALUE assoc
Definition: tkutil.c:545
argv
VALUE * argv
Definition: tcltklib.c:1971
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:934
RTEST
#define RTEST(v)
rb_define_module_function
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
errno
int errno
util.h
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1270
chfunc
static int chfunc(void *data, char *errbuf, size_t errbuf_len)
Definition: pty.c:86
cPTY
static VALUE cPTY
Definition: pty.c:670
Init_pty
void Init_pty()
Definition: pty.c:739
s
register char * s
Definition: os2.c:56
void
VP_EXPORT void
Definition: bigdecimal.c:5083
mode
VALUE mode
Definition: tcltklib.c:1664
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1570
pty_info::child_pid
rb_pid_t child_pid
Definition: pty.c:73
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:545
internal.h
rb_execarg
Definition: ripper.y:207
rb_exc_new2
VALUE rb_exc_new2(VALUE etype, const char *s)
Definition: error.c:542
raise_from_check
static void raise_from_check(pid_t pid, int status)
Definition: pty.c:609
rb_exec_async_signal_safe
int rb_exec_async_signal_safe(const struct rb_execarg *e, char *errmsg, size_t errmsg_buflen)
Definition: process.c:3019
RB_GC_GUARD
#define RB_GC_GUARD(v)
mode_t
#define mode_t
Definition: win32.h:100
argc
int argc
Definition: tcltklib.c:1970
getenv
char * getenv()
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:804
rb_io_mode_flags
#define rb_io_mode_flags(modestr)
Definition: io.h:192
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1899
rb_jump_tag
void rb_jump_tag(int tag)
Definition: eval.c:666
rb_cIO
RUBY_EXTERN VALUE rb_cIO
Definition: ripper.y:1442
rb_cFile
RUBY_EXTERN VALUE rb_cFile
Definition: ripper.y:1437
child_info::slavename
char * slavename
Definition: pty.c:80
pty_getpty
static VALUE pty_getpty(int argc, VALUE *argv, VALUE self)
Definition: pty.c:570
signal
sighandler_t signal(int signum, sighandler_t handler)
rb_io_t::pathv
VALUE pathv
Definition: io.h:69
klass
klass
Definition: tcltklib.c:3504
ERROR_EXIT
#define ERROR_EXIT(str)
dup2
RUBY_EXTERN int dup2(int, int)
Definition: dup2.c:27
io
gz io
Definition: zlib.c:2263
DEVICELEN
#define DEVICELEN
Definition: pty.c:46
rb_ary_new2
VALUE rb_ary_new2(long capa)
Definition: array.c:417
res
Real * res
Definition: bigdecimal.c:1233
echild_status
static VALUE echild_status(VALUE self)
Definition: pty.c:66
rb_obj_alloc
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1721
rb_cloexec_open
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Definition: io.c:209
FMODE_SYNC
#define FMODE_SYNC
Definition: io.h:107
FMODE_TTY
#define FMODE_TTY
Definition: io.h:108
MakeOpenFile
#define MakeOpenFile(obj, fp)
Definition: io.h:129
rb_io_close
VALUE rb_io_close(VALUE)
Definition: io.c:4221
pty_detach_process
static VALUE pty_detach_process(struct pty_info *info)
Definition: pty.c:535
e
BDIGIT e
Definition: bigdecimal.c:5085
VALUE
unsigned long VALUE
Definition: ripper.y:104
getgid
rb_gid_t getgid(void)
Definition: win32.c:2406
snprintf
#define snprintf
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:617
rb_intern
#define rb_intern(str)
v
BDIGIT v
Definition: bigdecimal.c:5656
NULL
#define NULL
Definition: _sdbm.c:103
name
const char * name
Definition: nkf.c:208
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1344
master
static VALUE VALUE master
Definition: tcltklib.c:6542
rb_execarg_fixup
void rb_execarg_fixup(VALUE execarg_obj)
Definition: process.c:2254