1 /*
2 ** io.c - IO class
3 */
4 
5 #include "mruby.h"
6 #include "mruby/array.h"
7 #include "mruby/class.h"
8 #include "mruby/data.h"
9 #include "mruby/hash.h"
10 #include "mruby/string.h"
11 #include "mruby/variable.h"
12 #include "mruby/ext/io.h"
13 
14 #if MRUBY_RELEASE_NO < 10000
15 #include "error.h"
16 #else
17 #include "mruby/error.h"
18 #endif
19 
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 
23 #if defined(_WIN32) || defined(_WIN64)
24   #include <winsock.h>
25   #include <io.h>
26   #define open  _open
27   #define close _close
28   #define dup _dup
29   #define dup2 _dup2
30   #define read  _read
31   #define write _write
32   #define lseek _lseek
33   #define isatty _isatty
34   #define WEXITSTATUS(x) (x)
35   typedef int fsize_t;
36   typedef long ftime_t;
37   typedef long fsuseconds_t;
38   typedef int fmode_t;
39 
40 #else
41   #include <sys/wait.h>
42   #include <unistd.h>
43   typedef size_t fsize_t;
44   typedef time_t ftime_t;
45   typedef suseconds_t fsuseconds_t;
46   typedef mode_t fmode_t;
47 #endif
48 
49 #ifdef _MSC_VER
50 typedef mrb_int pid_t;
51 #endif
52 
53 #include <fcntl.h>
54 
55 #include <errno.h>
56 #include <stdio.h>
57 #include <string.h>
58 
59 
60 static void mrb_io_free(mrb_state *mrb, void *ptr);
61 struct mrb_data_type mrb_io_type = { "IO", mrb_io_free };
62 
63 
64 static struct mrb_io *io_get_open_fptr(mrb_state *mrb, mrb_value self);
65 static int mrb_io_modestr_to_flags(mrb_state *mrb, const char *modestr);
66 static int mrb_io_flags_to_modenum(mrb_state *mrb, int flags);
67 static void fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet);
68 
69 #if MRUBY_RELEASE_NO < 10000
70 static struct RClass *
mrb_module_get(mrb_state * mrb,const char * name)71 mrb_module_get(mrb_state *mrb, const char *name)
72 {
73   return mrb_class_get(mrb, name);
74 }
75 #endif
76 
77 static struct mrb_io *
io_get_open_fptr(mrb_state * mrb,mrb_value self)78 io_get_open_fptr(mrb_state *mrb, mrb_value self)
79 {
80   struct mrb_io *fptr;
81 
82   fptr = (struct mrb_io *)mrb_get_datatype(mrb, self, &mrb_io_type);
83   if (fptr == NULL) {
84     mrb_raise(mrb, E_IO_ERROR, "uninitialized stream.");
85   }
86   if (fptr->fd < 0) {
87     mrb_raise(mrb, E_IO_ERROR, "closed stream.");
88   }
89   return fptr;
90 }
91 
92 static void
io_set_process_status(mrb_state * mrb,pid_t pid,int status)93 io_set_process_status(mrb_state *mrb, pid_t pid, int status)
94 {
95   struct RClass *c_process, *c_status;
96   mrb_value v;
97 
98   c_status = NULL;
99   if (mrb_class_defined(mrb, "Process")) {
100     c_process = mrb_module_get(mrb, "Process");
101     if (mrb_const_defined(mrb, mrb_obj_value(c_process), mrb_intern_cstr(mrb, "Status"))) {
102       c_status = mrb_class_get_under(mrb, c_process, "Status");
103     }
104   }
105   if (c_status != NULL) {
106     v = mrb_funcall(mrb, mrb_obj_value(c_status), "new", 2, mrb_fixnum_value(pid), mrb_fixnum_value(status));
107   } else {
108     v = mrb_fixnum_value(WEXITSTATUS(status));
109   }
110   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$?"), v);
111 }
112 
113 static int
mrb_io_modestr_to_flags(mrb_state * mrb,const char * mode)114 mrb_io_modestr_to_flags(mrb_state *mrb, const char *mode)
115 {
116   int flags = 0;
117   const char *m = mode;
118 
119   switch (*m++) {
120     case 'r':
121       flags |= FMODE_READABLE;
122       break;
123     case 'w':
124       flags |= FMODE_WRITABLE | FMODE_CREATE | FMODE_TRUNC;
125       break;
126     case 'a':
127       flags |= FMODE_WRITABLE | FMODE_APPEND | FMODE_CREATE;
128       break;
129     default:
130       mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode));
131   }
132 
133   while (*m) {
134     switch (*m++) {
135       case 'b':
136         flags |= FMODE_BINMODE;
137         break;
138       case '+':
139         flags |= FMODE_READWRITE;
140         break;
141       case ':':
142         /* XXX: PASSTHROUGH*/
143       default:
144         mrb_raisef(mrb, E_ARGUMENT_ERROR, "illegal access mode %S", mrb_str_new_cstr(mrb, mode));
145     }
146   }
147 
148   return flags;
149 }
150 
151 static int
mrb_io_flags_to_modenum(mrb_state * mrb,int flags)152 mrb_io_flags_to_modenum(mrb_state *mrb, int flags)
153 {
154   int modenum = 0;
155 
156   switch(flags & (FMODE_READABLE|FMODE_WRITABLE|FMODE_READWRITE)) {
157     case FMODE_READABLE:
158       modenum = O_RDONLY;
159       break;
160     case FMODE_WRITABLE:
161       modenum = O_WRONLY;
162       break;
163     case FMODE_READWRITE:
164       modenum = O_RDWR;
165       break;
166   }
167 
168   if (flags & FMODE_APPEND) {
169     modenum |= O_APPEND;
170   }
171   if (flags & FMODE_TRUNC) {
172     modenum |= O_TRUNC;
173   }
174   if (flags & FMODE_CREATE) {
175     modenum |= O_CREAT;
176   }
177 #ifdef O_BINARY
178   if (flags & FMODE_BINMODE) {
179     modenum |= O_BINARY;
180   }
181 #endif
182 
183   return modenum;
184 }
185 
186 static void
mrb_fd_cloexec(mrb_state * mrb,int fd)187 mrb_fd_cloexec(mrb_state *mrb, int fd)
188 {
189 #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
190   int flags, flags2;
191 
192   flags = fcntl(fd, F_GETFD);
193   if (flags == -1) {
194     mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_GETFD) failed: %S",
195       mrb_fixnum_value(fd), mrb_fixnum_value(errno));
196   }
197   if (fd <= 2) {
198     flags2 = flags & ~FD_CLOEXEC; /* Clear CLOEXEC for standard file descriptors: 0, 1, 2. */
199   }
200   else {
201     flags2 = flags | FD_CLOEXEC; /* Set CLOEXEC for non-standard file descriptors: 3, 4, 5, ... */
202   }
203   if (flags != flags2) {
204     if (fcntl(fd, F_SETFD, flags2) == -1) {
205       mrb_bug(mrb, "mrb_fd_cloexec: fcntl(%S, F_SETFD, %S) failed: %S",
206         mrb_fixnum_value(fd), mrb_fixnum_value(flags2), mrb_fixnum_value(errno));
207     }
208   }
209 #endif
210 }
211 
212 #if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
213 static int
mrb_cloexec_pipe(mrb_state * mrb,int fildes[2])214 mrb_cloexec_pipe(mrb_state *mrb, int fildes[2])
215 {
216   int ret;
217   ret = pipe(fildes);
218   if (ret == -1)
219     return -1;
220   mrb_fd_cloexec(mrb, fildes[0]);
221   mrb_fd_cloexec(mrb, fildes[1]);
222   return ret;
223 }
224 
225 static int
mrb_pipe(mrb_state * mrb,int pipes[2])226 mrb_pipe(mrb_state *mrb, int pipes[2])
227 {
228   int ret;
229   ret = mrb_cloexec_pipe(mrb, pipes);
230   if (ret == -1) {
231     if (errno == EMFILE || errno == ENFILE) {
232       mrb_garbage_collect(mrb);
233       ret = mrb_cloexec_pipe(mrb, pipes);
234     }
235   }
236   return ret;
237 }
238 
239 static int
mrb_proc_exec(const char * pname)240 mrb_proc_exec(const char *pname)
241 {
242   const char *s;
243   s = pname;
244 
245   while (*s == ' ' || *s == '\t' || *s == '\n')
246     s++;
247 
248   if (!*s) {
249     errno = ENOENT;
250     return -1;
251   }
252 
253   execl("/bin/sh", "sh", "-c", pname, (char *)NULL);
254   return -1;
255 }
256 #endif
257 
258 static void
mrb_io_free(mrb_state * mrb,void * ptr)259 mrb_io_free(mrb_state *mrb, void *ptr)
260 {
261   struct mrb_io *io = (struct mrb_io *)ptr;
262   if (io != NULL) {
263     fptr_finalize(mrb, io, TRUE);
264     mrb_free(mrb, io);
265   }
266 }
267 
268 static struct mrb_io *
mrb_io_alloc(mrb_state * mrb)269 mrb_io_alloc(mrb_state *mrb)
270 {
271   struct mrb_io *fptr;
272 
273   fptr = (struct mrb_io *)mrb_malloc(mrb, sizeof(struct mrb_io));
274   fptr->fd = -1;
275   fptr->fd2 = -1;
276   fptr->pid = 0;
277   fptr->readable = 0;
278   fptr->writable = 0;
279   fptr->sync = 0;
280   fptr->is_socket = 0;
281   return fptr;
282 }
283 
284 #ifndef NOFILE
285 #define NOFILE 64
286 #endif
287 
288 static int
option_to_fd(mrb_state * mrb,mrb_value obj,const char * key)289 option_to_fd(mrb_state *mrb, mrb_value obj, const char *key)
290 {
291   mrb_value opt = mrb_funcall(mrb, obj, "[]", 1, mrb_symbol_value(mrb_intern_static(mrb, key, strlen(key))));
292   if (mrb_nil_p(opt)) {
293     return -1;
294   }
295 
296   switch (mrb_type(opt)) {
297     case MRB_TT_DATA: /* IO */
298       return (int)mrb_fixnum(mrb_io_fileno(mrb, opt));
299     case MRB_TT_FIXNUM:
300       return (int)mrb_fixnum(opt);
301     default:
302       mrb_raise(mrb, E_ARGUMENT_ERROR, "wrong exec redirect action");
303       break;
304   }
305   return -1; /* never reached */
306 }
307 
308 #ifdef _WIN32
309 mrb_value
mrb_io_s_popen(mrb_state * mrb,mrb_value klass)310 mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
311 {
312   mrb_value cmd, io;
313   mrb_value mode = mrb_str_new_cstr(mrb, "r");
314   mrb_value opt  = mrb_hash_new(mrb);
315 
316   struct mrb_io *fptr;
317   const char *pname;
318   int pid = 0, flags;
319   STARTUPINFO si;
320   PROCESS_INFORMATION pi;
321   SECURITY_ATTRIBUTES saAttr;
322 
323   HANDLE ifd[2];
324   HANDLE ofd[2];
325 
326   int doexec;
327   int opt_in, opt_out, opt_err;
328 
329   ifd[0] = INVALID_HANDLE_VALUE;
330   ifd[1] = INVALID_HANDLE_VALUE;
331   ofd[0] = INVALID_HANDLE_VALUE;
332   ofd[1] = INVALID_HANDLE_VALUE;
333 
334   mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
335   io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
336 
337   pname = mrb_string_value_cstr(mrb, &cmd);
338   flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
339 
340   doexec = (strcmp("-", pname) != 0);
341   opt_in = option_to_fd(mrb, opt, "in");
342   opt_out = option_to_fd(mrb, opt, "out");
343   opt_err = option_to_fd(mrb, opt, "err");
344 
345   saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
346   saAttr.bInheritHandle = TRUE;
347   saAttr.lpSecurityDescriptor = NULL;
348 
349   if (flags & FMODE_READABLE) {
350     if (!CreatePipe(&ofd[0], &ofd[1], &saAttr, 0)
351         || !SetHandleInformation(ofd[0], HANDLE_FLAG_INHERIT, 0)) {
352       mrb_sys_fail(mrb, "pipe");
353     }
354   }
355 
356   if (flags & FMODE_WRITABLE) {
357     if (!CreatePipe(&ifd[0], &ifd[1], &saAttr, 0)
358         || !SetHandleInformation(ifd[1], HANDLE_FLAG_INHERIT, 0)) {
359       mrb_sys_fail(mrb, "pipe");
360     }
361   }
362 
363   if (doexec) {
364     ZeroMemory(&pi, sizeof(pi));
365     ZeroMemory(&si, sizeof(si));
366     si.cb = sizeof(si);
367     si.dwFlags |= STARTF_USESHOWWINDOW;
368     si.wShowWindow = SW_HIDE;
369     si.dwFlags |= STARTF_USESTDHANDLES;
370     if (flags & FMODE_READABLE) {
371       si.hStdOutput = ofd[1];
372       si.hStdError = ofd[1];
373     }
374     if (flags & FMODE_WRITABLE) {
375       si.hStdInput = ifd[0];
376     }
377     if (!CreateProcess(
378         NULL, (char*)pname, NULL, NULL,
379         TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi)) {
380       CloseHandle(ifd[0]);
381       CloseHandle(ifd[1]);
382       CloseHandle(ofd[0]);
383       CloseHandle(ofd[1]);
384       mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
385     }
386     CloseHandle(pi.hThread);
387     CloseHandle(ifd[0]);
388     CloseHandle(ofd[1]);
389     pid = pi.dwProcessId;
390   }
391 
392   mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
393 
394   fptr = mrb_io_alloc(mrb);
395   fptr->fd = _open_osfhandle((intptr_t)ofd[0], 0);
396   fptr->fd2 = _open_osfhandle((intptr_t)ifd[1], 0);
397   fptr->pid = pid;
398   fptr->readable = ((flags & FMODE_READABLE) != 0);
399   fptr->writable = ((flags & FMODE_WRITABLE) != 0);
400   fptr->sync = 0;
401 
402   DATA_TYPE(io) = &mrb_io_type;
403   DATA_PTR(io)  = fptr;
404   return io;
405 }
406 #elif defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE
407 mrb_value
mrb_io_s_popen(mrb_state * mrb,mrb_value klass)408 mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
409 {
410   mrb_raise(mrb, E_NOTIMP_ERROR, "IO#popen is not supported on the platform");
411   return mrb_false_value();
412 }
413 #else
414 mrb_value
mrb_io_s_popen(mrb_state * mrb,mrb_value klass)415 mrb_io_s_popen(mrb_state *mrb, mrb_value klass)
416 {
417   mrb_value cmd, io, result;
418   mrb_value mode = mrb_str_new_cstr(mrb, "r");
419   mrb_value opt  = mrb_hash_new(mrb);
420 
421   struct mrb_io *fptr;
422   const char *pname;
423   int pid, flags, fd, write_fd = -1;
424   int pr[2] = { -1, -1 };
425   int pw[2] = { -1, -1 };
426   int doexec;
427   int saved_errno;
428   int opt_in, opt_out, opt_err;
429 
430   mrb_get_args(mrb, "S|SH", &cmd, &mode, &opt);
431   io = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
432 
433   pname = mrb_string_value_cstr(mrb, &cmd);
434   flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
435 
436   doexec = (strcmp("-", pname) != 0);
437   opt_in = option_to_fd(mrb, opt, "in");
438   opt_out = option_to_fd(mrb, opt, "out");
439   opt_err = option_to_fd(mrb, opt, "err");
440 
441   if (flags & FMODE_READABLE) {
442     if (pipe(pr) == -1) {
443       mrb_sys_fail(mrb, "pipe");
444     }
445     mrb_fd_cloexec(mrb, pr[0]);
446     mrb_fd_cloexec(mrb, pr[1]);
447   }
448 
449   if (flags & FMODE_WRITABLE) {
450     if (pipe(pw) == -1) {
451       if (pr[0] != -1) close(pr[0]);
452       if (pr[1] != -1) close(pr[1]);
453       mrb_sys_fail(mrb, "pipe");
454     }
455     mrb_fd_cloexec(mrb, pw[0]);
456     mrb_fd_cloexec(mrb, pw[1]);
457   }
458 
459   if (!doexec) {
460     // XXX
461     fflush(stdin);
462     fflush(stdout);
463     fflush(stderr);
464   }
465 
466   result = mrb_nil_value();
467   switch (pid = fork()) {
468     case 0: /* child */
469       if (opt_in != -1) {
470         dup2(opt_in, 0);
471       }
472       if (opt_out != -1) {
473         dup2(opt_out, 1);
474       }
475       if (opt_err != -1) {
476         dup2(opt_err, 2);
477       }
478       if (flags & FMODE_READABLE) {
479         close(pr[0]);
480         if (pr[1] != 1) {
481           dup2(pr[1], 1);
482           close(pr[1]);
483         }
484       }
485       if (flags & FMODE_WRITABLE) {
486         close(pw[1]);
487         if (pw[0] != 0) {
488           dup2(pw[0], 0);
489           close(pw[0]);
490         }
491       }
492       if (doexec) {
493         for (fd = 3; fd < NOFILE; fd++) {
494           close(fd);
495         }
496         mrb_proc_exec(pname);
497         mrb_raisef(mrb, E_IO_ERROR, "command not found: %S", cmd);
498         _exit(127);
499       }
500       result = mrb_nil_value();
501       break;
502 
503     default: /* parent */
504       if ((flags & FMODE_READABLE) && (flags & FMODE_WRITABLE)) {
505         close(pr[1]);
506         fd = pr[0];
507         close(pw[0]);
508         write_fd = pw[1];
509       } else if (flags & FMODE_READABLE) {
510         close(pr[1]);
511         fd = pr[0];
512       } else {
513         close(pw[0]);
514         fd = pw[1];
515       }
516 
517       mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
518 
519       fptr = mrb_io_alloc(mrb);
520       fptr->fd = fd;
521       fptr->fd2 = write_fd;
522       fptr->pid = pid;
523       fptr->readable = ((flags & FMODE_READABLE) != 0);
524       fptr->writable = ((flags & FMODE_WRITABLE) != 0);
525       fptr->sync = 0;
526 
527       DATA_TYPE(io) = &mrb_io_type;
528       DATA_PTR(io)  = fptr;
529       result = io;
530       break;
531 
532     case -1: /* error */
533       saved_errno = errno;
534       if (flags & FMODE_READABLE) {
535         close(pr[0]);
536         close(pr[1]);
537       }
538       if (flags & FMODE_WRITABLE) {
539         close(pw[0]);
540         close(pw[1]);
541       }
542       errno = saved_errno;
543       mrb_sys_fail(mrb, "pipe_open failed.");
544       break;
545   }
546   return result;
547 }
548 #endif
549 
550 static int
mrb_dup(mrb_state * mrb,int fd,mrb_bool * failed)551 mrb_dup(mrb_state *mrb, int fd, mrb_bool *failed)
552 {
553   int new_fd;
554 
555   *failed = TRUE;
556   if (fd < 0)
557     return fd;
558 
559   new_fd = dup(fd);
560   if (new_fd > 0) *failed = FALSE;
561   return new_fd;
562 }
563 
564 mrb_value
mrb_io_initialize_copy(mrb_state * mrb,mrb_value copy)565 mrb_io_initialize_copy(mrb_state *mrb, mrb_value copy)
566 {
567   mrb_value orig;
568   mrb_value buf;
569   struct mrb_io *fptr_copy;
570   struct mrb_io *fptr_orig;
571   mrb_bool failed = TRUE;
572 
573   mrb_get_args(mrb, "o", &orig);
574   fptr_orig = io_get_open_fptr(mrb, orig);
575   fptr_copy = (struct mrb_io *)DATA_PTR(copy);
576   if (fptr_orig == fptr_copy) return copy;
577   if (fptr_copy != NULL) {
578     fptr_finalize(mrb, fptr_copy, FALSE);
579     mrb_free(mrb, fptr_copy);
580   }
581   fptr_copy = (struct mrb_io *)mrb_io_alloc(mrb);
582 
583   DATA_TYPE(copy) = &mrb_io_type;
584   DATA_PTR(copy) = fptr_copy;
585 
586   buf = mrb_iv_get(mrb, orig, mrb_intern_cstr(mrb, "@buf"));
587   mrb_iv_set(mrb, copy, mrb_intern_cstr(mrb, "@buf"), buf);
588 
589   fptr_copy->fd = mrb_dup(mrb, fptr_orig->fd, &failed);
590   if (failed) {
591     mrb_sys_fail(mrb, 0);
592   }
593   mrb_fd_cloexec(mrb, fptr_copy->fd);
594 
595   if (fptr_orig->fd2 != -1) {
596     fptr_copy->fd2 = mrb_dup(mrb, fptr_orig->fd2, &failed);
597     if (failed) {
598       close(fptr_copy->fd);
599       mrb_sys_fail(mrb, 0);
600     }
601     mrb_fd_cloexec(mrb, fptr_copy->fd2);
602   }
603 
604   fptr_copy->pid = fptr_orig->pid;
605   fptr_copy->readable = fptr_orig->readable;
606   fptr_copy->writable = fptr_orig->writable;
607   fptr_copy->sync = fptr_orig->sync;
608   fptr_copy->is_socket = fptr_orig->is_socket;
609 
610   return copy;
611 }
612 
613 mrb_value
mrb_io_initialize(mrb_state * mrb,mrb_value io)614 mrb_io_initialize(mrb_state *mrb, mrb_value io)
615 {
616   struct mrb_io *fptr;
617   mrb_int fd;
618   mrb_value mode, opt;
619   int flags;
620 
621   mode = opt = mrb_nil_value();
622 
623   mrb_get_args(mrb, "i|So", &fd, &mode, &opt);
624   if (mrb_nil_p(mode)) {
625     mode = mrb_str_new_cstr(mrb, "r");
626   }
627   if (mrb_nil_p(opt)) {
628     opt = mrb_hash_new(mrb);
629   }
630 
631   flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
632 
633   mrb_iv_set(mrb, io, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
634 
635   fptr = (struct mrb_io *)DATA_PTR(io);
636   if (fptr != NULL) {
637     fptr_finalize(mrb, fptr, TRUE);
638     mrb_free(mrb, fptr);
639   }
640   fptr = mrb_io_alloc(mrb);
641 
642   DATA_TYPE(io) = &mrb_io_type;
643   DATA_PTR(io) = fptr;
644 
645   fptr->fd = (int)fd;
646   fptr->readable = ((flags & FMODE_READABLE) != 0);
647   fptr->writable = ((flags & FMODE_WRITABLE) != 0);
648   fptr->sync = 0;
649   return io;
650 }
651 
652 static void
fptr_finalize(mrb_state * mrb,struct mrb_io * fptr,int quiet)653 fptr_finalize(mrb_state *mrb, struct mrb_io *fptr, int quiet)
654 {
655   int saved_errno = 0;
656 
657   if (fptr == NULL) {
658     return;
659   }
660 
661   if (fptr->fd > 2) {
662 #ifdef _WIN32
663     if (fptr->is_socket) {
664       if (closesocket(fptr->fd) != 0) {
665         saved_errno = WSAGetLastError();
666       }
667       fptr->fd = -1;
668     }
669 #endif
670     if (fptr->fd != -1) {
671       if (close(fptr->fd) == -1) {
672         saved_errno = errno;
673       }
674     }
675     fptr->fd = -1;
676   }
677 
678   if (fptr->fd2 > 2) {
679     if (close(fptr->fd2) == -1) {
680       if (saved_errno == 0) {
681         saved_errno = errno;
682       }
683     }
684     fptr->fd2 = -1;
685   }
686 
687   if (fptr->pid != 0) {
688 #if !defined(_WIN32) && !defined(_WIN64)
689     pid_t pid;
690     int status;
691     do {
692       pid = waitpid(fptr->pid, &status, 0);
693     } while (pid == -1 && errno == EINTR);
694     if (!quiet && pid == fptr->pid) {
695       io_set_process_status(mrb, pid, status);
696     }
697 #else
698     HANDLE h = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, fptr->pid);
699     DWORD status;
700     if (WaitForSingleObject(h, INFINITE) && GetExitCodeProcess(h, &status))
701       if (!quiet)
702         io_set_process_status(mrb, fptr->pid, (int)status);
703     CloseHandle(h);
704 #endif
705     fptr->pid = 0;
706     /* Note: we don't raise an exception when waitpid(3) fails */
707   }
708 
709   if (!quiet && saved_errno != 0) {
710     errno = saved_errno;
711     mrb_sys_fail(mrb, "fptr_finalize failed.");
712   }
713 }
714 
715 mrb_value
mrb_io_check_readable(mrb_state * mrb,mrb_value self)716 mrb_io_check_readable(mrb_state *mrb, mrb_value self)
717 {
718   struct mrb_io *fptr = io_get_open_fptr(mrb, self);
719   if (! fptr->readable) {
720     mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
721   }
722   return mrb_nil_value();
723 }
724 
725 mrb_value
mrb_io_isatty(mrb_state * mrb,mrb_value self)726 mrb_io_isatty(mrb_state *mrb, mrb_value self)
727 {
728   struct mrb_io *fptr;
729 
730   fptr = io_get_open_fptr(mrb, self);
731   if (isatty(fptr->fd) == 0)
732     return mrb_false_value();
733   return mrb_true_value();
734 }
735 
736 mrb_value
mrb_io_s_for_fd(mrb_state * mrb,mrb_value klass)737 mrb_io_s_for_fd(mrb_state *mrb, mrb_value klass)
738 {
739   struct RClass *c = mrb_class_ptr(klass);
740   enum mrb_vtype ttype = MRB_INSTANCE_TT(c);
741   mrb_value obj;
742 
743   /* copied from mrb_instance_alloc() */
744   if (ttype == 0) ttype = MRB_TT_OBJECT;
745   obj = mrb_obj_value((struct RObject*)mrb_obj_alloc(mrb, ttype, c));
746   return mrb_io_initialize(mrb, obj);
747 }
748 
749 mrb_value
mrb_io_s_sysclose(mrb_state * mrb,mrb_value klass)750 mrb_io_s_sysclose(mrb_state *mrb, mrb_value klass)
751 {
752   mrb_int fd;
753   mrb_get_args(mrb, "i", &fd);
754   if (close((int)fd) == -1) {
755     mrb_sys_fail(mrb, "close");
756   }
757   return mrb_fixnum_value(0);
758 }
759 
760 int
mrb_cloexec_open(mrb_state * mrb,const char * pathname,mrb_int flags,mrb_int mode)761 mrb_cloexec_open(mrb_state *mrb, const char *pathname, mrb_int flags, mrb_int mode)
762 {
763   mrb_value emsg;
764   int fd, retry = FALSE;
765   char* fname = mrb_locale_from_utf8(pathname, -1);
766 
767 #ifdef O_CLOEXEC
768   /* O_CLOEXEC is available since Linux 2.6.23.  Linux 2.6.18 silently ignore it. */
769   flags |= O_CLOEXEC;
770 #elif defined O_NOINHERIT
771   flags |= O_NOINHERIT;
772 #endif
773 reopen:
774   fd = open(fname, (int)flags, (fmode_t)mode);
775   if (fd == -1) {
776     if (!retry) {
777       switch (errno) {
778         case ENFILE:
779         case EMFILE:
780         mrb_garbage_collect(mrb);
781         retry = TRUE;
782         goto reopen;
783       }
784     }
785 
786     emsg = mrb_format(mrb, "open %S", mrb_str_new_cstr(mrb, pathname));
787     mrb_str_modify(mrb, mrb_str_ptr(emsg));
788     mrb_sys_fail(mrb, RSTRING_PTR(emsg));
789   }
790   mrb_locale_free(fname);
791 
792   if (fd <= 2) {
793     mrb_fd_cloexec(mrb, fd);
794   }
795   return fd;
796 }
797 
798 mrb_value
mrb_io_s_sysopen(mrb_state * mrb,mrb_value klass)799 mrb_io_s_sysopen(mrb_state *mrb, mrb_value klass)
800 {
801   mrb_value path = mrb_nil_value();
802   mrb_value mode = mrb_nil_value();
803   mrb_int fd, perm = -1;
804   const char *pat;
805   int flags, modenum;
806 
807   mrb_get_args(mrb, "S|Si", &path, &mode, &perm);
808   if (mrb_nil_p(mode)) {
809     mode = mrb_str_new_cstr(mrb, "r");
810   }
811   if (perm < 0) {
812     perm = 0666;
813   }
814 
815   pat = mrb_string_value_cstr(mrb, &path);
816   flags = mrb_io_modestr_to_flags(mrb, mrb_string_value_cstr(mrb, &mode));
817   modenum = mrb_io_flags_to_modenum(mrb, flags);
818   fd = mrb_cloexec_open(mrb, pat, modenum, perm);
819   return mrb_fixnum_value(fd);
820 }
821 
822 mrb_value
mrb_io_sysread(mrb_state * mrb,mrb_value io)823 mrb_io_sysread(mrb_state *mrb, mrb_value io)
824 {
825   struct mrb_io *fptr;
826   mrb_value buf = mrb_nil_value();
827   mrb_int maxlen;
828   int ret;
829 
830   mrb_get_args(mrb, "i|S", &maxlen, &buf);
831   if (maxlen < 0) {
832     mrb_raise(mrb, E_ARGUMENT_ERROR, "negative expanding string size");
833   }
834   else if (maxlen == 0) {
835     return mrb_str_new(mrb, NULL, maxlen);
836   }
837 
838   if (mrb_nil_p(buf)) {
839     buf = mrb_str_new(mrb, NULL, maxlen);
840   }
841 
842   if (RSTRING_LEN(buf) != maxlen) {
843     buf = mrb_str_resize(mrb, buf, maxlen);
844   } else {
845     mrb_str_modify(mrb, RSTRING(buf));
846   }
847 
848   fptr = (struct mrb_io *)io_get_open_fptr(mrb, io);
849   if (!fptr->readable) {
850     mrb_raise(mrb, E_IO_ERROR, "not opened for reading");
851   }
852   ret = read(fptr->fd, RSTRING_PTR(buf), (fsize_t)maxlen);
853   switch (ret) {
854     case 0: /* EOF */
855       if (maxlen == 0) {
856         buf = mrb_str_new_cstr(mrb, "");
857       } else {
858         mrb_raise(mrb, E_EOF_ERROR, "sysread failed: End of File");
859       }
860       break;
861     case -1: /* Error */
862       mrb_sys_fail(mrb, "sysread failed");
863       break;
864     default:
865       if (RSTRING_LEN(buf) != ret) {
866         buf = mrb_str_resize(mrb, buf, ret);
867       }
868       break;
869   }
870 
871   return buf;
872 }
873 
874 mrb_value
mrb_io_sysseek(mrb_state * mrb,mrb_value io)875 mrb_io_sysseek(mrb_state *mrb, mrb_value io)
876 {
877   struct mrb_io *fptr;
878   off_t pos;
879   mrb_int offset, whence = -1;
880 
881   mrb_get_args(mrb, "i|i", &offset, &whence);
882   if (whence < 0) {
883     whence = 0;
884   }
885 
886   fptr = io_get_open_fptr(mrb, io);
887   pos = lseek(fptr->fd, (off_t)offset, (int)whence);
888   if (pos == -1) {
889     mrb_sys_fail(mrb, "sysseek");
890   }
891   if (pos > MRB_INT_MAX) {
892 #ifndef MRB_WITHOUT_FLOAT
893     return mrb_float_value(mrb, (mrb_float)pos);
894 #else
895     mrb_raise(mrb, E_IO_ERROR, "sysseek reached too far for MRB_WITHOUT_FLOAT");
896 #endif
897   } else {
898     return mrb_fixnum_value(pos);
899   }
900 }
901 
902 mrb_value
mrb_io_syswrite(mrb_state * mrb,mrb_value io)903 mrb_io_syswrite(mrb_state *mrb, mrb_value io)
904 {
905   struct mrb_io *fptr;
906   mrb_value str, buf;
907   int fd, length;
908 
909   fptr = io_get_open_fptr(mrb, io);
910   if (! fptr->writable) {
911     mrb_raise(mrb, E_IO_ERROR, "not opened for writing");
912   }
913 
914   mrb_get_args(mrb, "S", &str);
915   if (mrb_type(str) != MRB_TT_STRING) {
916     buf = mrb_funcall(mrb, str, "to_s", 0);
917   } else {
918     buf = str;
919   }
920 
921   if (fptr->fd2 == -1) {
922     fd = fptr->fd;
923   } else {
924     fd = fptr->fd2;
925   }
926   length = write(fd, RSTRING_PTR(buf), (fsize_t)RSTRING_LEN(buf));
927   if (length == -1) {
928     mrb_sys_fail(mrb, 0);
929   }
930 
931   return mrb_fixnum_value(length);
932 }
933 
934 mrb_value
mrb_io_close(mrb_state * mrb,mrb_value self)935 mrb_io_close(mrb_state *mrb, mrb_value self)
936 {
937   struct mrb_io *fptr;
938   fptr = io_get_open_fptr(mrb, self);
939   fptr_finalize(mrb, fptr, FALSE);
940   return mrb_nil_value();
941 }
942 
943 mrb_value
mrb_io_close_write(mrb_state * mrb,mrb_value self)944 mrb_io_close_write(mrb_state *mrb, mrb_value self)
945 {
946   struct mrb_io *fptr;
947   fptr = io_get_open_fptr(mrb, self);
948   if (close((int)fptr->fd2) == -1) {
949     mrb_sys_fail(mrb, "close");
950   }
951   return mrb_nil_value();
952 }
953 
954 mrb_value
mrb_io_closed(mrb_state * mrb,mrb_value io)955 mrb_io_closed(mrb_state *mrb, mrb_value io)
956 {
957   struct mrb_io *fptr;
958   fptr = (struct mrb_io *)mrb_get_datatype(mrb, io, &mrb_io_type);
959   if (fptr == NULL || fptr->fd >= 0) {
960     return mrb_false_value();
961   }
962 
963   return mrb_true_value();
964 }
965 
966 mrb_value
mrb_io_pid(mrb_state * mrb,mrb_value io)967 mrb_io_pid(mrb_state *mrb, mrb_value io)
968 {
969   struct mrb_io *fptr;
970   fptr = io_get_open_fptr(mrb, io);
971 
972   if (fptr->pid > 0) {
973     return mrb_fixnum_value(fptr->pid);
974   }
975 
976   return mrb_nil_value();
977 }
978 
979 static struct timeval
time2timeval(mrb_state * mrb,mrb_value time)980 time2timeval(mrb_state *mrb, mrb_value time)
981 {
982   struct timeval t = { 0, 0 };
983 
984   switch (mrb_type(time)) {
985     case MRB_TT_FIXNUM:
986       t.tv_sec = (ftime_t)mrb_fixnum(time);
987       t.tv_usec = 0;
988       break;
989 
990 #ifndef MRB_WITHOUT_FLOAT
991     case MRB_TT_FLOAT:
992       t.tv_sec = (ftime_t)mrb_float(time);
993       t.tv_usec = (fsuseconds_t)((mrb_float(time) - t.tv_sec) * 1000000.0);
994       break;
995 #endif
996 
997     default:
998       mrb_raise(mrb, E_TYPE_ERROR, "wrong argument class");
999   }
1000 
1001   return t;
1002 }
1003 
1004 static int
mrb_io_read_data_pending(mrb_state * mrb,mrb_value io)1005 mrb_io_read_data_pending(mrb_state *mrb, mrb_value io)
1006 {
1007   mrb_value buf = mrb_iv_get(mrb, io, mrb_intern_cstr(mrb, "@buf"));
1008   if (mrb_type(buf) == MRB_TT_STRING && RSTRING_LEN(buf) > 0) {
1009     return 1;
1010   }
1011   return 0;
1012 }
1013 
1014 #if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
1015 static mrb_value
mrb_io_s_pipe(mrb_state * mrb,mrb_value klass)1016 mrb_io_s_pipe(mrb_state *mrb, mrb_value klass)
1017 {
1018   mrb_value r = mrb_nil_value();
1019   mrb_value w = mrb_nil_value();
1020   struct mrb_io *fptr_r;
1021   struct mrb_io *fptr_w;
1022   int pipes[2];
1023 
1024   if (mrb_pipe(mrb, pipes) == -1) {
1025     mrb_sys_fail(mrb, "pipe");
1026   }
1027 
1028   r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
1029   mrb_iv_set(mrb, r, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
1030   fptr_r = mrb_io_alloc(mrb);
1031   fptr_r->fd = pipes[0];
1032   fptr_r->readable = 1;
1033   fptr_r->writable = 0;
1034   fptr_r->sync = 0;
1035   DATA_TYPE(r) = &mrb_io_type;
1036   DATA_PTR(r)  = fptr_r;
1037 
1038   w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
1039   mrb_iv_set(mrb, w, mrb_intern_cstr(mrb, "@buf"), mrb_str_new_cstr(mrb, ""));
1040   fptr_w = mrb_io_alloc(mrb);
1041   fptr_w->fd = pipes[1];
1042   fptr_w->readable = 0;
1043   fptr_w->writable = 1;
1044   fptr_w->sync = 1;
1045   DATA_TYPE(w) = &mrb_io_type;
1046   DATA_PTR(w)  = fptr_w;
1047 
1048   return mrb_assoc_new(mrb, r, w);
1049 }
1050 #endif
1051 
1052 static mrb_value
mrb_io_s_select(mrb_state * mrb,mrb_value klass)1053 mrb_io_s_select(mrb_state *mrb, mrb_value klass)
1054 {
1055   mrb_value *argv;
1056   mrb_int argc;
1057   mrb_value read, read_io, write, except, timeout, list;
1058   struct timeval *tp, timerec;
1059   fd_set pset, rset, wset, eset;
1060   fd_set *rp, *wp, *ep;
1061   struct mrb_io *fptr;
1062   int pending = 0;
1063   mrb_value result;
1064   int max = 0;
1065   int interrupt_flag = 0;
1066   int i, n;
1067 
1068   mrb_get_args(mrb, "*", &argv, &argc);
1069 
1070   if (argc < 1 || argc > 4) {
1071     mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong number of arguments (%S for 1..4)", mrb_fixnum_value(argc));
1072   }
1073 
1074   timeout = mrb_nil_value();
1075   except = mrb_nil_value();
1076   write = mrb_nil_value();
1077   if (argc > 3)
1078     timeout = argv[3];
1079   if (argc > 2)
1080     except = argv[2];
1081   if (argc > 1)
1082     write = argv[1];
1083   read = argv[0];
1084 
1085   if (mrb_nil_p(timeout)) {
1086     tp = NULL;
1087   } else {
1088     timerec = time2timeval(mrb, timeout);
1089     tp = &timerec;
1090   }
1091 
1092   FD_ZERO(&pset);
1093   if (!mrb_nil_p(read)) {
1094     mrb_check_type(mrb, read, MRB_TT_ARRAY);
1095     rp = &rset;
1096     FD_ZERO(rp);
1097     for (i = 0; i < RARRAY_LEN(read); i++) {
1098       read_io = RARRAY_PTR(read)[i];
1099       fptr = io_get_open_fptr(mrb, read_io);
1100       FD_SET(fptr->fd, rp);
1101       if (mrb_io_read_data_pending(mrb, read_io)) {
1102         pending++;
1103         FD_SET(fptr->fd, &pset);
1104       }
1105       if (max < fptr->fd)
1106         max = fptr->fd;
1107     }
1108     if (pending) {
1109       timerec.tv_sec = timerec.tv_usec = 0;
1110       tp = &timerec;
1111     }
1112   } else {
1113     rp = NULL;
1114   }
1115 
1116   if (!mrb_nil_p(write)) {
1117     mrb_check_type(mrb, write, MRB_TT_ARRAY);
1118     wp = &wset;
1119     FD_ZERO(wp);
1120     for (i = 0; i < RARRAY_LEN(write); i++) {
1121       fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
1122       FD_SET(fptr->fd, wp);
1123       if (max < fptr->fd)
1124         max = fptr->fd;
1125       if (fptr->fd2 >= 0) {
1126         FD_SET(fptr->fd2, wp);
1127         if (max < fptr->fd2)
1128           max = fptr->fd2;
1129       }
1130     }
1131   } else {
1132     wp = NULL;
1133   }
1134 
1135   if (!mrb_nil_p(except)) {
1136     mrb_check_type(mrb, except, MRB_TT_ARRAY);
1137     ep = &eset;
1138     FD_ZERO(ep);
1139     for (i = 0; i < RARRAY_LEN(except); i++) {
1140       fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
1141       FD_SET(fptr->fd, ep);
1142       if (max < fptr->fd)
1143         max = fptr->fd;
1144       if (fptr->fd2 >= 0) {
1145         FD_SET(fptr->fd2, ep);
1146         if (max < fptr->fd2)
1147           max = fptr->fd2;
1148       }
1149     }
1150   } else {
1151     ep = NULL;
1152   }
1153 
1154   max++;
1155 
1156 retry:
1157   n = select(max, rp, wp, ep, tp);
1158   if (n < 0) {
1159     if (errno != EINTR)
1160       mrb_sys_fail(mrb, "select failed");
1161     if (tp == NULL)
1162       goto retry;
1163     interrupt_flag = 1;
1164   }
1165 
1166   if (!pending && n == 0)
1167     return mrb_nil_value();
1168 
1169   result = mrb_ary_new_capa(mrb, 3);
1170   mrb_ary_push(mrb, result, rp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
1171   mrb_ary_push(mrb, result, wp? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
1172   mrb_ary_push(mrb, result, ep? mrb_ary_new(mrb) : mrb_ary_new_capa(mrb, 0));
1173 
1174   if (interrupt_flag == 0) {
1175     if (rp) {
1176       list = RARRAY_PTR(result)[0];
1177       for (i = 0; i < RARRAY_LEN(read); i++) {
1178         fptr = io_get_open_fptr(mrb, RARRAY_PTR(read)[i]);
1179         if (FD_ISSET(fptr->fd, rp) ||
1180             FD_ISSET(fptr->fd, &pset)) {
1181           mrb_ary_push(mrb, list, RARRAY_PTR(read)[i]);
1182         }
1183       }
1184     }
1185 
1186     if (wp) {
1187       list = RARRAY_PTR(result)[1];
1188       for (i = 0; i < RARRAY_LEN(write); i++) {
1189         fptr = io_get_open_fptr(mrb, RARRAY_PTR(write)[i]);
1190         if (FD_ISSET(fptr->fd, wp)) {
1191           mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
1192         } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, wp)) {
1193           mrb_ary_push(mrb, list, RARRAY_PTR(write)[i]);
1194         }
1195       }
1196     }
1197 
1198     if (ep) {
1199       list = RARRAY_PTR(result)[2];
1200       for (i = 0; i < RARRAY_LEN(except); i++) {
1201         fptr = io_get_open_fptr(mrb, RARRAY_PTR(except)[i]);
1202         if (FD_ISSET(fptr->fd, ep)) {
1203           mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
1204         } else if (fptr->fd2 >= 0 && FD_ISSET(fptr->fd2, ep)) {
1205           mrb_ary_push(mrb, list, RARRAY_PTR(except)[i]);
1206         }
1207       }
1208     }
1209   }
1210 
1211   return result;
1212 }
1213 
1214 mrb_value
mrb_io_fileno(mrb_state * mrb,mrb_value io)1215 mrb_io_fileno(mrb_state *mrb, mrb_value io)
1216 {
1217   struct mrb_io *fptr;
1218   fptr = io_get_open_fptr(mrb, io);
1219   return mrb_fixnum_value(fptr->fd);
1220 }
1221 
1222 mrb_value
mrb_io_close_on_exec_p(mrb_state * mrb,mrb_value self)1223 mrb_io_close_on_exec_p(mrb_state *mrb, mrb_value self)
1224 {
1225 #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
1226   struct mrb_io *fptr;
1227   int ret;
1228 
1229   fptr = io_get_open_fptr(mrb, self);
1230 
1231   if (fptr->fd2 >= 0) {
1232     if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1233     if (!(ret & FD_CLOEXEC)) return mrb_false_value();
1234   }
1235 
1236   if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1237   if (!(ret & FD_CLOEXEC)) return mrb_false_value();
1238   return mrb_true_value();
1239 
1240 #else
1241   mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec? is not supported on the platform");
1242   return mrb_false_value();
1243 #endif
1244 }
1245 
1246 mrb_value
mrb_io_set_close_on_exec(mrb_state * mrb,mrb_value self)1247 mrb_io_set_close_on_exec(mrb_state *mrb, mrb_value self)
1248 {
1249 #if defined(F_GETFD) && defined(F_SETFD) && defined(FD_CLOEXEC)
1250   struct mrb_io *fptr;
1251   int flag, ret;
1252   mrb_bool b;
1253 
1254   fptr = io_get_open_fptr(mrb, self);
1255   mrb_get_args(mrb, "b", &b);
1256   flag = b ? FD_CLOEXEC : 0;
1257 
1258   if (fptr->fd2 >= 0) {
1259     if ((ret = fcntl(fptr->fd2, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1260     if ((ret & FD_CLOEXEC) != flag) {
1261       ret = (ret & ~FD_CLOEXEC) | flag;
1262       ret = fcntl(fptr->fd2, F_SETFD, ret);
1263 
1264       if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed");
1265     }
1266   }
1267 
1268   if ((ret = fcntl(fptr->fd, F_GETFD)) == -1) mrb_sys_fail(mrb, "F_GETFD failed");
1269   if ((ret & FD_CLOEXEC) != flag) {
1270     ret = (ret & ~FD_CLOEXEC) | flag;
1271     ret = fcntl(fptr->fd, F_SETFD, ret);
1272     if (ret == -1) mrb_sys_fail(mrb, "F_SETFD failed");
1273   }
1274 
1275   return mrb_bool_value(b);
1276 #else
1277   mrb_raise(mrb, E_NOTIMP_ERROR, "IO#close_on_exec= is not supported on the platform");
1278   return mrb_nil_value();
1279 #endif
1280 }
1281 
1282 mrb_value
mrb_io_set_sync(mrb_state * mrb,mrb_value self)1283 mrb_io_set_sync(mrb_state *mrb, mrb_value self)
1284 {
1285   struct mrb_io *fptr;
1286   mrb_bool b;
1287 
1288   fptr = io_get_open_fptr(mrb, self);
1289   mrb_get_args(mrb, "b", &b);
1290   fptr->sync = b;
1291   return mrb_bool_value(b);
1292 }
1293 
1294 mrb_value
mrb_io_sync(mrb_state * mrb,mrb_value self)1295 mrb_io_sync(mrb_state *mrb, mrb_value self)
1296 {
1297   struct mrb_io *fptr;
1298   fptr = io_get_open_fptr(mrb, self);
1299   return mrb_bool_value(fptr->sync);
1300 }
1301 
1302 void
mrb_init_io(mrb_state * mrb)1303 mrb_init_io(mrb_state *mrb)
1304 {
1305   struct RClass *io;
1306 
1307   io      = mrb_define_class(mrb, "IO", mrb->object_class);
1308   MRB_SET_INSTANCE_TT(io, MRB_TT_DATA);
1309 
1310   mrb_include_module(mrb, io, mrb_module_get(mrb, "Enumerable")); /* 15.2.20.3 */
1311   mrb_define_class_method(mrb, io, "_popen",  mrb_io_s_popen,   MRB_ARGS_ANY());
1312   mrb_define_class_method(mrb, io, "_sysclose",  mrb_io_s_sysclose, MRB_ARGS_REQ(1));
1313   mrb_define_class_method(mrb, io, "for_fd",  mrb_io_s_for_fd,   MRB_ARGS_ANY());
1314   mrb_define_class_method(mrb, io, "select",  mrb_io_s_select,  MRB_ARGS_ANY());
1315   mrb_define_class_method(mrb, io, "sysopen", mrb_io_s_sysopen, MRB_ARGS_ANY());
1316 #if !defined(_WIN32) && !(defined(TARGET_OS_IPHONE) && TARGET_OS_IPHONE)
1317   mrb_define_class_method(mrb, io, "_pipe", mrb_io_s_pipe, MRB_ARGS_NONE());
1318 #endif
1319 
1320   mrb_define_method(mrb, io, "initialize", mrb_io_initialize, MRB_ARGS_ANY());    /* 15.2.20.5.21 (x)*/
1321   mrb_define_method(mrb, io, "initialize_copy", mrb_io_initialize_copy, MRB_ARGS_REQ(1));
1322   mrb_define_method(mrb, io, "_check_readable", mrb_io_check_readable, MRB_ARGS_NONE());
1323   mrb_define_method(mrb, io, "isatty",     mrb_io_isatty,     MRB_ARGS_NONE());
1324   mrb_define_method(mrb, io, "sync",       mrb_io_sync,       MRB_ARGS_NONE());
1325   mrb_define_method(mrb, io, "sync=",      mrb_io_set_sync,   MRB_ARGS_REQ(1));
1326   mrb_define_method(mrb, io, "sysread",    mrb_io_sysread,    MRB_ARGS_ANY());
1327   mrb_define_method(mrb, io, "sysseek",    mrb_io_sysseek,    MRB_ARGS_REQ(1));
1328   mrb_define_method(mrb, io, "syswrite",   mrb_io_syswrite,   MRB_ARGS_REQ(1));
1329   mrb_define_method(mrb, io, "close",      mrb_io_close,      MRB_ARGS_NONE());   /* 15.2.20.5.1 */
1330   mrb_define_method(mrb, io, "close_write",    mrb_io_close_write,       MRB_ARGS_NONE());
1331   mrb_define_method(mrb, io, "close_on_exec=", mrb_io_set_close_on_exec, MRB_ARGS_REQ(1));
1332   mrb_define_method(mrb, io, "close_on_exec?", mrb_io_close_on_exec_p,   MRB_ARGS_NONE());
1333   mrb_define_method(mrb, io, "closed?",    mrb_io_closed,     MRB_ARGS_NONE());   /* 15.2.20.5.2 */
1334   mrb_define_method(mrb, io, "pid",        mrb_io_pid,        MRB_ARGS_NONE());   /* 15.2.20.5.2 */
1335   mrb_define_method(mrb, io, "fileno",     mrb_io_fileno,     MRB_ARGS_NONE());
1336 
1337 
1338   mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$/"), mrb_str_new_cstr(mrb, "\n"));
1339 }
1340