author | Sergey Poznyakoff <gray@gnu.org> | 2019-06-09 15:54:58 (GMT) |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org> | 2019-06-09 15:54:58 (GMT) |
commit | c4dbd40477bb658cdc5c5e01b8f80057e587cd88 (patch) (unidiff) | |
tree | 73534b2cd2fff99e16c26ed4be8cf115cf4b3960 /tests | |
parent | c33922f128403f5d05d24f19abeaad2368ce5467 (diff) | |
download | pies-c4dbd40477bb658cdc5c5e01b8f80057e587cd88.tar.gz pies-c4dbd40477bb658cdc5c5e01b8f80057e587cd88.tar.bz2 |
Test inetd components.
* lib/Makefile.am: Add urlconn.c
* lib/libpies.h (url_connect): New proto.
* lib/urlconn.c: New file.
* src/piesctl.c (shttp_connect): Use url_connect.
* tests/.gitignore: Update.
* tests/Makefile.am: New auxtool: aux/in.test
New test: inet.at
* tests/aux/in.test: New file.
* tests/inet.at: New file.
* tests/iobuf.h: New file.
* tests/nt.c: New file.
* tests/testsuite.at: Add new test.
* tests/to.c: explicitly terminate the child process on timeout.
-rw-r--r-- | tests/.gitignore | 1 | ||||
-rw-r--r-- | tests/Makefile.am | 9 | ||||
-rwxr-xr-x | tests/aux/in.test | 22 | ||||
-rw-r--r-- | tests/inet.at | 38 | ||||
-rw-r--r-- | tests/iobuf.h | 141 | ||||
-rw-r--r-- | tests/nt.c | 339 | ||||
-rw-r--r-- | tests/testsuite.at | 1 | ||||
-rw-r--r-- | tests/to.c | 50 |
8 files changed, 590 insertions, 11 deletions
diff --git a/tests/.gitignore b/tests/.gitignore index 459fa44..68159e3 100644 --- a/tests/.gitignore +++ b/tests/.gitignore | |||
@@ -7,3 +7,4 @@ testsuite | |||
7 | testsuite.dir | 7 | testsuite.dir |
8 | testsuite.log | 8 | testsuite.log |
9 | to | 9 | to |
10 | nt | ||
diff --git a/tests/Makefile.am b/tests/Makefile.am index 14f5b4f..0290f61 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am | |||
@@ -20,7 +20,8 @@ AUXTOOLS = \ | |||
20 | aux/mailer\ | 20 | aux/mailer\ |
21 | aux/touchfile\ | 21 | aux/touchfile\ |
22 | aux/sleepexit\ | 22 | aux/sleepexit\ |
23 | aux/startcheck | 23 | aux/startcheck\ |
24 | aux/in.test | ||
24 | 25 | ||
25 | EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 $(AUXTOOLS) | 26 | EXTRA_DIST = $(TESTSUITE_AT) testsuite package.m4 $(AUXTOOLS) |
26 | DISTCLEANFILES = atconfig $(check_SCRIPTS) | 27 | DISTCLEANFILES = atconfig $(check_SCRIPTS) |
@@ -52,6 +53,7 @@ TESTSUITE_AT = \ | |||
52 | cyclic.at\ | 53 | cyclic.at\ |
53 | env.at\ | 54 | env.at\ |
54 | envop.at\ | 55 | envop.at\ |
56 | inet.at\ | ||
55 | respawn.at\ | 57 | respawn.at\ |
56 | redirect.at\ | 58 | redirect.at\ |
57 | ret-exec.at\ | 59 | ret-exec.at\ |
@@ -64,9 +66,12 @@ TESTSUITE_AT = \ | |||
64 | TESTSUITE = $(srcdir)/testsuite | 66 | TESTSUITE = $(srcdir)/testsuite |
65 | M4=m4 | 67 | M4=m4 |
66 | 68 | ||
67 | noinst_PROGRAMS = envtest to lines | 69 | noinst_PROGRAMS = envtest to lines nt |
70 | nt_SOURCES = nt.c iobuf.h | ||
68 | AM_CPPFLAGS = \ | 71 | AM_CPPFLAGS = \ |
69 | -I$(top_srcdir)/lib\ | 72 | -I$(top_srcdir)/lib\ |
73 | -I$(top_srcdir)/gnu\ | ||
74 | -I$(top_builddir)/gnu\ | ||
70 | @GRECS_INCLUDES@ | 75 | @GRECS_INCLUDES@ |
71 | 76 | ||
72 | LDADD = \ | 77 | LDADD = \ |
diff --git a/tests/aux/in.test b/tests/aux/in.test new file mode 100755 index 0000000..4a98763 --- a/dev/null +++ b/tests/aux/in.test | |||
@@ -0,0 +1,22 @@ | |||
1 | #! /bin/sh | ||
2 | |||
3 | FILE=${1:?} | ||
4 | IFS=' | ||
5 | ' | ||
6 | while read COMMAND ARG | ||
7 | do | ||
8 | echo $COMMAND $ARG >> $FILE | ||
9 | case $COMMAND in | ||
10 | stop) if [ -n "$STOPCMD" ]; then | ||
11 | echo "STOP" | ||
12 | $STOPCMD | ||
13 | else | ||
14 | echo "OK $COMMAND $ARG" | ||
15 | fi | ||
16 | ;; | ||
17 | quit) exit $ARG;; | ||
18 | *) echo "OK $COMMAND $ARG" | ||
19 | ;; | ||
20 | esac | ||
21 | done | ||
22 | |||
diff --git a/tests/inet.at b/tests/inet.at new file mode 100644 index 0000000..41cae6a --- a/dev/null +++ b/tests/inet.at | |||
@@ -0,0 +1,38 @@ | |||
1 | AT_SETUP([inet component]) | ||
2 | AT_CHECK([ | ||
3 | PIES_XFAIL_CHECK | ||
4 | PIES_CONTROL_INIT | ||
5 | AT_DATA([input], | ||
6 | [line 1 | ||
7 | line 2 | ||
8 | stop | ||
9 | ]) | ||
10 | : ${PIES_TEST_INET_SOCKET:=unix://$PWD/in.sock} | ||
11 | cat > pies.conf <<_EOT | ||
12 | component in { | ||
13 | command "$auxdir/in.test $PWD/inlog"; | ||
14 | env { | ||
15 | set "STOPCMD=piesctl --url unix:///$PWD/pies.ctl --no-netrc shutdown"; | ||
16 | } | ||
17 | mode inetd; | ||
18 | socket "$PIES_TEST_INET_SOCKET"; | ||
19 | stderr file "$PWD/log.err"; | ||
20 | } | ||
21 | component controller { | ||
22 | command "nt $PIES_TEST_INET_SOCKET -i input"; | ||
23 | } | ||
24 | _EOT | ||
25 | set -e | ||
26 | to 10 \ | ||
27 | pies --foreground --stderr \ | ||
28 | --config-file control.conf --config-file pies.conf --debug 1 2>errlog | ||
29 | |||
30 | cat inlog | ||
31 | cat log.err >&2 | ||
32 | ], | ||
33 | [0], | ||
34 | [line 1 | ||
35 | line 2 | ||
36 | stop | ||
37 | ]) | ||
38 | AT_CLEANUP | ||
diff --git a/tests/iobuf.h b/tests/iobuf.h new file mode 100644 index 0000000..4e43338 --- a/dev/null +++ b/tests/iobuf.h | |||
@@ -0,0 +1,141 @@ | |||
1 | /* This file is part of GNU Pies. | ||
2 | Copyright (C) 2019 Sergey Poznyakoff | ||
3 | |||
4 | GNU Pies is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Pies is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #define IO_BUF_SIZE 512 | ||
18 | |||
19 | struct iobuf | ||
20 | { | ||
21 | char buf[IO_BUF_SIZE]; /* Initial line buffer */ | ||
22 | size_t start; /* Start of data */ | ||
23 | size_t avail; /* Start of available space */ | ||
24 | }; | ||
25 | |||
26 | static inline void | ||
27 | iobuf_reset (struct iobuf *bp) | ||
28 | { | ||
29 | bp->start = bp->avail = 0; | ||
30 | } | ||
31 | |||
32 | /* Return the count of data bytes in the buffer */ | ||
33 | static inline size_t | ||
34 | iobuf_data_size (struct iobuf *bp) | ||
35 | { | ||
36 | return bp->avail - bp->start; | ||
37 | } | ||
38 | |||
39 | static inline char * | ||
40 | iobuf_data_ptr (struct iobuf *bp) | ||
41 | { | ||
42 | return bp->buf + bp->start; | ||
43 | } | ||
44 | |||
45 | static inline void | ||
46 | iobuf_data_advance (struct iobuf *bp, size_t n) | ||
47 | { | ||
48 | bp->start += n; | ||
49 | if (bp->start == bp->avail) | ||
50 | iobuf_reset (bp); | ||
51 | } | ||
52 | |||
53 | static inline int | ||
54 | iobuf_putback (struct iobuf *bp) | ||
55 | { | ||
56 | return bp->buf[--bp->start-1]; | ||
57 | } | ||
58 | |||
59 | static inline int | ||
60 | iobuf_getc (struct iobuf *bp) | ||
61 | { | ||
62 | int c = -1; | ||
63 | if (iobuf_data_size (bp) > 0) | ||
64 | { | ||
65 | c = *iobuf_data_ptr (bp); | ||
66 | iobuf_data_advance(bp, 1); | ||
67 | } | ||
68 | return c; | ||
69 | } | ||
70 | |||
71 | /* Return the count of available bytes in the buffer */ | ||
72 | static inline size_t | ||
73 | iobuf_avail_size (struct iobuf *bp) | ||
74 | { | ||
75 | return sizeof (bp->buf) - bp->avail; | ||
76 | } | ||
77 | |||
78 | static inline char * | ||
79 | iobuf_avail_ptr (struct iobuf *bp) | ||
80 | { | ||
81 | return bp->buf + bp->avail; | ||
82 | } | ||
83 | |||
84 | static inline void | ||
85 | iobuf_avail_advance (struct iobuf *bp, size_t n) | ||
86 | { | ||
87 | bp->avail += n; | ||
88 | if (iobuf_avail_size (bp) == 0 && iobuf_data_size (bp) == 0) | ||
89 | iobuf_reset (bp); | ||
90 | } | ||
91 | |||
92 | static inline int | ||
93 | iobuf_putc (struct iobuf *bp, int c) | ||
94 | { | ||
95 | if (iobuf_avail_size (bp) > 0) | ||
96 | { | ||
97 | *iobuf_avail_ptr (bp) = c; | ||
98 | iobuf_avail_advance (bp, 1); | ||
99 | return c; | ||
100 | } | ||
101 | return -1; | ||
102 | } | ||
103 | |||
104 | static inline ssize_t | ||
105 | iobuf_fill (struct iobuf *bp, int fd) | ||
106 | { | ||
107 | ssize_t n = read (fd, iobuf_avail_ptr (bp), iobuf_avail_size (bp)); | ||
108 | if (n >= 0) | ||
109 | iobuf_avail_advance (bp, n); | ||
110 | return n; | ||
111 | } | ||
112 | |||
113 | static inline ssize_t | ||
114 | iobuf_flush (struct iobuf *bp, int fd) | ||
115 | { | ||
116 | ssize_t n = write (fd, iobuf_data_ptr (bp), iobuf_data_size (bp)); | ||
117 | if (n >= 0) | ||
118 | iobuf_data_advance (bp, n); | ||
119 | return n; | ||
120 | } | ||
121 | |||
122 | static inline ssize_t | ||
123 | iobuf_copy (struct iobuf *dst, struct iobuf *src) | ||
124 | { | ||
125 | ssize_t n = iobuf_data_size (src); | ||
126 | if (n > 0) | ||
127 | { | ||
128 | ssize_t avail = iobuf_avail_size (dst); | ||
129 | if (avail < n) | ||
130 | n = avail; | ||
131 | if (n) | ||
132 | { | ||
133 | memcpy (iobuf_avail_ptr (dst), iobuf_data_ptr (src), n); | ||
134 | iobuf_avail_advance (dst, n); | ||
135 | iobuf_data_advance (src, n); | ||
136 | } | ||
137 | } | ||
138 | return 0; | ||
139 | } | ||
140 | |||
141 | |||
diff --git a/tests/nt.c b/tests/nt.c new file mode 100644 index 0000000..6ee18f8 --- a/dev/null +++ b/tests/nt.c | |||
@@ -0,0 +1,339 @@ | |||
1 | /* This file is part of GNU Pies. | ||
2 | Copyright (C) 2019 Sergey Poznyakoff | ||
3 | |||
4 | GNU Pies is free software; you can redistribute it and/or modify | ||
5 | it under the terms of the GNU General Public License as published by | ||
6 | the Free Software Foundation; either version 3, or (at your option) | ||
7 | any later version. | ||
8 | |||
9 | GNU Pies is distributed in the hope that it will be useful, | ||
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
12 | GNU General Public License for more details. | ||
13 | |||
14 | You should have received a copy of the GNU General Public License | ||
15 | along with GNU Pies. If not, see <http://www.gnu.org/licenses/>. */ | ||
16 | |||
17 | #include <config.h> | ||
18 | #include <stdio.h> | ||
19 | #include <stdlib.h> | ||
20 | #include <sys/types.h> | ||
21 | #include <sys/stat.h> | ||
22 | #include <fcntl.h> | ||
23 | #include <unistd.h> | ||
24 | #include <poll.h> | ||
25 | #include <errno.h> | ||
26 | #include <libpies.h> | ||
27 | #include <iobuf.h> | ||
28 | |||
29 | typedef struct netcat_server netcat_server_t; | ||
30 | typedef struct netcat_stream netcat_stream_t; | ||
31 | typedef ssize_t (*netcat_stream_io_t) (netcat_server_t *srv); | ||
32 | typedef int (*netcat_stream_disconnect_t) (netcat_server_t *srv); | ||
33 | |||
34 | enum { IN, OUT }; | ||
35 | |||
36 | struct netcat_server | ||
37 | { | ||
38 | char const *id; | ||
39 | netcat_server_t *next, *prev; | ||
40 | struct pollfd *pollfd; | ||
41 | int state; | ||
42 | netcat_stream_disconnect_t disconnect; | ||
43 | netcat_server_t *peer; | ||
44 | struct iobuf buf[2]; | ||
45 | }; | ||
46 | |||
47 | static netcat_server_t *server_head, *server_tail; | ||
48 | |||
49 | netcat_server_t * | ||
50 | netcat_server_create (char const *id, struct pollfd *pfd, int state, | ||
51 | netcat_stream_disconnect_t dis, netcat_server_t *peer) | ||
52 | { | ||
53 | netcat_server_t *srv = grecs_zalloc (sizeof (*srv)); | ||
54 | srv->id = id; | ||
55 | srv->pollfd = pfd; | ||
56 | srv->state = state; | ||
57 | srv->pollfd->events |= srv->state; | ||
58 | srv->disconnect = dis; | ||
59 | srv->peer = peer; | ||
60 | if (peer) | ||
61 | srv->peer->peer = srv; | ||
62 | iobuf_reset (&srv->buf[IN]); | ||
63 | iobuf_reset (&srv->buf[OUT]); | ||
64 | |||
65 | srv->prev = server_tail; | ||
66 | srv->next = NULL; | ||
67 | if (server_tail) | ||
68 | server_tail->next = srv; | ||
69 | else | ||
70 | server_head = srv; | ||
71 | server_tail = srv; | ||
72 | |||
73 | return srv; | ||
74 | } | ||
75 | |||
76 | void | ||
77 | netcat_server_remove (netcat_server_t *srv) | ||
78 | { | ||
79 | netcat_server_t *p; | ||
80 | if ((p = srv->next) != NULL) | ||
81 | p->prev = srv->prev; | ||
82 | else | ||
83 | server_tail = srv->prev; | ||
84 | if ((p = srv->prev) != NULL) | ||
85 | p->next = srv->next; | ||
86 | else | ||
87 | server_head = srv->next; | ||
88 | if (srv->peer) | ||
89 | srv->peer->peer = NULL; | ||
90 | free (srv); | ||
91 | } | ||
92 | |||
93 | /* | ||
94 | net_reader | ||
95 | 1. If there is free space in the IN buffer, fill it with the data read | ||
96 | from the fd and return | ||
97 | 2. Otherwise, clear the POLLIN bit. | ||
98 | |||
99 | stdout_writer (peer -> net_reader) | ||
100 | 1. If OUT buffer is empty | ||
101 | 1.1 If the peer's IN buffer is not empty, transfer data from it | ||
102 | 1.2 Else raise the peers POLLIN bit and return. | ||
103 | 2. Write as much as possible from OUT to fd | ||
104 | |||
105 | stdin_reader (same as net_reader) | ||
106 | |||
107 | net_writer (peer -> stdin_reader) same as stdout_writer | ||
108 | */ | ||
109 | |||
110 | ssize_t | ||
111 | netcat_stream_read (netcat_server_t *srv) | ||
112 | { | ||
113 | ssize_t n; | ||
114 | |||
115 | if (iobuf_avail_size (&srv->buf[IN])) | ||
116 | { | ||
117 | n = iobuf_fill (&srv->buf[IN], srv->pollfd->fd); | ||
118 | if (n == -1) | ||
119 | { | ||
120 | grecs_error (NULL, errno, "%s: read", srv->id); | ||
121 | srv->pollfd->events &= ~POLLIN; | ||
122 | return -1; | ||
123 | } | ||
124 | if (n == 0) | ||
125 | { | ||
126 | /* No more input is expected */ | ||
127 | srv->disconnect (srv); | ||
128 | srv->state &= ~POLLIN; | ||
129 | srv->pollfd->events &= ~POLLIN; | ||
130 | if (srv->pollfd->events == 0) | ||
131 | srv->pollfd->fd = -1; | ||
132 | } | ||
133 | } | ||
134 | else | ||
135 | { | ||
136 | srv->pollfd->events &= ~POLLIN; | ||
137 | n = 0; /* catch timeout? */ | ||
138 | } | ||
139 | return n; | ||
140 | } | ||
141 | |||
142 | static inline int | ||
143 | peer_is_state (netcat_server_t *srv, int state) | ||
144 | { | ||
145 | return srv->peer && (srv->peer->state & state); | ||
146 | } | ||
147 | |||
148 | ssize_t | ||
149 | netcat_stream_write (netcat_server_t *srv) | ||
150 | { | ||
151 | ssize_t n; | ||
152 | |||
153 | if (iobuf_data_size (&srv->buf[OUT]) == 0) | ||
154 | { | ||
155 | if (!peer_is_state (srv, POLLIN)) | ||
156 | { | ||
157 | // shutdown write end | ||
158 | srv->disconnect (srv); | ||
159 | srv->state &= ~POLLOUT; | ||
160 | srv->pollfd->events &= ~POLLOUT; | ||
161 | if (srv->pollfd->events == 0) | ||
162 | srv->pollfd->fd = -1; | ||
163 | return -1; | ||
164 | } | ||
165 | if (iobuf_copy (&srv->buf[OUT], &srv->peer->buf[IN]) == 0) | ||
166 | { | ||
167 | srv->peer->pollfd->events |= POLLIN; | ||
168 | return 0; | ||
169 | } | ||
170 | } | ||
171 | n = iobuf_flush (&srv->buf[OUT], srv->pollfd->fd); | ||
172 | if (n == -1) | ||
173 | { | ||
174 | grecs_error (NULL, errno, "%s: write", srv->id); | ||
175 | return -1; | ||
176 | } | ||
177 | if (n == 0) | ||
178 | { | ||
179 | // FIXME: eof | ||
180 | return -1; | ||
181 | } | ||
182 | return 0; | ||
183 | } | ||
184 | |||
185 | int | ||
186 | disconnect_in (netcat_server_t *srv) | ||
187 | { | ||
188 | return shutdown (srv->pollfd->fd, SHUT_RD); | ||
189 | } | ||
190 | |||
191 | int | ||
192 | disconnect_out (netcat_server_t *srv) | ||
193 | { | ||
194 | return shutdown (srv->pollfd->fd, SHUT_WR); | ||
195 | } | ||
196 | |||
197 | int | ||
198 | disconnect_stdin (netcat_server_t *srv) | ||
199 | { | ||
200 | return close (srv->pollfd->fd); | ||
201 | } | ||
202 | |||
203 | int | ||
204 | disconnect_stdout (netcat_server_t *srv) | ||
205 | { | ||
206 | close (srv->pollfd->fd); | ||
207 | exit (0); | ||
208 | } | ||
209 | |||
210 | static int | ||
211 | netcat (char const *urlstr) | ||
212 | { | ||
213 | int fd; | ||
214 | struct pies_url *url; | ||
215 | struct pollfd pfd[3]; | ||
216 | int nfd = sizeof (pfd) / sizeof (pfd[0]); | ||
217 | netcat_server_t *srvin, *srvout, *srv; | ||
218 | |||
219 | if (pies_url_create (&url, urlstr)) | ||
220 | { | ||
221 | perror (urlstr); | ||
222 | return 64; | ||
223 | } | ||
224 | |||
225 | fd = url_connect (url, NULL); | ||
226 | if (fd == -1) | ||
227 | return 1; | ||
228 | |||
229 | pfd[0].fd = 0; | ||
230 | pfd[0].events = 0; | ||
231 | srvin = netcat_server_create ("stdin", &pfd[0], POLLIN, disconnect_stdin, NULL); | ||
232 | |||
233 | pfd[1].fd = 1; | ||
234 | pfd[1].events = 0; | ||
235 | srvout = netcat_server_create ("stdout", &pfd[1], POLLOUT, disconnect_stdout, NULL); | ||
236 | |||
237 | pfd[2].fd = fd; | ||
238 | pfd[2].events = 0; | ||
239 | |||
240 | netcat_server_create ("netread", &pfd[2], POLLIN, disconnect_in, srvout); | ||
241 | netcat_server_create ("netwrite", &pfd[2], POLLOUT, disconnect_out, srvin); | ||
242 | |||
243 | while (server_head) | ||
244 | { | ||
245 | ssize_t n = poll (pfd, nfd, -1); | ||
246 | if (n == -1) | ||
247 | { | ||
248 | if (errno != EINTR) | ||
249 | grecs_error (NULL, errno, "poll"); | ||
250 | continue; | ||
251 | } | ||
252 | for (srv = server_head; srv; ) | ||
253 | { | ||
254 | netcat_server_t *next = srv->next; | ||
255 | int events; | ||
256 | |||
257 | events = (srv->pollfd->events|POLLHUP) | ||
258 | & (srv->pollfd->revents & (srv->state|POLLHUP)); | ||
259 | if (events) | ||
260 | { | ||
261 | if (events & POLLHUP) | ||
262 | { | ||
263 | //grecs_error (NULL, 0, "HUP on %s", srv->id); | ||
264 | srv->disconnect (srv); | ||
265 | srv->pollfd->events &= ~srv->state; | ||
266 | if (srv->pollfd->events == 0) | ||
267 | srv->pollfd->fd = -1; | ||
268 | srv->state = 0; | ||
269 | } | ||
270 | else if (events & POLLIN) | ||
271 | netcat_stream_read (srv); | ||
272 | else if (events & POLLOUT) | ||
273 | netcat_stream_write (srv); | ||
274 | } | ||
275 | if (srv->state == 0 || srv->pollfd->fd == -1) | ||
276 | netcat_server_remove (srv); | ||
277 | srv = next; | ||
278 | } | ||
279 | } | ||
280 | return 0; | ||
281 | } | ||
282 | |||
283 | static void | ||
284 | redirect (int sfd, char const *name) | ||
285 | { | ||
286 | int fd; | ||
287 | |||
288 | fd = open (name, sfd ? (O_WRONLY | O_TRUNC) : O_RDONLY); | ||
289 | if (!fd) | ||
290 | { | ||
291 | perror (name); | ||
292 | exit (1); | ||
293 | } | ||
294 | if (dup2 (fd, sfd)) | ||
295 | { | ||
296 | perror ("dup2"); | ||
297 | exit (1); | ||
298 | } | ||
299 | } | ||
300 | |||
301 | static void | ||
302 | usage (FILE *fp) | ||
303 | { | ||
304 | fprintf (fp, "usage: nt [-i FILE] [-o FILE] URL\n"); | ||
305 | } | ||
306 | |||
307 | int | ||
308 | main (int argc, char **argv) | ||
309 | { | ||
310 | int c; | ||
311 | |||
312 | while ((c = getopt (argc, argv, "i:o:")) != EOF) | ||
313 | { | ||
314 | switch (c) | ||
315 | { | ||
316 | case 'i': | ||
317 | redirect (0, optarg); | ||
318 | break; | ||
319 | |||
320 | case 'o': | ||
321 | redirect (1, optarg); | ||
322 | break; | ||
323 | |||
324 | default: | ||
325 | exit (64); | ||
326 | } | ||
327 | } | ||
328 | |||
329 | argc -= optind; | ||
330 | argv += optind; | ||
331 | |||
332 | if (argc != 1) | ||
333 | { | ||
334 | usage (stderr); | ||
335 | exit (64); | ||
336 | } | ||
337 | |||
338 | return netcat (argv[0]); | ||
339 | } | ||
diff --git a/tests/testsuite.at b/tests/testsuite.at index e340a2b..822ac7b 100644 --- a/tests/testsuite.at +++ b/tests/testsuite.at | |||
@@ -68,6 +68,7 @@ m4_include([ret-notify.at]) | |||
68 | m4_include([startup.at]) | 68 | m4_include([startup.at]) |
69 | m4_include([shutdown.at]) | 69 | m4_include([shutdown.at]) |
70 | m4_include([shell.at]) | 70 | m4_include([shell.at]) |
71 | m4_include([inet.at]) | ||
71 | 72 | ||
72 | m4_include([envop.at]) | 73 | m4_include([envop.at]) |
73 | m4_include([env.at]) \ No newline at end of file | 74 | m4_include([env.at]) \ No newline at end of file |
@@ -1,9 +1,28 @@ | |||
1 | #include <config.h> | ||
1 | #include <stdlib.h> | 2 | #include <stdlib.h> |
2 | #include <stdio.h> | 3 | #include <stdio.h> |
3 | #include <errno.h> | 4 | #include <errno.h> |
4 | #include <unistd.h> | 5 | #include <unistd.h> |
5 | #include <sys/types.h> | 6 | #include <sys/types.h> |
6 | #include <sys/wait.h> | 7 | #include <sys/wait.h> |
8 | #include <signal.h> | ||
9 | |||
10 | int volatile got_sigchld, got_sigalrm; | ||
11 | |||
12 | void | ||
13 | sighan (int sig) | ||
14 | { | ||
15 | switch (sig) | ||
16 | { | ||
17 | case SIGCHLD: | ||
18 | got_sigchld = 1; | ||
19 | break; | ||
20 | |||
21 | case SIGALRM: | ||
22 | got_sigalrm = 1; | ||
23 | break; | ||
24 | } | ||
25 | } | ||
7 | 26 | ||
8 | int | 27 | int |
9 | main (int argc, char **argv) | 28 | main (int argc, char **argv) |
@@ -13,7 +32,7 @@ main (int argc, char **argv) | |||
13 | char *p; | 32 | char *p; |
14 | pid_t pid, ret; | 33 | pid_t pid, ret; |
15 | int status; | 34 | int status; |
16 | 35 | ||
17 | if (argc < 3) | 36 | if (argc < 3) |
18 | { | 37 | { |
19 | fprintf (stderr, "usage: %s TIMEOUT COMMAND ...\n", progname); | 38 | fprintf (stderr, "usage: %s TIMEOUT COMMAND ...\n", progname); |
@@ -30,13 +49,16 @@ main (int argc, char **argv) | |||
30 | argc -= 2; | 49 | argc -= 2; |
31 | argv += 2; | 50 | argv += 2; |
32 | 51 | ||
52 | signal (SIGALRM, sighan); | ||
53 | signal (SIGCHLD, sighan); | ||
54 | |||
33 | pid = fork (); | 55 | pid = fork (); |
34 | if (pid == -1) | 56 | if (pid == -1) |
35 | { | 57 | { |
36 | perror ("fork"); | 58 | perror ("fork"); |
37 | exit (127); | 59 | exit (127); |
38 | } | 60 | } |
39 | 61 | ||
40 | if (pid == 0) | 62 | if (pid == 0) |
41 | { | 63 | { |
42 | execvp (argv[0], argv); | 64 | execvp (argv[0], argv); |
@@ -45,8 +67,23 @@ main (int argc, char **argv) | |||
45 | } | 67 | } |
46 | 68 | ||
47 | alarm (n); | 69 | alarm (n); |
70 | while (1) | ||
71 | { | ||
72 | pause (); | ||
73 | if (got_sigchld) | ||
74 | { | ||
75 | alarm (0); | ||
76 | break; | ||
77 | } | ||
78 | if (got_sigalrm) | ||
79 | { | ||
80 | fprintf (stderr, "%s: timed out\n", progname); | ||
81 | kill (pid, SIGKILL); | ||
82 | exit (127); | ||
83 | } | ||
84 | } | ||
85 | |||
48 | ret = wait (&status); | 86 | ret = wait (&status); |
49 | alarm (0); | ||
50 | 87 | ||
51 | if (ret != pid) | 88 | if (ret != pid) |
52 | { | 89 | { |
@@ -56,7 +93,7 @@ main (int argc, char **argv) | |||
56 | 93 | ||
57 | if (WIFEXITED (status)) | 94 | if (WIFEXITED (status)) |
58 | return WEXITSTATUS (status); | 95 | return WEXITSTATUS (status); |
59 | 96 | ||
60 | if (WIFSIGNALED (status)) | 97 | if (WIFSIGNALED (status)) |
61 | fprintf (stderr, "%s: %s terminated on signal %d\n", progname, argv[0], | 98 | fprintf (stderr, "%s: %s terminated on signal %d\n", progname, argv[0], |
62 | WTERMSIG (status)); | 99 | WTERMSIG (status)); |
@@ -67,8 +104,3 @@ main (int argc, char **argv) | |||
67 | progname, argv[0], status); | 104 | progname, argv[0], status); |
68 | return 127; | 105 | return 127; |
69 | } | 106 | } |
70 | |||
71 | |||
72 | |||
73 | |||
74 | |||