Ruby 2.1.5p273(2014-11-13revision48405)

- 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 #if defined(HAVE_SYS_PARAM_H)
26 /* for __FreeBSD_version */
27 # include <sys/param.h>
28 #endif
29 #ifdef HAVE_SYS_WAIT_H
30 #include <sys/wait.h>
31 #else
32 #define WIFSTOPPED(status) (((status) & 0xff) == 0x7f)
33 #endif
34 #include <ctype.h>
35
36 #include "ruby/ruby.h"
37 #include "ruby/io.h"
38 #include "ruby/util.h"
39 #include "internal.h"
40
41 #include <signal.h>
42 #ifdef HAVE_SYS_STROPTS_H
43 #include <sys/stropts.h>
44 #endif
45
46 #ifdef HAVE_UNISTD_H
47 #include <unistd.h>
48 #endif
49
50 #define DEVICELEN 16
51
52 #ifndef HAVE_SETEUID
53 # ifdef HAVE_SETREUID
54 # define seteuid(e) setreuid(-1, (e))
55 # else /* NOT HAVE_SETREUID */
56 # ifdef HAVE_SETRESUID
57 # define seteuid(e) setresuid(-1, (e), -1)
58 # else /* NOT HAVE_SETRESUID */
59 /* I can't set euid. (;_;) */
60 # endif /* HAVE_SETRESUID */
61 # endif /* HAVE_SETREUID */
62 #endif /* NO_SETEUID */
63
64 static VALUE eChildExited;
65
66 /* Returns the exit status of the child for which PTY#check
67 * raised this exception
68 */
69 static VALUE
70 echild_status(VALUE self)
71 {
72 return rb_ivar_get(self, rb_intern("status"));
73 }
74
75 struct pty_info {
76 int fd;
77 rb_pid_t child_pid;
78 };
79
80 static void getDevice(int*, int*, char [DEVICELEN], int);
81
82 struct child_info {
83 int master, slave;
84 char *slavename;
85 VALUE execarg_obj;
86 struct rb_execarg *eargp;
87 };
88
89 static int
90 chfunc(void *data, char *errbuf, size_t errbuf_len)
91 {
92 struct child_info *carg = data;
93 int master = carg->master;
94 int slave = carg->slave;
95
96 #define ERROR_EXIT(str) do { \
97 strlcpy(errbuf, (str), errbuf_len); \
98 return -1; \
99 } while (0)
100
101 /*
102 * Set free from process group and controlling terminal
103 */
104 #ifdef HAVE_SETSID
105 (void) setsid();
106 #else /* HAS_SETSID */
107 # ifdef HAVE_SETPGRP
108 # ifdef SETGRP_VOID
109 if (setpgrp() == -1)
110 ERROR_EXIT("setpgrp()");
111 # else /* SETGRP_VOID */
112 if (setpgrp(0, getpid()) == -1)
113 ERROR_EXIT("setpgrp()");
114 {
115 int i = rb_cloexec_open("/dev/tty", O_RDONLY, 0);
116 if (i < 0) ERROR_EXIT("/dev/tty");
117 rb_update_max_fd(i);
118 if (ioctl(i, TIOCNOTTY, (char *)0))
119 ERROR_EXIT("ioctl(TIOCNOTTY)");
120 close(i);
121 }
122 # endif /* SETGRP_VOID */
123 # endif /* HAVE_SETPGRP */
124 #endif /* HAS_SETSID */
125
126 /*
127 * obtain new controlling terminal
128 */
129 #if defined(TIOCSCTTY)
130 close(master);
131 (void) ioctl(slave, TIOCSCTTY, (char *)0);
132 /* errors ignored for sun */
133 #else
134 close(slave);
135 slave = rb_cloexec_open(carg->slavename, O_RDWR, 0);
136 if (slave < 0) {
137 ERROR_EXIT("open: pty slave");
138 }
139 rb_update_max_fd(slave);
140 close(master);
141 #endif
142 dup2(slave,0);
143 dup2(slave,1);
144 dup2(slave,2);
145 close(slave);
146 #if defined(HAVE_SETEUID) || defined(HAVE_SETREUID) || defined(HAVE_SETRESUID)
147 if (seteuid(getuid())) ERROR_EXIT("seteuid()");
148 #endif
149
150 return rb_exec_async_signal_safe(carg->eargp, errbuf, sizeof(errbuf_len));
151 #undef ERROR_EXIT
152 }
153
154 static void
155 establishShell(int argc, VALUE *argv, struct pty_info *info,
156 char SlaveName[DEVICELEN])
157 {
158 int master, slave, status = 0;
159 rb_pid_t pid;
160 char *p, *getenv();
161 struct passwd *pwent;
162 VALUE v;
163 struct child_info carg;
164 char errbuf[32];
165
166 if (argc == 0) {
167 const char *shellname;
168
169 if ((p = getenv("SHELL")) != NULL) {
170 shellname = p;
171 }
172 else {
173 pwent = getpwuid(getuid());
174 if (pwent && pwent->pw_shell)
175 shellname = pwent->pw_shell;
176 else
177 shellname = "/bin/sh";
178 }
179 v = rb_str_new2(shellname);
180 argc = 1;
181 argv = &v;
182 }
183
184 carg.execarg_obj = rb_execarg_new(argc, argv, 1);
185 carg.eargp = rb_execarg_get(carg.execarg_obj);
186 rb_execarg_fixup(carg.execarg_obj);
187
188 getDevice(&master, &slave, SlaveName, 0);
189
190 carg.master = master;
191 carg.slave = slave;
192 carg.slavename = SlaveName;
193 errbuf[0] = '\0';
194 pid = rb_fork_async_signal_safe(&status, chfunc, &carg, Qnil, errbuf, sizeof(errbuf));
195
196 if (pid < 0) {
197 int e = errno;
198 close(master);
199 close(slave);
200 errno = e;
201 if (status) rb_jump_tag(status);
202 rb_sys_fail(errbuf[0] ? errbuf : "fork failed");
203 }
204
205 close(slave);
206
207 info->child_pid = pid;
208 info->fd = master;
209
210 RB_GC_GUARD(carg.execarg_obj);
211 }
212
213 static int
214 no_mesg(char *slavedevice, int nomesg)
215 {
216 if (nomesg)
217 return chmod(slavedevice, 0600);
218 else
219 return 0;
220 }
221
222 static int
223 get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
224 {
225 #if defined(HAVE_POSIX_OPENPT)
226 /* Unix98 PTY */
227 int masterfd = -1, slavefd = -1;
228 char *slavedevice;
229 struct sigaction dfl, old;
230
231 dfl.sa_handler = SIG_DFL;
232 dfl.sa_flags = 0;
233 sigemptyset(&dfl.sa_mask);
234
235 #if defined(__sun) || (defined(__FreeBSD__) && __FreeBSD_version < 902000)
236 /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
237 /* FreeBSD 9.2 or later supports O_CLOEXEC
238 * http://www.freebsd.org/cgi/query-pr.cgi?pr=162374 */
239 if ((masterfd = posix_openpt(O_RDWR|O_NOCTTY)) == -1) goto error;
240 if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
241 if (grantpt(masterfd) == -1) goto grantpt_error;
242 rb_fd_fix_cloexec(masterfd);
243 #else
244 {
245 int flags = O_RDWR|O_NOCTTY;
246 # if defined(O_CLOEXEC)
247 /* glibc posix_openpt() in GNU/Linux calls open("/dev/ptmx", flags) internally.
248 * So version dependency on GNU/Linux is same as O_CLOEXEC with open().
249 * O_CLOEXEC is available since Linux 2.6.23. Linux 2.6.18 silently ignore it. */
250 flags |= O_CLOEXEC;
251 # endif
252 if ((masterfd = posix_openpt(flags)) == -1) goto error;
253 }
254 rb_fd_fix_cloexec(masterfd);
255 if (sigaction(SIGCHLD, &dfl, &old) == -1) goto error;
256 if (grantpt(masterfd) == -1) goto grantpt_error;
257 #endif
258 if (sigaction(SIGCHLD, &old, NULL) == -1) goto error;
259 if (unlockpt(masterfd) == -1) goto error;
260 if ((slavedevice = ptsname(masterfd)) == NULL) goto error;
261 if (no_mesg(slavedevice, nomesg) == -1) goto error;
262 if ((slavefd = rb_cloexec_open(slavedevice, O_RDWR|O_NOCTTY, 0)) == -1) goto error;
263 rb_update_max_fd(slavefd);
264
265 #if defined(I_PUSH) && !defined(__linux__)
266 if (ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
267 if (ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
268 if (ioctl(slavefd, I_PUSH, "ttcompat") == -1) goto error;
269 #endif
270
271 *master = masterfd;
272 *slave = slavefd;
273 strlcpy(SlaveName, slavedevice, DEVICELEN);
274 return 0;
275
276 grantpt_error:
277 sigaction(SIGCHLD, &old, NULL);
278 error:
279 if (slavefd != -1) close(slavefd);
280 if (masterfd != -1) close(masterfd);
281 if (fail) {
282 rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
283 }
284 return -1;
285 #elif defined HAVE_OPENPTY
286 /*
287 * Use openpty(3) of 4.3BSD Reno and later,
288 * or the same interface function.
289 */
290 if (openpty(master, slave, SlaveName,
291 (struct termios *)0, (struct winsize *)0) == -1) {
292 if (!fail) return -1;
293 rb_raise(rb_eRuntimeError, "openpty() failed");
294 }
295 rb_fd_fix_cloexec(*master);
296 rb_fd_fix_cloexec(*slave);
297 if (no_mesg(SlaveName, nomesg) == -1) {
298 if (!fail) return -1;
299 rb_raise(rb_eRuntimeError, "can't chmod slave pty");
300 }
301
302 return 0;
303
304 #elif defined HAVE__GETPTY
305 /* SGI IRIX */
306 char *name;
307 mode_t mode = nomesg ? 0600 : 0622;
308
309 if (!(name = _getpty(master, O_RDWR, mode, 0))) {
310 if (!fail) return -1;
311 rb_raise(rb_eRuntimeError, "_getpty() failed");
312 }
313 rb_fd_fix_cloexec(*master);
314
315 *slave = rb_cloexec_open(name, O_RDWR, 0);
316 /* error check? */
317 rb_update_max_fd(*slave);
318 strlcpy(SlaveName, name, DEVICELEN);
319
320 return 0;
321 #elif defined(HAVE_PTSNAME)
322 /* System V */
323 int masterfd = -1, slavefd = -1;
324 char *slavedevice;
325 void (*s)();
326
327 extern char *ptsname(int);
328 extern int unlockpt(int);
329 extern int grantpt(int);
330
331 #if defined(__sun)
332 /* workaround for Solaris 10: grantpt() doesn't work if FD_CLOEXEC is set. [ruby-dev:44688] */
333 if((masterfd = open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
334 s = signal(SIGCHLD, SIG_DFL);
335 if(grantpt(masterfd) == -1) goto error;
336 rb_fd_fix_cloexec(masterfd);
337 #else
338 if((masterfd = rb_cloexec_open("/dev/ptmx", O_RDWR, 0)) == -1) goto error;
339 rb_update_max_fd(masterfd);
340 s = signal(SIGCHLD, SIG_DFL);
341 if(grantpt(masterfd) == -1) goto error;
342 #endif
343 signal(SIGCHLD, s);
344 if(unlockpt(masterfd) == -1) goto error;
345 if((slavedevice = ptsname(masterfd)) == NULL) goto error;
346 if (no_mesg(slavedevice, nomesg) == -1) goto error;
347 if((slavefd = rb_cloexec_open(slavedevice, O_RDWR, 0)) == -1) goto error;
348 rb_update_max_fd(slavefd);
349 #if defined(I_PUSH) && !defined(__linux__)
350 if(ioctl(slavefd, I_PUSH, "ptem") == -1) goto error;
351 if(ioctl(slavefd, I_PUSH, "ldterm") == -1) goto error;
352 ioctl(slavefd, I_PUSH, "ttcompat");
353 #endif
354 *master = masterfd;
355 *slave = slavefd;
356 strlcpy(SlaveName, slavedevice, DEVICELEN);
357 return 0;
358
359 error:
360 if (slavefd != -1) close(slavefd);
361 if (masterfd != -1) close(masterfd);
362 if (fail) rb_raise(rb_eRuntimeError, "can't get Master/Slave device");
363 return -1;
364 #else
365 /* BSD */
366 int masterfd = -1, slavefd = -1;
367 const char *const *p;
368 char MasterName[DEVICELEN];
369
370 #if defined(__hpux)
371 static const char MasterDevice[] = "/dev/ptym/pty%s";
372 static const char SlaveDevice[] = "/dev/pty/tty%s";
373 static const char *const deviceNo[] = {
374 "p0","p1","p2","p3","p4","p5","p6","p7",
375 "p8","p9","pa","pb","pc","pd","pe","pf",
376 "q0","q1","q2","q3","q4","q5","q6","q7",
377 "q8","q9","qa","qb","qc","qd","qe","qf",
378 "r0","r1","r2","r3","r4","r5","r6","r7",
379 "r8","r9","ra","rb","rc","rd","re","rf",
380 "s0","s1","s2","s3","s4","s5","s6","s7",
381 "s8","s9","sa","sb","sc","sd","se","sf",
382 "t0","t1","t2","t3","t4","t5","t6","t7",
383 "t8","t9","ta","tb","tc","td","te","tf",
384 "u0","u1","u2","u3","u4","u5","u6","u7",
385 "u8","u9","ua","ub","uc","ud","ue","uf",
386 "v0","v1","v2","v3","v4","v5","v6","v7",
387 "v8","v9","va","vb","vc","vd","ve","vf",
388 "w0","w1","w2","w3","w4","w5","w6","w7",
389 "w8","w9","wa","wb","wc","wd","we","wf",
390 0
391 };
392 #elif defined(_IBMESA) /* AIX/ESA */
393 static const char MasterDevice[] = "/dev/ptyp%s";
394 static const char SlaveDevice[] = "/dev/ttyp%s";
395 static const char *const deviceNo[] = {
396 "00","01","02","03","04","05","06","07","08","09","0a","0b","0c","0d","0e","0f",
397 "10","11","12","13","14","15","16","17","18","19","1a","1b","1c","1d","1e","1f",
398 "20","21","22","23","24","25","26","27","28","29","2a","2b","2c","2d","2e","2f",
399 "30","31","32","33","34","35","36","37","38","39","3a","3b","3c","3d","3e","3f",
400 "40","41","42","43","44","45","46","47","48","49","4a","4b","4c","4d","4e","4f",
401 "50","51","52","53","54","55","56","57","58","59","5a","5b","5c","5d","5e","5f",
402 "60","61","62","63","64","65","66","67","68","69","6a","6b","6c","6d","6e","6f",
403 "70","71","72","73","74","75","76","77","78","79","7a","7b","7c","7d","7e","7f",
404 "80","81","82","83","84","85","86","87","88","89","8a","8b","8c","8d","8e","8f",
405 "90","91","92","93","94","95","96","97","98","99","9a","9b","9c","9d","9e","9f",
406 "a0","a1","a2","a3","a4","a5","a6","a7","a8","a9","aa","ab","ac","ad","ae","af",
407 "b0","b1","b2","b3","b4","b5","b6","b7","b8","b9","ba","bb","bc","bd","be","bf",
408 "c0","c1","c2","c3","c4","c5","c6","c7","c8","c9","ca","cb","cc","cd","ce","cf",
409 "d0","d1","d2","d3","d4","d5","d6","d7","d8","d9","da","db","dc","dd","de","df",
410 "e0","e1","e2","e3","e4","e5","e6","e7","e8","e9","ea","eb","ec","ed","ee","ef",
411 "f0","f1","f2","f3","f4","f5","f6","f7","f8","f9","fa","fb","fc","fd","fe","ff",
412 0
413 };
414 #else /* 4.2BSD */
415 static const char MasterDevice[] = "/dev/pty%s";
416 static const char SlaveDevice[] = "/dev/tty%s";
417 static const char *const deviceNo[] = {
418 "p0","p1","p2","p3","p4","p5","p6","p7",
419 "p8","p9","pa","pb","pc","pd","pe","pf",
420 "q0","q1","q2","q3","q4","q5","q6","q7",
421 "q8","q9","qa","qb","qc","qd","qe","qf",
422 "r0","r1","r2","r3","r4","r5","r6","r7",
423 "r8","r9","ra","rb","rc","rd","re","rf",
424 "s0","s1","s2","s3","s4","s5","s6","s7",
425 "s8","s9","sa","sb","sc","sd","se","sf",
426 0
427 };
428 #endif
429 for (p = deviceNo; *p != NULL; p++) {
430 snprintf(MasterName, sizeof MasterName, MasterDevice, *p);
431 if ((masterfd = rb_cloexec_open(MasterName,O_RDWR,0)) >= 0) {
432 rb_update_max_fd(masterfd);
433 *master = masterfd;
434 snprintf(SlaveName, DEVICELEN, SlaveDevice, *p);
435 if ((slavefd = rb_cloexec_open(SlaveName,O_RDWR,0)) >= 0) {
436 rb_update_max_fd(slavefd);
437 *slave = slavefd;
438 if (chown(SlaveName, getuid(), getgid()) != 0) goto error;
439 if (chmod(SlaveName, nomesg ? 0600 : 0622) != 0) goto error;
440 return 0;
441 }
442 close(masterfd);
443 }
444 }
445 error:
446 if (slavefd != -1) close(slavefd);
447 if (masterfd != -1) close(masterfd);
448 if (fail) rb_raise(rb_eRuntimeError, "can't get %s", SlaveName);
449 return -1;
450 #endif
451 }
452
453 static void
454 getDevice(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg)
455 {
456 if (get_device_once(master, slave, SlaveName, nomesg, 0)) {
457 rb_gc();
458 get_device_once(master, slave, SlaveName, nomesg, 1);
459 }
460 }
461
462 static VALUE
463 pty_close_pty(VALUE assoc)
464 {
465 VALUE io;
466 int i;
467
468 for (i = 0; i < 2; i++) {
469 io = rb_ary_entry(assoc, i);
470 if (RB_TYPE_P(io, T_FILE) && 0 <= RFILE(io)->fptr->fd)
471 rb_io_close(io);
472 }
473 return Qnil;
474 }
475
476 /*
477 * call-seq:
478 * PTY.open => [master_io, slave_file]
479 * PTY.open {|master_io, slave_file| ... } => block value
480 *
481 * Allocates a pty (pseudo-terminal).
482 *
483 * In the block form, yields two arguments <tt>master_io, slave_file</tt>
484 * and the value of the block is returned from +open+.
485 *
486 * The IO and File are both closed after the block completes if they haven't
487 * been already closed.
488 *
489 * PTY.open {|master, slave|
490 * p master #=> #<IO:masterpty:/dev/pts/1>
491 * p slave #=> #<File:/dev/pts/1>
492 * p slave.path #=> "/dev/pts/1"
493 * }
494 *
495 * In the non-block form, returns a two element array, <tt>[master_io,
496 * slave_file]</tt>.
497 *
498 * master, slave = PTY.open
499 * # do something with master for IO, or the slave file
500 *
501 * The arguments in both forms are:
502 *
503 * +master_io+:: the master of the pty, as an IO.
504 * +slave_file+:: the slave of the pty, as a File. The path to the
505 * terminal device is available via +slave_file.path+
506 *
507 */
508 static VALUE
509 pty_open(VALUE klass)
510 {
511 int master_fd, slave_fd;
512 char slavename[DEVICELEN];
513 VALUE master_io, slave_file;
514 rb_io_t *master_fptr, *slave_fptr;
515 VALUE assoc;
516
517 getDevice(&master_fd, &slave_fd, slavename, 1);
518
519 master_io = rb_obj_alloc(rb_cIO);
520 MakeOpenFile(master_io, master_fptr);
521 master_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX;
522 master_fptr->fd = master_fd;
523 master_fptr->pathv = rb_obj_freeze(rb_sprintf("masterpty:%s", slavename));
524
525 slave_file = rb_obj_alloc(rb_cFile);
526 MakeOpenFile(slave_file, slave_fptr);
527 slave_fptr->mode = FMODE_READWRITE | FMODE_SYNC | FMODE_DUPLEX | FMODE_TTY;
528 slave_fptr->fd = slave_fd;
529 slave_fptr->pathv = rb_obj_freeze(rb_str_new_cstr(slavename));
530
531 assoc = rb_assoc_new(master_io, slave_file);
532 if (rb_block_given_p()) {
533 return rb_ensure(rb_yield, assoc, pty_close_pty, assoc);
534 }
535 return assoc;
536 }
537
538 static VALUE
539 pty_detach_process(struct pty_info *info)
540 {
541 rb_detach_process(info->child_pid);
542 return Qnil;
543 }
544
545 /*
546 * call-seq:
547 * PTY.spawn(command_line) { |r, w, pid| ... }
548 * PTY.spawn(command_line) => [r, w, pid]
549 * PTY.spawn(command, arguments, ...) { |r, w, pid| ... }
550 * PTY.spawn(command, arguments, ...) => [r, w, pid]
551 *
552 * Spawns the specified command on a newly allocated pty. You can also use the
553 * alias ::getpty.
554 *
555 * The command's controlling tty is set to the slave device of the pty
556 * and its standard input/output/error is redirected to the slave device.
557 *
558 * +command+ and +command_line+ are the full commands to run, given a String.
559 * Any additional +arguments+ will be passed to the command.
560 *
561 * === Return values
562 *
563 * In the non-block form this returns an array of size three,
564 * <tt>[r, w, pid]</tt>.
565 *
566 * In the block form these same values will be yielded to the block:
567 *
568 * +r+:: A readable IO that that contains the command's
569 * standard output and standard error
570 * +w+:: A writable IO that is the command's standard input
571 * +pid+:: The process identifier for the command.
572 */
573 static VALUE
574 pty_getpty(int argc, VALUE *argv, VALUE self)
575 {
576 VALUE res;
577 struct pty_info info;
578 rb_io_t *wfptr,*rfptr;
579 VALUE rport = rb_obj_alloc(rb_cFile);
580 VALUE wport = rb_obj_alloc(rb_cFile);
581 char SlaveName[DEVICELEN];
582
583 MakeOpenFile(rport, rfptr);
584 MakeOpenFile(wport, wfptr);
585
586 establishShell(argc, argv, &info, SlaveName);
587
588 rfptr->mode = rb_io_mode_flags("r");
589 rfptr->fd = info.fd;
590 rfptr->pathv = rb_obj_freeze(rb_str_new_cstr(SlaveName));
591
592 wfptr->mode = rb_io_mode_flags("w") | FMODE_SYNC;
593 wfptr->fd = rb_cloexec_dup(info.fd);
594 if (wfptr->fd == -1)
595 rb_sys_fail("dup()");
596 rb_update_max_fd(wfptr->fd);
597 wfptr->pathv = rfptr->pathv;
598
599 res = rb_ary_new2(3);
600 rb_ary_store(res,0,(VALUE)rport);
601 rb_ary_store(res,1,(VALUE)wport);
602 rb_ary_store(res,2,PIDT2NUM(info.child_pid));
603
604 if (rb_block_given_p()) {
605 rb_ensure(rb_yield, res, pty_detach_process, (VALUE)&info);
606 return Qnil;
607 }
608 return res;
609 }
610
611 NORETURN(static void raise_from_check(rb_pid_t pid, int status));
612 static void
613 raise_from_check(rb_pid_t pid, int status)
614 {
615 const char *state;
616 VALUE msg;
617 VALUE exc;
618
619 #if defined(WIFSTOPPED)
620 #elif defined(IF_STOPPED)
621 #define WIFSTOPPED(status) IF_STOPPED(status)
622 #else
623 ---->> Either IF_STOPPED or WIFSTOPPED is needed <<----
624 #endif /* WIFSTOPPED | IF_STOPPED */
625 if (WIFSTOPPED(status)) { /* suspend */
626 state = "stopped";
627 }
628 else if (kill(pid, 0) == 0) {
629 state = "changed";
630 }
631 else {
632 state = "exited";
633 }
634 msg = rb_sprintf("pty - %s: %ld", state, (long)pid);
635 exc = rb_exc_new_str(eChildExited, msg);
636 rb_iv_set(exc, "status", rb_last_status_get());
637 rb_exc_raise(exc);
638 }
639
640 /*
641 * call-seq:
642 * PTY.check(pid, raise = false) => Process::Status or nil
643 * PTY.check(pid, true) => nil or raises PTY::ChildExited
644 *
645 * Checks the status of the child process specified by +pid+.
646 * Returns +nil+ if the process is still alive.
647 *
648 * If the process is not alive, and +raise+ was true, a PTY::ChildExited
649 * exception will be raised. Otherwise it will return a Process::Status
650 * instance.
651 *
652 * +pid+:: The process id of the process to check
653 * +raise+:: If +true+ and the process identified by +pid+ is no longer
654 * alive a PTY::ChildExited is raised.
655 *
656 */
657 static VALUE
658 pty_check(int argc, VALUE *argv, VALUE self)
659 {
660 VALUE pid, exc;
661 rb_pid_t cpid;
662 int status;
663
664 rb_scan_args(argc, argv, "11", &pid, &exc);
665 cpid = rb_waitpid(NUM2PIDT(pid), &status, WNOHANG|WUNTRACED);
666 if (cpid == -1 || cpid == 0) return Qnil;
667
668 if (!RTEST(exc)) return rb_last_status_get();
669 raise_from_check(cpid, status);
670
671 UNREACHABLE;
672 }
673
674 static VALUE cPTY;
675
676 /*
677 * Document-class: PTY::ChildExited
678 *
679 * Thrown when PTY::check is called for a pid that represents a process that
680 * has exited.
681 */
682
683 /*
684 * Document-class: PTY
685 *
686 * Creates and managed pseudo terminals (PTYs). See also
687 * http://en.wikipedia.org/wiki/Pseudo_terminal
688 *
689 * PTY allows you to allocate new terminals using ::open or ::spawn a new
690 * terminal with a specific command.
691 *
692 * == Example
693 *
694 * In this example we will change the buffering type in the +factor+ command,
695 * assuming that factor uses stdio for stdout buffering.
696 *
697 * If IO.pipe is used instead of PTY.open, this code deadlocks because factor's
698 * stdout is fully buffered.
699 *
700 * # start by requiring the standard library PTY
701 * require 'pty'
702 *
703 * master, slave = PTY.open
704 * read, write = IO.pipe
705 * pid = spawn("factor", :in=>read, :out=>slave)
706 * read.close # we dont need the read
707 * slave.close # or the slave
708 *
709 * # pipe "42" to the factor command
710 * write.puts "42"
711 * # output the response from factor
712 * p master.gets #=> "42: 2 3 7\n"
713 *
714 * # pipe "144" to factor and print out the response
715 * write.puts "144"
716 * p master.gets #=> "144: 2 2 2 2 3 3\n"
717 * write.close # close the pipe
718 *
719 * # The result of read operation when pty slave is closed is platform
720 * # dependent.
721 * ret = begin
722 * m.gets # FreeBSD returns nil.
723 * rescue Errno::EIO # GNU/Linux raises EIO.
724 * nil
725 * end
726 * p ret #=> nil
727 *
728 * == License
729 *
730 * C) Copyright 1998 by Akinori Ito.
731 *
732 * This software may be redistributed freely for this purpose, in full
733 * or in part, provided that this entire copyright notice is included
734 * on any copies of this software and applications and derivations thereof.
735 *
736 * This software is provided on an "as is" basis, without warranty of any
737 * kind, either expressed or implied, as to any matter including, but not
738 * limited to warranty of fitness of purpose, or merchantability, or
739 * results obtained from use of this software.
740 */
741
742 void
743 Init_pty()
744 {
745 cPTY = rb_define_module("PTY");
746 /* :nodoc */
747 rb_define_module_function(cPTY,"getpty",pty_getpty,-1);
748 rb_define_module_function(cPTY,"spawn",pty_getpty,-1);
749 rb_define_singleton_method(cPTY,"check",pty_check,-1);
750 rb_define_singleton_method(cPTY,"open",pty_open,0);
751
752 eChildExited = rb_define_class_under(cPTY,"ChildExited",rb_eRuntimeError);
753 rb_define_method(eChildExited,"status",echild_status,0);
754 }
rb_gc
void rb_gc(void)
Definition: gc.c:5190
WNOHANG
#define WNOHANG
Definition: win32.h:125
child_info::slave
int slave
Definition: pty.c:83
pty_info::fd
int fd
Definition: pty.c:76
rb_ary_entry
VALUE rb_ary_entry(VALUE ary, long offset)
Definition: array.c:1171
child_info
Definition: pty.c:82
rb_detach_process
VALUE rb_detach_process(rb_pid_t pid)
Definition: process.c:1027
ioctl
int ioctl(int, int,...)
Definition: win32.c:2540
FMODE_READWRITE
#define FMODE_READWRITE
Definition: io.h:103
rb_update_max_fd
void rb_update_max_fd(int fd)
Definition: io.c:183
WIFSTOPPED
#define WIFSTOPPED(status)
Definition: pty.c:32
getuid
rb_uid_t getuid(void)
Definition: win32.c:2494
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:1655
pty_check
static VALUE pty_check(int argc, VALUE *argv, VALUE self)
Definition: pty.c:658
ruby.h
NUM2PIDT
#define NUM2PIDT(v)
Definition: ruby.h:324
rb_cloexec_open
int rb_cloexec_open(const char *pathname, int flags, mode_t mode)
Definition: io.c:228
child_info::master
int master
Definition: pty.c:83
PIDT2NUM
#define PIDT2NUM(v)
Definition: ruby.h:321
pty_close_pty
static VALUE pty_close_pty(VALUE assoc)
Definition: pty.c:463
rb_io_t
Definition: io.h:61
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:3104
rb_exc_new_str
VALUE rb_exc_new_str(VALUE etype, VALUE str)
Definition: error.c:585
UNREACHABLE
#define UNREACHABLE
Definition: ruby.h:42
rb_cFile
VALUE rb_cFile
Definition: file.c:139
kill
int kill(int, int)
Definition: win32.c:4439
rb_iv_set
VALUE rb_iv_set(VALUE, const char *, VALUE)
Definition: variable.c:2609
child_info::execarg_obj
VALUE execarg_obj
Definition: pty.c:85
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:676
rb_raise
void rb_raise(VALUE exc, const char *fmt,...)
Definition: error.c:1857
rb_ivar_get
VALUE rb_ivar_get(VALUE, ID)
Definition: variable.c:1115
get_device_once
static int get_device_once(int *master, int *slave, char SlaveName[DEVICELEN], int nomesg, int fail)
Definition: pty.c:223
RB_GC_GUARD
#define RB_GC_GUARD(v)
Definition: ruby.h:523
FMODE_DUPLEX
#define FMODE_DUPLEX
Definition: io.h:107
pty_open
static VALUE pty_open(VALUE klass)
Definition: pty.c:509
pty_info
Definition: pty.c:75
RFILE
#define RFILE(obj)
Definition: ruby.h:1129
establishShell
static void establishShell(int argc, VALUE *argv, struct pty_info *info, char SlaveName[DEVICELEN])
Definition: pty.c:155
io.h
getDevice
static void getDevice(int *, int *, char[DEVICELEN], int)
Definition: pty.c:454
rb_ary_new2
#define rb_ary_new2
Definition: intern.h:90
rb_io_t::mode
int mode
Definition: io.h:64
child_info::eargp
struct rb_execarg * eargp
Definition: pty.c:86
rb_exc_raise
void rb_exc_raise(VALUE mesg)
Definition: eval.c:567
RB_TYPE_P
#define RB_TYPE_P(obj, type)
Definition: ruby.h:1664
eChildExited
static VALUE eChildExited
Definition: pty.c:64
fail
#define fail()
Definition: date_strptime.c:118
O_CLOEXEC
#define O_CLOEXEC
rb_execarg_get
struct rb_execarg * rb_execarg_get(VALUE execarg_obj)
Definition: process.c:2272
rb_block_given_p
int rb_block_given_p(void)
Definition: eval.c:712
rb_eRuntimeError
VALUE rb_eRuntimeError
Definition: error.c:547
snprintf
#define snprintf
Definition: subst.h:6
msg
static char msg[50]
Definition: strerror.c:8
chown
int chown(const char *, int, int)
Definition: win32.c:4425
no_mesg
static int no_mesg(char *slavedevice, int nomesg)
Definition: pty.c:214
rb_io_t::fd
int fd
Definition: io.h:62
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)
rb_ary_store
void rb_ary_store(VALUE ary, long idx, VALUE val)
Definition: array.c:790
unistd.h
signal.h
argc
int argc
Definition: ruby.c:131
seteuid
int seteuid(pid_t pid)
rb_str_new2
#define rb_str_new2
Definition: intern.h:840
rb_obj_alloc
VALUE rb_obj_alloc(VALUE)
Definition: object.c:1801
rb_cIO
RUBY_EXTERN VALUE rb_cIO
Definition: ruby.h:1569
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:1670
rb_yield
VALUE rb_yield(VALUE)
Definition: vm_eval.c:942
errno
int errno
util.h
rb_sprintf
VALUE rb_sprintf(const char *format,...)
Definition: sprintf.c:1250
chfunc
static int chfunc(void *data, char *errbuf, size_t errbuf_len)
Definition: pty.c:90
cPTY
static VALUE cPTY
Definition: pty.c:674
Init_pty
void Init_pty()
Definition: pty.c:743
rb_execarg_fixup
void rb_execarg_fixup(VALUE execarg_obj)
Definition: process.c:2325
rb_scan_args
int rb_scan_args(int argc, const VALUE *argv, const char *fmt,...)
Definition: class.c:1728
pty_info::child_pid
rb_pid_t child_pid
Definition: pty.c:77
rb_assoc_new
VALUE rb_assoc_new(VALUE car, VALUE cdr)
Definition: array.c:616
internal.h
rb_execarg
Definition: internal.h:636
Qnil
#define Qnil
Definition: ruby.h:427
mode_t
#define mode_t
Definition: win32.h:116
rb_io_close
VALUE rb_io_close(VALUE)
Definition: io.c:4292
VALUE
unsigned long VALUE
Definition: ruby.h:88
strlcpy
RUBY_EXTERN size_t strlcpy(char *, const char *, size_t)
Definition: strlcpy.c:44
rb_ensure
VALUE rb_ensure(VALUE(*b_proc)(ANYARGS), VALUE data1, VALUE(*e_proc)(ANYARGS), VALUE data2)
Definition: eval.c:839
rb_str_new_cstr
VALUE rb_str_new_cstr(const char *)
Definition: string.c:560
rb_io_mode_flags
#define rb_io_mode_flags(modestr)
Definition: io.h:190
rb_sys_fail
void rb_sys_fail(const char *mesg)
Definition: error.c:1976
rb_jump_tag
void rb_jump_tag(int tag)
Definition: eval.c:706
NORETURN
NORETURN(static void raise_from_check(rb_pid_t pid, int status))
getenv
#define getenv(name)
Definition: win32.c:66
child_info::slavename
char * slavename
Definition: pty.c:84
pty_getpty
static VALUE pty_getpty(int argc, VALUE *argv, VALUE self)
Definition: pty.c:574
signal
sighandler_t signal(int signum, sighandler_t handler)
rb_fd_fix_cloexec
void rb_fd_fix_cloexec(int fd)
Definition: io.c:221
rb_io_t::pathv
VALUE pathv
Definition: io.h:67
RTEST
#define RTEST(v)
Definition: ruby.h:437
ERROR_EXIT
#define ERROR_EXIT(str)
T_FILE
#define T_FILE
Definition: ruby.h:488
DEVICELEN
#define DEVICELEN
Definition: pty.c:50
name
const char * name
Definition: nkf.c:208
raise_from_check
static void raise_from_check(rb_pid_t pid, int status)
Definition: pty.c:613
echild_status
static VALUE echild_status(VALUE self)
Definition: pty.c:70
FMODE_SYNC
#define FMODE_SYNC
Definition: io.h:105
FMODE_TTY
#define FMODE_TTY
Definition: io.h:106
MakeOpenFile
#define MakeOpenFile(obj, fp)
Definition: io.h:127
dup2
RUBY_EXTERN int dup2(int, int)
Definition: dup2.c:27
pty_detach_process
static VALUE pty_detach_process(struct pty_info *info)
Definition: pty.c:539
rb_cloexec_dup
int rb_cloexec_dup(int oldfd)
Definition: io.c:244
getgid
rb_gid_t getgid(void)
Definition: win32.c:2508
rb_execarg_new
VALUE rb_execarg_new(int argc, VALUE *argv, int accept_shell)
Definition: process.c:2261
rb_obj_freeze
VALUE rb_obj_freeze(VALUE)
Definition: object.c:1076
rb_define_module
VALUE rb_define_module(const char *name)
Definition: class.c:746
rb_intern
#define rb_intern(str)
rb_last_status_get
VALUE rb_last_status_get(void)
Definition: process.c:321
NULL
#define NULL
Definition: _sdbm.c:103
rb_waitpid
rb_pid_t rb_waitpid(rb_pid_t pid, int *status, int flags)
Definition: process.c:758
rb_define_method
void rb_define_method(VALUE klass, const char *name, VALUE(*func)(ANYARGS), int argc)
Definition: class.c:1488
argv
char ** argv
Definition: ruby.c:132