1 /* source: xio-stdio.c */
2 /* Copyright Gerhard Rieger and contributors (see file CHANGES) */
3 /* Published under the GNU General Public License V.2, see file COPYING */
5 /* this file contains the source for opening addresses stdio type */
7 #include "xiosysincludes.h"
10 #include "xio-fdnum.h"
11 #include "xio-stdio.h"
16 static int xioopen_stdio(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*fd
, const struct addrdesc
*addrdesc
);
17 static int xioopen_stdfd(int argc
, const char *argv
[], struct opt
*opts
, int xioflags
, xiofile_t
*xfd
, const struct addrdesc
*addrdesc
);
20 /* we specify all option groups that we can imagine for a FD, becasue the
21 changed parsing mechanism does not allow us to check the type of FD before
22 applying the options */
23 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
) };
24 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
) };
25 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
) };
26 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
) };
29 /* process a bidirectional "stdio" or "-" argument with options.
30 generate a dual address. */
31 int xioopen_stdio_bi(xiofile_t
*sock
) {
33 groups_t groups1
= xioaddr_stdio
.groups
;
36 if (xioopen_makedual(sock
) < 0) {
40 sock
->dual
.stream
[0]->tag
= XIO_TAG_RDONLY
;
41 sock
->dual
.stream
[0]->fd
= 0 /*stdin*/;
42 sock
->dual
.stream
[1]->tag
= XIO_TAG_WRONLY
;
43 sock
->dual
.stream
[1]->fd
= 1 /*stdout*/;
44 if (sock
->dual
.stream
[0]->howtoend
== END_UNSPEC
)
45 sock
->dual
.stream
[0]->howtoend
= END_NONE
;
46 if (sock
->dual
.stream
[1]->howtoend
== END_UNSPEC
)
47 sock
->dual
.stream
[1]->howtoend
= END_NONE
;
50 if (Isatty(sock
->dual
.stream
[0]->fd
)) {
51 if (Tcgetattr(sock
->dual
.stream
[0]->fd
,
52 &sock
->dual
.stream
[0]->savetty
)
54 Warn2("cannot query current terminal settings on fd %d: %s",
55 sock
->dual
.stream
[0]->fd
, strerror(errno
));
57 sock
->dual
.stream
[0]->ttyvalid
= true;
60 if (Isatty(sock
->dual
.stream
[1]->fd
)) {
61 if (Tcgetattr(sock
->dual
.stream
[1]->fd
,
62 &sock
->dual
.stream
[1]->savetty
)
64 Warn2("cannot query current terminal settings on fd %d: %s",
65 sock
->dual
.stream
[1]->fd
, strerror(errno
));
67 sock
->dual
.stream
[1]->ttyvalid
= true;
70 #endif /* WITH_TERMIOS */
72 /* options here are one-time and one-direction, no second use */
73 retropt_bool(sock
->stream
.opts
, OPT_IGNOREEOF
, &sock
->dual
.stream
[0]->ignoreeof
);
75 /* extract opts that should be applied only once */
76 if ((optspr
= copyopts(sock
->stream
.opts
, GROUP_PROCESS
)) == NULL
) {
79 /* here we copy opts, because most have to be applied twice! */
80 if ((sock
->dual
.stream
[1]->opts
= copyopts(sock
->stream
.opts
, GROUP_FD
|GROUP_APPL
|(groups1
&~GROUP_PROCESS
))) == NULL
) {
83 sock
->dual
.stream
[0]->opts
= sock
->stream
.opts
;
84 sock
->stream
.opts
= NULL
;
86 if (applyopts_single(sock
->dual
.stream
[0],
87 sock
->dual
.stream
[0]->opts
, PH_INIT
)
90 if (applyopts_single(sock
->dual
.stream
[1],
91 sock
->dual
.stream
[1]->opts
, PH_INIT
)
94 applyopts(sock
->dual
.stream
[0], -1, sock
->dual
.stream
[0]->opts
, PH_INIT
);
95 applyopts(sock
->dual
.stream
[1], -1, sock
->dual
.stream
[1]->opts
, PH_INIT
);
96 if ((result
= applyopts(NULL
, -1, optspr
, PH_EARLY
)) < 0)
98 if ((result
= applyopts(NULL
, -1, optspr
, PH_PREOPEN
)) < 0)
101 /* apply options to first FD */
103 applyopts(sock
->dual
.stream
[0], -1,
104 sock
->dual
.stream
[0]->opts
, PH_ALL
))
108 if ((result
= _xio_openlate(sock
->dual
.stream
[0],
109 sock
->dual
.stream
[0]->opts
)) < 0) {
113 /* ignore this opt */
114 retropt_bool(sock
->dual
.stream
[0]->opts
, OPT_COOL_WRITE
);
117 /* apply options to second FD */
118 if ((result
= applyopts(sock
->dual
.stream
[1], -1,
119 sock
->dual
.stream
[1]->opts
, PH_ALL
)) < 0) {
122 if ((result
= _xio_openlate(sock
->dual
.stream
[1],
123 sock
->dual
.stream
[1]->opts
)) < 0) {
128 if ((result
= _xio_openlate(sock
->dual
.stream
[1], optspr
)) < 0) {
133 Notice("reading from and writing to stdio");
138 /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
139 Do not set FD_CLOEXEC flag. */
140 static int xioopen_stdio(
146 const struct addrdesc
*addrdesc
)
148 int rw
= (xioflags
&XIO_ACCMODE
);
151 Error2("%s: wrong number of parameters (%d instead of 0)", argv
[0], argc
-1);
154 if (rw
== XIO_RDWR
) {
155 return xioopen_stdio_bi(fd
);
158 Notice2("using %s for %s",
159 &("stdin\0\0\0stdout"[rw
<<3]),
161 return xioopen_fd(opts
, rw
, &fd
->stream
, rw
);
164 /* wrap around unidirectional xioopensingle and xioopen_fd to automatically determine stdin or stdout fd depending on rw.
165 Do not set FD_CLOEXEC flag. */
166 static int xioopen_stdfd(
172 const struct addrdesc
*addrdesc
)
174 int rw
= (xioflags
&XIO_ACCMODE
);
175 int fd
= addrdesc
->arg1
;
178 Error2("%s: wrong number of parameters (%d instead of 0)", argv
[0], argc
-1);
180 Notice2("using %s for %s",
181 &("stdin\0\0\0stdout\0\0stderr"[fd
<<3]),
183 return xioopen_fd(opts
, rw
, &xfd
->stream
, fd
);
185 #endif /* WITH_STDIO */