| /* source: xio-stdio.c */ |
| /* Copyright Gerhard Rieger and contributors (see file CHANGES) */ |
| /* Published under the GNU General Public License V.2, see file COPYING */ |
| |
| /* this file contains the source for opening addresses stdio type */ |
| |
| #include "xiosysincludes.h" |
| #include "xioopen.h" |
| |
| #include "xio-fdnum.h" |
| #include "xio-stdio.h" |
| |
| |
| #if WITH_STDIO |
| |
| static int xioopen_stdio(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *fd, const struct addrdesc *addrdesc); |
| static int xioopen_stdfd(int argc, const char *argv[], struct opt *opts, int xioflags, xiofile_t *xfd, const struct addrdesc *addrdesc); |
| |
| |
| /* we specify all option groups that we can imagine for a FD, becasue the |
| changed parsing mechanism does not allow us to check the type of FD before |
| applying the options */ |
| const struct addrdesc xioaddr_stdio = { "STDIO", 3, xioopen_stdio, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(NULL) }; |
| const struct addrdesc xioaddr_stdin = { "STDIN", 1, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 0, 0, 0 HELP(NULL) }; |
| const struct addrdesc xioaddr_stdout = { "STDOUT", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 1, 0, 0 HELP(NULL) }; |
| const struct addrdesc xioaddr_stderr = { "STDERR", 2, xioopen_stdfd, GROUP_FD|GROUP_FIFO|GROUP_CHR|GROUP_BLK|GROUP_FILE|GROUP_SOCKET|GROUP_TERMIOS|GROUP_SOCK_UNIX|GROUP_SOCK_IP|GROUP_IPAPP, 2, 0, 0 HELP(NULL) }; |
| |
| |
| /* process a bidirectional "stdio" or "-" argument with options. |
| generate a dual address. */ |
| int xioopen_stdio_bi(xiofile_t *sock) { |
| struct opt *optspr; |
| groups_t groups1 = xioaddr_stdio.groups; |
| int result; |
| |
| if (xioopen_makedual(sock) < 0) { |
| return -1; |
| } |
| |
| sock->dual.stream[0]->tag = XIO_TAG_RDONLY; |
| sock->dual.stream[0]->fd = 0 /*stdin*/; |
| sock->dual.stream[1]->tag = XIO_TAG_WRONLY; |
| sock->dual.stream[1]->fd = 1 /*stdout*/; |
| if (sock->dual.stream[0]->howtoend == END_UNSPEC) |
| sock->dual.stream[0]->howtoend = END_NONE; |
| if (sock->dual.stream[1]->howtoend == END_UNSPEC) |
| sock->dual.stream[1]->howtoend = END_NONE; |
| |
| #if WITH_TERMIOS |
| if (Isatty(sock->dual.stream[0]->fd)) { |
| if (Tcgetattr(sock->dual.stream[0]->fd, |
| &sock->dual.stream[0]->savetty) |
| < 0) { |
| Warn2("cannot query current terminal settings on fd %d: %s", |
| sock->dual.stream[0]->fd, strerror(errno)); |
| } else { |
| sock->dual.stream[0]->ttyvalid = true; |
| } |
| } |
| if (Isatty(sock->dual.stream[1]->fd)) { |
| if (Tcgetattr(sock->dual.stream[1]->fd, |
| &sock->dual.stream[1]->savetty) |
| < 0) { |
| Warn2("cannot query current terminal settings on fd %d: %s", |
| sock->dual.stream[1]->fd, strerror(errno)); |
| } else { |
| sock->dual.stream[1]->ttyvalid = true; |
| } |
| } |
| #endif /* WITH_TERMIOS */ |
| |
| /* options here are one-time and one-direction, no second use */ |
| retropt_bool(sock->stream.opts, OPT_IGNOREEOF, &sock->dual.stream[0]->ignoreeof); |
| |
| /* extract opts that should be applied only once */ |
| if ((optspr = copyopts(sock->stream.opts, GROUP_PROCESS)) == NULL) { |
| return -1; |
| } |
| /* here we copy opts, because most have to be applied twice! */ |
| if ((sock->dual.stream[1]->opts = copyopts(sock->stream.opts, GROUP_FD|GROUP_APPL|(groups1&~GROUP_PROCESS))) == NULL) { |
| return -1; |
| } |
| sock->dual.stream[0]->opts = sock->stream.opts; |
| sock->stream.opts = NULL; |
| |
| if (applyopts_single(sock->dual.stream[0], |
| sock->dual.stream[0]->opts, PH_INIT) |
| < 0) |
| return -1; |
| if (applyopts_single(sock->dual.stream[1], |
| sock->dual.stream[1]->opts, PH_INIT) |
| < 0) |
| return -1; |
| applyopts(sock->dual.stream[0], -1, sock->dual.stream[0]->opts, PH_INIT); |
| applyopts(sock->dual.stream[1], -1, sock->dual.stream[1]->opts, PH_INIT); |
| if ((result = applyopts(NULL, -1, optspr, PH_EARLY)) < 0) |
| return result; |
| if ((result = applyopts(NULL, -1, optspr, PH_PREOPEN)) < 0) |
| return result; |
| |
| /* apply options to first FD */ |
| if ((result = |
| applyopts(sock->dual.stream[0], -1, |
| sock->dual.stream[0]->opts, PH_ALL)) |
| < 0) { |
| return result; |
| } |
| if ((result = _xio_openlate(sock->dual.stream[0], |
| sock->dual.stream[0]->opts)) < 0) { |
| return result; |
| } |
| #if 0 |
| /* ignore this opt */ |
| retropt_bool(sock->dual.stream[0]->opts, OPT_COOL_WRITE); |
| #endif |
| |
| /* apply options to second FD */ |
| if ((result = applyopts(sock->dual.stream[1], -1, |
| sock->dual.stream[1]->opts, PH_ALL)) < 0) { |
| return result; |
| } |
| if ((result = _xio_openlate(sock->dual.stream[1], |
| sock->dual.stream[1]->opts)) < 0) { |
| return result; |
| } |
| |
| #if 0 |
| if ((result = _xio_openlate(sock->dual.stream[1], optspr)) < 0) { |
| return result; |
| } |
| #endif |
| |
| Notice("reading from and writing to stdio"); |
| return 0; |
| } |
| |
| |
| /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw. |
| Do not set FD_CLOEXEC flag. */ |
| static int xioopen_stdio( |
| int argc, |
| const char *argv[], |
| struct opt *opts, |
| int xioflags, |
| xiofile_t *fd, |
| const struct addrdesc *addrdesc) |
| { |
| int rw = (xioflags&XIO_ACCMODE); |
| |
| if (argc != 1) { |
| Error2("%s: wrong number of parameters (%d instead of 0)", argv[0], argc-1); |
| } |
| |
| if (rw == XIO_RDWR) { |
| return xioopen_stdio_bi(fd); |
| } |
| |
| Notice2("using %s for %s", |
| &("stdin\0\0\0stdout"[rw<<3]), |
| ddirection[rw]); |
| return xioopen_fd(opts, rw, &fd->stream, rw); |
| } |
| |
| /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw. |
| Do not set FD_CLOEXEC flag. */ |
| static int xioopen_stdfd( |
| int argc, |
| const char *argv[], |
| struct opt *opts, |
| int xioflags, |
| xiofile_t *xfd, |
| const struct addrdesc *addrdesc) |
| { |
| int rw = (xioflags&XIO_ACCMODE); |
| int fd = addrdesc->arg1; |
| |
| if (argc != 1) { |
| Error2("%s: wrong number of parameters (%d instead of 0)", argv[0], argc-1); |
| } |
| Notice2("using %s for %s", |
| &("stdin\0\0\0stdout\0\0stderr"[fd<<3]), |
| ddirection[rw]); |
| return xioopen_fd(opts, rw, &xfd->stream, fd); |
| } |
| #endif /* WITH_STDIO */ |