| @@ -1,107 +1,107 @@ | | | @@ -1,107 +1,107 @@ |
1 | /* $NetBSD: h_intr.c,v 1.4 2021/07/09 20:00:26 kre Exp $ */ | | 1 | /* $NetBSD: h_intr.c,v 1.5 2021/07/10 07:50:20 christos Exp $ */ |
2 | | | 2 | |
3 | /** | | 3 | /** |
4 | * Test of interrupted I/O to popen()ed commands. | | 4 | * Test of interrupted I/O to popen()ed commands. |
5 | * | | 5 | * |
6 | * Example 1: | | 6 | * Example 1: |
7 | * ./h_intr -c "gzip -t" *.gz | | 7 | * ./h_intr -c "gzip -t" *.gz |
8 | * | | 8 | * |
9 | * Example 2: | | 9 | * Example 2: |
10 | * while :; do ./h_intr -b $((12*1024)) -t 10 -c "bzip2 -t" *.bz2; sleep 2; done | | 10 | * while :; do ./h_intr -b $((12*1024)) -t 10 -c "bzip2 -t" *.bz2; sleep 2; done |
11 | * | | 11 | * |
12 | * Example 3: | | 12 | * Example 3: |
13 | * Create checksum file: | | 13 | * Create checksum file: |
14 | * find /mnt -type f -exec sha512 -n {} + >SHA512 | | 14 | * find /mnt -type f -exec sha512 -n {} + >SHA512 |
15 | * | | 15 | * |
16 | * Check program: | | 16 | * Check program: |
17 | * find /mnt -type f -exec ./h_intr -b 512 -c run.sh {} + | | 17 | * find /mnt -type f -exec ./h_intr -b 512 -c run.sh {} + |
18 | * | | 18 | * |
19 | * ./run.sh: | | 19 | * ./run.sh: |
20 | #!/bin/sh | | 20 | #!/bin/sh |
21 | set -eu | | 21 | set -eu |
22 | grep -q "^$(sha512 -q)" SHA512 | | 22 | grep -q "^$(sha512 -q)" SHA512 |
23 | * | | 23 | * |
24 | * Author: RVP at sdf.org | | 24 | * Author: RVP at sdf.org |
25 | */ | | 25 | */ |
26 | | | 26 | |
27 | #include <sys/cdefs.h> | | 27 | #include <sys/cdefs.h> |
28 | __RCSID("$NetBSD: h_intr.c,v 1.4 2021/07/09 20:00:26 kre Exp $"); | | 28 | __RCSID("$NetBSD: h_intr.c,v 1.5 2021/07/10 07:50:20 christos Exp $"); |
29 | | | 29 | |
30 | #include <time.h> | | 30 | #include <time.h> |
31 | #include <err.h> | | 31 | #include <err.h> |
32 | #include <errno.h> | | 32 | #include <errno.h> |
33 | #include <stdbool.h> | | 33 | #include <stdbool.h> |
34 | #include <libgen.h> | | 34 | #include <libgen.h> |
35 | #include <signal.h> | | 35 | #include <signal.h> |
36 | #include <stdio.h> | | 36 | #include <stdio.h> |
37 | #include <stdlib.h> | | 37 | #include <stdlib.h> |
38 | #include <string.h> | | 38 | #include <string.h> |
39 | #include <unistd.h> | | 39 | #include <unistd.h> |
40 | | | 40 | |
41 | static bool process(const char *fn); | | 41 | static bool process(const char *fn); |
42 | ssize_t maxread(FILE *fp, void *buf, size_t size); | | 42 | ssize_t maxread(FILE *fp, void *buf, size_t size); |
43 | ssize_t smaxread(FILE *fp, void *buf, size_t size); | | 43 | ssize_t smaxread(FILE *fp, void *buf, size_t size); |
44 | ssize_t maxwrite(FILE *fp, const void *buf, size_t size); | | 44 | ssize_t maxwrite(FILE *fp, const void *buf, size_t size); |
45 | ssize_t smaxwrite(FILE *fp, const void *buf, size_t size); | | 45 | ssize_t smaxwrite(FILE *fp, const void *buf, size_t size); |
46 | static int rndbuf(void); | | 46 | static int rndbuf(void); |
47 | static int rndmode(void); | | 47 | static int rndmode(void); |
48 | static sig_t xsignal(int signo, sig_t handler); | | 48 | static sig_t xsignal(int signo, sig_t handler); |
49 | static void alarmtimer(int wait); | | 49 | static void alarmtimer(int wait); |
50 | static void pr_star(int signo); | | 50 | static void pr_star(int signo); |
51 | static int do_opts(int argc, char* argv[]); | | 51 | static int do_opts(int argc, char *argv[]); |
52 | static void usage(FILE *fp); | | 52 | static void usage(FILE *fp); |
53 | | | 53 | |
54 | /* Globals */ | | 54 | /* Globals */ |
55 | static struct options { | | 55 | static struct options { |
56 | const char* cmd; /* cmd to run (which must read from stdin) */ | | 56 | const char *cmd; /* cmd to run (which must read from stdin) */ |
57 | size_t bsize; /* block size to use */ | | 57 | size_t bsize; /* block size to use */ |
58 | size_t asize; /* alt. stdio buffer size */ | | 58 | size_t asize; /* alt. stdio buffer size */ |
59 | int btype; /* buffering type: _IONBF, ... */ | | 59 | int btype; /* buffering type: _IONBF, ... */ |
60 | int tmout; /* alarm timeout */ | | 60 | int tmout; /* alarm timeout */ |
61 | int flush; /* call fflush() after write if 1 */ | | 61 | int flush; /* call fflush() after write if 1 */ |
62 | int rndbuf; /* switch buffer randomly if 1 */ | | 62 | int rndbuf; /* switch buffer randomly if 1 */ |
63 | int rndmod; /* switch buffering modes randomly if 1 */ | | 63 | int rndmod; /* switch buffering modes randomly if 1 */ |
64 | } opts; | | 64 | } opts; |
65 | | | 65 | |
66 | static const struct { | | 66 | static const struct { |
67 | const char *name; | | 67 | const char *name; |
68 | int value; | | 68 | int value; |
69 | } btypes[] = { | | 69 | } btypes[] = { |
70 | { "IONBF", _IONBF }, | | 70 | { "IONBF", _IONBF }, |
71 | { "IOLBF", _IOLBF }, | | 71 | { "IOLBF", _IOLBF }, |
72 | { "IOFBF", _IOFBF }, | | 72 | { "IOFBF", _IOFBF }, |
73 | }; | | 73 | }; |
74 | | | 74 | |
75 | static void (*alarm_fn)(int); /* real/dummy alarm fn. */ | | 75 | static void (*alarm_fn)(int); /* real/dummy alarm fn. */ |
76 | static int (*sintr_fn)(int, int); /* " siginterrupt fn. */ | | 76 | static int (*sintr_fn)(int, int); /* " siginterrupt fn. */ |
77 | static ssize_t (*rd_fn)(FILE*, void*, size_t); /* read fn. */ | | 77 | static ssize_t (*rd_fn)(FILE *, void *, size_t); /* read fn. */ |
78 | static ssize_t (*wr_fn)(FILE*, const void*, size_t); /* write fn. */ | | 78 | static ssize_t (*wr_fn)(FILE *, const void *, size_t); /* write fn. */ |
79 | | | 79 | |
80 | enum { | | 80 | enum { |
81 | MB = 1024 * 1024, /* a megabyte */ | | 81 | MB = 1024 * 1024, /* a megabyte */ |
82 | BSIZE = 16 * 1024, /* default RW buffer size */ | | 82 | BSIZE = 16 * 1024, /* default RW buffer size */ |
83 | DEF_MS = 100, /* interrupt 10x a second */ | | 83 | DEF_MS = 100, /* interrupt 10x a second */ |
84 | MS = 1000, /* msecs. in a second */ | | 84 | MS = 1000, /* msecs. in a second */ |
85 | }; | | 85 | }; |
86 | | | 86 | |
87 | | | 87 | |
88 | | | 88 | |
89 | | | 89 | |
90 | /** | | 90 | /** |
91 | * M A I N | | 91 | * M A I N |
92 | */ | | 92 | */ |
93 | int | | 93 | int |
94 | main(int argc, char* argv[]) | | 94 | main(int argc, char *argv[]) |
95 | { | | 95 | { |
96 | int i, rc = EXIT_SUCCESS; | | 96 | int i, rc = EXIT_SUCCESS; |
97 | | | 97 | |
98 | i = do_opts(argc, argv); | | 98 | i = do_opts(argc, argv); |
99 | argc -= i; | | 99 | argc -= i; |
100 | argv += i; | | 100 | argv += i; |
101 | | | 101 | |
102 | if (argc == 0) { | | 102 | if (argc == 0) { |
103 | usage(stderr); | | 103 | usage(stderr); |
104 | return rc; | | 104 | return rc; |
105 | } | | 105 | } |
106 | | | 106 | |
107 | xsignal(SIGPIPE, SIG_IGN); | | 107 | xsignal(SIGPIPE, SIG_IGN); |
| @@ -195,55 +195,55 @@ process(const char *fn) | | | @@ -195,55 +195,55 @@ process(const char *fn) |
195 | rc = true; | | 195 | rc = true; |
196 | | | 196 | |
197 | fail: | | 197 | fail: |
198 | free(abuf); | | 198 | free(abuf); |
199 | free(buf); | | 199 | free(buf); |
200 | | | 200 | |
201 | return rc; | | 201 | return rc; |
202 | } | | 202 | } |
203 | | | 203 | |
204 | /** | | 204 | /** |
205 | * maxread - syscall version | | 205 | * maxread - syscall version |
206 | */ | | 206 | */ |
207 | ssize_t | | 207 | ssize_t |
208 | smaxread(FILE* fp, void* buf, size_t size) | | 208 | smaxread(FILE* fp, void *buf, size_t size) |
209 | { | | 209 | { |
210 | char* p = buf; | | 210 | char *p = buf; |
211 | ssize_t nrd = 0; | | 211 | ssize_t nrd = 0; |
212 | ssize_t n; | | 212 | ssize_t n; |
213 | | | 213 | |
214 | while (size > 0) { | | 214 | while (size > 0) { |
215 | n = read(fileno(fp), p, size); | | 215 | n = read(fileno(fp), p, size); |
216 | if (n < 0) { | | 216 | if (n < 0) { |
217 | if (errno == EINTR) | | 217 | if (errno == EINTR) |
218 | continue; | | 218 | continue; |
219 | else | | 219 | else |
220 | return -1; | | 220 | return -1; |
221 | } else if (n == 0) | | 221 | } else if (n == 0) |
222 | break; | | 222 | break; |
223 | p += n; | | 223 | p += n; |
224 | nrd += n; | | 224 | nrd += n; |
225 | size -= n; | | 225 | size -= n; |
226 | } | | 226 | } |
227 | return nrd; | | 227 | return nrd; |
228 | } | | 228 | } |
229 | | | 229 | |
230 | /** | | 230 | /** |
231 | * maxread - stdio version | | 231 | * maxread - stdio version |
232 | */ | | 232 | */ |
233 | ssize_t | | 233 | ssize_t |
234 | maxread(FILE* fp, void* buf, size_t size) | | 234 | maxread(FILE* fp, void *buf, size_t size) |
235 | { | | 235 | { |
236 | char* p = buf; | | 236 | char *p = buf; |
237 | ssize_t nrd = 0; | | 237 | ssize_t nrd = 0; |
238 | size_t n; | | 238 | size_t n; |
239 | | | 239 | |
240 | while (size > 0) { | | 240 | while (size > 0) { |
241 | errno = 0; | | 241 | errno = 0; |
242 | n = fread(p, 1, size, fp); | | 242 | n = fread(p, 1, size, fp); |
243 | if (n == 0) { | | 243 | if (n == 0) { |
244 | printf("ir."); | | 244 | printf("ir."); |
245 | fflush(stdout); | | 245 | fflush(stdout); |
246 | if (errno == EINTR) | | 246 | if (errno == EINTR) |
247 | continue; | | 247 | continue; |
248 | if (feof(fp) || nrd > 0) | | 248 | if (feof(fp) || nrd > 0) |
249 | break; | | 249 | break; |
| @@ -252,54 +252,54 @@ maxread(FILE* fp, void* buf, size_t size | | | @@ -252,54 +252,54 @@ maxread(FILE* fp, void* buf, size_t size |
252 | if (n != size) | | 252 | if (n != size) |
253 | clearerr(fp); | | 253 | clearerr(fp); |
254 | p += n; | | 254 | p += n; |
255 | nrd += n; | | 255 | nrd += n; |
256 | size -= n; | | 256 | size -= n; |
257 | } | | 257 | } |
258 | return nrd; | | 258 | return nrd; |
259 | } | | 259 | } |
260 | | | 260 | |
261 | /** | | 261 | /** |
262 | * maxwrite - syscall version | | 262 | * maxwrite - syscall version |
263 | */ | | 263 | */ |
264 | ssize_t | | 264 | ssize_t |
265 | smaxwrite(FILE* fp, const void* buf, size_t size) | | 265 | smaxwrite(FILE* fp, const void *buf, size_t size) |
266 | { | | 266 | { |
267 | const char* p = buf; | | 267 | const char *p = buf; |
268 | ssize_t nwr = 0; | | 268 | ssize_t nwr = 0; |
269 | ssize_t n; | | 269 | ssize_t n; |
270 | | | 270 | |
271 | while (size > 0) { | | 271 | while (size > 0) { |
272 | n = write(fileno(fp), p, size); | | 272 | n = write(fileno(fp), p, size); |
273 | if (n <= 0) { | | 273 | if (n <= 0) { |
274 | if (errno == EINTR) | | 274 | if (errno == EINTR) |
275 | n = 0; | | 275 | n = 0; |
276 | else | | 276 | else |
277 | return -1; | | 277 | return -1; |
278 | } | | 278 | } |
279 | p += n; | | 279 | p += n; |
280 | nwr += n; | | 280 | nwr += n; |
281 | size -= n; | | 281 | size -= n; |
282 | } | | 282 | } |
283 | return nwr; | | 283 | return nwr; |
284 | } | | 284 | } |
285 | | | 285 | |
286 | /** | | 286 | /** |
287 | * maxwrite - stdio version (warning: substrate may be buggy) | | 287 | * maxwrite - stdio version (warning: substrate may be buggy) |
288 | */ | | 288 | */ |
289 | ssize_t | | 289 | ssize_t |
290 | maxwrite(FILE* fp, const void* buf, size_t size) | | 290 | maxwrite(FILE* fp, const void *buf, size_t size) |
291 | { | | 291 | { |
292 | const char* p = buf; | | 292 | const char *p = buf; |
293 | ssize_t nwr = 0; | | 293 | ssize_t nwr = 0; |
294 | size_t n; | | 294 | size_t n; |
295 | | | 295 | |
296 | while (size > 0) { | | 296 | while (size > 0) { |
297 | errno = 0; | | 297 | errno = 0; |
298 | n = fwrite(p, 1, size, fp); | | 298 | n = fwrite(p, 1, size, fp); |
299 | if (n == 0) { | | 299 | if (n == 0) { |
300 | printf("iw."); | | 300 | printf("iw."); |
301 | fflush(stdout); | | 301 | fflush(stdout); |
302 | if (errno == EINTR) | | 302 | if (errno == EINTR) |
303 | continue; | | 303 | continue; |
304 | if (nwr > 0) | | 304 | if (nwr > 0) |
305 | break; | | 305 | break; |
| @@ -402,27 +402,27 @@ isvalid(const char *s) | | | @@ -402,27 +402,27 @@ isvalid(const char *s) |
402 | return strspn(s, " \t") != strlen(s); | | 402 | return strspn(s, " \t") != strlen(s); |
403 | } | | 403 | } |
404 | | | 404 | |
405 | static const char * | | 405 | static const char * |
406 | btype2str(int val) | | 406 | btype2str(int val) |
407 | { | | 407 | { |
408 | for (size_t i = 0; i < __arraycount(btypes); i++) | | 408 | for (size_t i = 0; i < __arraycount(btypes); i++) |
409 | if (btypes[i].value == val) | | 409 | if (btypes[i].value == val) |
410 | return btypes[i].name; | | 410 | return btypes[i].name; |
411 | return "*invalid*"; | | 411 | return "*invalid*"; |
412 | } | | 412 | } |
413 | | | 413 | |
414 | static int | | 414 | static int |
415 | str2btype(const char* s) | | 415 | str2btype(const char *s) |
416 | { | | 416 | { |
417 | for (size_t i = 0; i < __arraycount(btypes); i++) | | 417 | for (size_t i = 0; i < __arraycount(btypes); i++) |
418 | if (strcmp(btypes[i].name, s) == 0) | | 418 | if (strcmp(btypes[i].name, s) == 0) |
419 | return btypes[i].value; | | 419 | return btypes[i].value; |
420 | return EOF; | | 420 | return EOF; |
421 | } | | 421 | } |
422 | | | 422 | |
423 | /** | | 423 | /** |
424 | * Print usage information. | | 424 | * Print usage information. |
425 | */ | | 425 | */ |
426 | static void | | 426 | static void |
427 | usage(FILE* fp) | | 427 | usage(FILE* fp) |
428 | { | | 428 | { |