clang -cc1 -cc1 -triple amd64-unknown-openbsd7.4 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name ypserv.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 1 -pic-is-pie -mframe-pointer=all -relaxed-aliasing -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -target-feature +retpoline-indirect-calls -target-feature +retpoline-indirect-branches -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/usr/src/usr.sbin/ypserv/ypserv/obj -resource-dir /usr/local/llvm16/lib/clang/16 -D DAEMON -D OPTDB -I /usr/src/usr.sbin/ypserv/ypserv/../common -I . -internal-isystem /usr/local/llvm16/lib/clang/16/include -internal-externc-isystem /usr/include -O2 -fdebug-compilation-dir=/usr/src/usr.sbin/ypserv/ypserv/obj -ferror-limit 19 -fwrapv -D_RET_PROTECTOR -ret-protector -fcf-protection=branch -fno-jump-tables -fgnuc-version=4.2.1 -vectorize-loops -vectorize-slp -fno-builtin-malloc -fno-builtin-calloc -fno-builtin-realloc -fno-builtin-valloc -fno-builtin-free -fno-builtin-strdup -fno-builtin-strndup -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/ben/Projects/scan/2024-01-11-140451-98009-1 -x c /usr/src/usr.sbin/ypserv/ypserv/ypserv.c
1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
18 | |
19 | |
20 | |
21 | |
22 | |
23 | |
24 | |
25 | |
26 | |
27 | |
28 | |
29 | #include <sys/types.h> |
30 | #include <sys/socket.h> |
31 | #include <sys/ioctl.h> |
32 | #include <netinet/in.h> |
33 | #include <rpcsvc/yp.h> |
34 | #include "ypv1.h" |
35 | #include <stdio.h> |
36 | #include <stdlib.h> |
37 | #include <string.h> |
38 | #include <netdb.h> |
39 | #include <signal.h> |
40 | #include <errno.h> |
41 | #include <util.h> |
42 | #include <unistd.h> |
43 | #include <fcntl.h> |
44 | #include <rpc/pmap_clnt.h> |
45 | #include <ndbm.h> |
46 | #include <syslog.h> |
47 | #include "acl.h" |
48 | #include "yplog.h" |
49 | #include "ypdef.h" |
50 | #include "ypserv.h" |
51 | #include <sys/wait.h> |
52 | |
53 | void ypdb_init(void); |
54 | |
55 | #ifdef DEBUG |
56 | #define RPC_SVC_FG |
57 | #endif |
58 | |
59 | #define _RPCSVC_CLOSEDOWN 120 |
60 | static int _rpcpmstart; |
61 | static int _rpcfdtype; |
62 | static int _rpcsvcdirty; |
63 | |
64 | int usedns = FALSE; |
65 | char *aclfile = NULL; |
66 | |
67 | void sig_child(int); |
68 | void sig_hup(int); |
69 | volatile sig_atomic_t wantsighup; |
70 | |
71 | static void |
72 | _msgout(char *msg) |
73 | { |
74 | #ifdef RPC_SVC_FG |
75 | if (_rpcpmstart) |
76 | syslog(LOG_ERR, "%s", msg); |
77 | else |
78 | (void) fprintf(stderr, "%s\n", msg); |
79 | #else |
80 | syslog(LOG_ERR, "%s", msg); |
81 | #endif |
82 | } |
83 | |
84 | static void |
85 | closedown(int sig) |
86 | { |
87 | int save_errno = errno; |
88 | |
89 | if (_rpcsvcdirty == 0) { |
90 | int i, openfd; |
91 | |
92 | if (_rpcfdtype == SOCK_DGRAM) |
93 | exit(0); |
94 | for (i = 0, openfd = 0; i < svc_max_pollfd && openfd < 2; i++) |
95 | if (svc_pollfd[i].fd != -1) |
96 | openfd++; |
97 | if (openfd <= (_rpcpmstart ? 0 : 1)) |
98 | _exit(0); |
99 | } |
100 | (void) alarm(_RPCSVC_CLOSEDOWN); |
101 | errno = save_errno; |
102 | } |
103 | |
104 | static void |
105 | ypprog_1(struct svc_req *rqstp, SVCXPRT *transp) |
106 | { |
107 | union { |
108 | domainname ypoldproc_domain_1_arg; |
109 | domainname ypoldproc_domain_nonack_1_arg; |
110 | yprequest ypoldproc_match_1_arg; |
111 | yprequest ypoldproc_first_1_arg; |
112 | yprequest ypoldproc_next_1_arg; |
113 | yprequest ypoldproc_poll_1_arg; |
114 | yprequest ypoldproc_push_1_arg; |
115 | yprequest ypoldproc_pull_1_arg; |
116 | yprequest ypoldproc_get_1_arg; |
117 | } argument; |
118 | char *result; |
119 | xdrproc_t xdr_argument, xdr_result; |
120 | char *(*local)(char *, struct svc_req *); |
121 | |
122 | _rpcsvcdirty = 1; |
123 | switch (rqstp->rq_proc) { |
124 | case YPOLDPROC_NULL: |
125 | xdr_argument = (xdrproc_t) xdr_void; |
126 | xdr_result = (xdrproc_t) xdr_void; |
127 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_null_1_svc; |
128 | break; |
129 | |
130 | case YPOLDPROC_DOMAIN: |
131 | xdr_argument = (xdrproc_t) xdr_domainname; |
132 | xdr_result = (xdrproc_t) xdr_bool; |
133 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_domain_1_svc; |
134 | break; |
135 | |
136 | case YPOLDPROC_DOMAIN_NONACK: |
137 | xdr_argument = (xdrproc_t) xdr_domainname; |
138 | xdr_result = (xdrproc_t) xdr_bool; |
139 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_domain_nonack_1_svc; |
140 | break; |
141 | |
142 | case YPOLDPROC_MATCH: |
143 | xdr_argument = (xdrproc_t) xdr_yprequest; |
144 | xdr_result = (xdrproc_t) xdr_ypresponse; |
145 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_match_1_svc; |
146 | break; |
147 | |
148 | case YPOLDPROC_FIRST: |
149 | xdr_argument = (xdrproc_t) xdr_yprequest; |
150 | xdr_result = (xdrproc_t) xdr_ypresponse; |
151 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_first_1_svc; |
152 | break; |
153 | |
154 | case YPOLDPROC_NEXT: |
155 | xdr_argument = (xdrproc_t) xdr_yprequest; |
156 | xdr_result = (xdrproc_t) xdr_ypresponse; |
157 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_next_1_svc; |
158 | break; |
159 | |
160 | case YPOLDPROC_POLL: |
161 | xdr_argument = (xdrproc_t) xdr_yprequest; |
162 | xdr_result = (xdrproc_t) xdr_ypresponse; |
163 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_poll_1_svc; |
164 | break; |
165 | |
166 | case YPOLDPROC_PUSH: |
167 | xdr_argument = (xdrproc_t) xdr_yprequest; |
168 | xdr_result = (xdrproc_t) xdr_void; |
169 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_push_1_svc; |
170 | break; |
171 | |
172 | case YPOLDPROC_PULL: |
173 | xdr_argument = (xdrproc_t) xdr_yprequest; |
174 | xdr_result = (xdrproc_t) xdr_void; |
175 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_pull_1_svc; |
176 | break; |
177 | |
178 | case YPOLDPROC_GET: |
179 | xdr_argument = (xdrproc_t) xdr_yprequest; |
180 | xdr_result = (xdrproc_t) xdr_void; |
181 | local = (char *(*)(char *, struct svc_req *)) ypoldproc_get_1_svc; |
182 | break; |
183 | |
184 | default: |
185 | svcerr_noproc(transp); |
186 | _rpcsvcdirty = 0; |
187 | return; |
188 | } |
189 | (void) memset(&argument, 0, sizeof(argument)); |
190 | if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { |
191 | svcerr_decode(transp); |
192 | _rpcsvcdirty = 0; |
193 | return; |
194 | } |
195 | result = (*local)((char *)&argument, rqstp); |
196 | if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { |
197 | svcerr_systemerr(transp); |
198 | } |
199 | if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { |
200 | _msgout("unable to free arguments"); |
201 | exit(1); |
202 | } |
203 | _rpcsvcdirty = 0; |
204 | } |
205 | |
206 | static void |
207 | ypprog_2(struct svc_req *rqstp, SVCXPRT *transp) |
208 | { |
209 | union { |
210 | domainname ypproc_domain_2_arg; |
211 | domainname ypproc_domain_nonack_2_arg; |
212 | ypreq_key ypproc_match_2_arg; |
213 | ypreq_nokey ypproc_first_2_arg; |
214 | ypreq_key ypproc_next_2_arg; |
215 | ypreq_xfr ypproc_xfr_2_arg; |
216 | ypreq_nokey ypproc_all_2_arg; |
217 | ypreq_nokey ypproc_master_2_arg; |
218 | ypreq_nokey ypproc_order_2_arg; |
219 | domainname ypproc_maplist_2_arg; |
220 | } argument; |
221 | char *result; |
222 | xdrproc_t xdr_argument, xdr_result; |
223 | char *(*local)(char *, struct svc_req *); |
224 | |
225 | _rpcsvcdirty = 1; |
226 | switch (rqstp->rq_proc) { |
227 | case YPPROC_NULL: |
228 | xdr_argument = (xdrproc_t) xdr_void; |
229 | xdr_result = (xdrproc_t) xdr_void; |
230 | local = (char *(*)(char *, struct svc_req *)) ypproc_null_2_svc; |
231 | break; |
232 | |
233 | case YPPROC_DOMAIN: |
234 | xdr_argument = (xdrproc_t) xdr_domainname; |
235 | xdr_result = (xdrproc_t) xdr_bool; |
236 | local = (char *(*)(char *, struct svc_req *)) ypproc_domain_2_svc; |
237 | break; |
238 | |
239 | case YPPROC_DOMAIN_NONACK: |
240 | xdr_argument = (xdrproc_t) xdr_domainname; |
241 | xdr_result = (xdrproc_t) xdr_bool; |
242 | local = (char *(*)(char *, struct svc_req *)) ypproc_domain_nonack_2_svc; |
243 | break; |
244 | |
245 | case YPPROC_MATCH: |
246 | xdr_argument = (xdrproc_t) xdr_ypreq_key; |
247 | xdr_result = (xdrproc_t) xdr_ypresp_val; |
248 | local = (char *(*)(char *, struct svc_req *)) ypproc_match_2_svc; |
249 | break; |
250 | |
251 | case YPPROC_FIRST: |
252 | xdr_argument = (xdrproc_t) xdr_ypreq_nokey; |
253 | xdr_result = (xdrproc_t) xdr_ypresp_key_val; |
254 | local = (char *(*)(char *, struct svc_req *)) ypproc_first_2_svc; |
255 | break; |
256 | |
257 | case YPPROC_NEXT: |
258 | xdr_argument = (xdrproc_t) xdr_ypreq_key; |
259 | xdr_result = (xdrproc_t) xdr_ypresp_key_val; |
260 | local = (char *(*)(char *, struct svc_req *)) ypproc_next_2_svc; |
261 | break; |
262 | |
263 | case YPPROC_XFR: |
264 | xdr_argument = (xdrproc_t) xdr_ypreq_xfr; |
265 | xdr_result = (xdrproc_t) xdr_ypresp_xfr; |
266 | local = (char *(*)(char *, struct svc_req *)) ypproc_xfr_2_svc; |
267 | break; |
268 | |
269 | case YPPROC_CLEAR: |
270 | xdr_argument = (xdrproc_t) xdr_void; |
271 | xdr_result = (xdrproc_t) xdr_void; |
272 | local = (char *(*)(char *, struct svc_req *)) ypproc_clear_2_svc; |
273 | break; |
274 | |
275 | case YPPROC_ALL: |
276 | xdr_argument = (xdrproc_t) xdr_ypreq_nokey; |
277 | xdr_result = (xdrproc_t) xdr_ypresp_all; |
278 | local = (char *(*)(char *, struct svc_req *)) ypproc_all_2_svc; |
279 | break; |
280 | |
281 | case YPPROC_MASTER: |
282 | xdr_argument = (xdrproc_t) xdr_ypreq_nokey; |
283 | xdr_result = (xdrproc_t) xdr_ypresp_master; |
284 | local = (char *(*)(char *, struct svc_req *)) ypproc_master_2_svc; |
285 | break; |
286 | |
287 | case YPPROC_ORDER: |
288 | xdr_argument = (xdrproc_t) xdr_ypreq_nokey; |
289 | xdr_result = (xdrproc_t) xdr_ypresp_order; |
290 | local = (char *(*)(char *, struct svc_req *)) ypproc_order_2_svc; |
291 | break; |
292 | |
293 | case YPPROC_MAPLIST: |
294 | xdr_argument = (xdrproc_t) xdr_domainname; |
295 | xdr_result = (xdrproc_t) xdr_ypresp_maplist; |
296 | local = (char *(*)(char *, struct svc_req *)) ypproc_maplist_2_svc; |
297 | break; |
298 | |
299 | default: |
300 | svcerr_noproc(transp); |
301 | _rpcsvcdirty = 0; |
302 | return; |
303 | } |
304 | (void) memset(&argument, 0, sizeof(argument)); |
305 | if (!svc_getargs(transp, xdr_argument, (caddr_t)&argument)) { |
306 | svcerr_decode(transp); |
307 | _rpcsvcdirty = 0; |
308 | return; |
309 | } |
310 | result = (*local)((char *)&argument, rqstp); |
311 | if (result != NULL && !svc_sendreply(transp, xdr_result, result)) { |
312 | svcerr_systemerr(transp); |
313 | } |
314 | if (!svc_freeargs(transp, xdr_argument, (caddr_t)&argument)) { |
315 | _msgout("unable to free arguments"); |
316 | exit(1); |
317 | } |
318 | _rpcsvcdirty = 0; |
319 | } |
320 | |
321 | static void |
322 | hup(void) |
323 | { |
324 | |
325 | ypcloselog(); |
326 | ypopenlog(); |
327 | |
328 | acl_reset(); |
329 | if (aclfile != NULL) { |
330 | yplog("sig_hup: reread %s", aclfile); |
331 | (void)acl_init(aclfile); |
332 | } else { |
333 | yplog("sig_hup: reread %s", YP_SECURENET_FILE); |
334 | (void)acl_securenet(YP_SECURENET_FILE); |
335 | } |
336 | |
337 | ypdb_close_all(); |
338 | } |
339 | |
340 | static void |
341 | my_svc_run(void) |
342 | { |
343 | struct pollfd *pfd = NULL, *newp; |
| 28 | | 'pfd' initialized to a null pointer value | |
|
344 | int nready, saved_max_pollfd = 0; |
345 | |
346 | for (;;) { |
| 29 | | Loop condition is true. Entering loop body | |
|
347 | if (wantsighup) { |
| 30 | | Assuming 'wantsighup' is 0 | |
|
| |
348 | wantsighup = 0; |
349 | hup(); |
350 | } |
351 | if (svc_max_pollfd > saved_max_pollfd) { |
| 32 | | Assuming 'svc_max_pollfd' is <= 'saved_max_pollfd' | |
|
| |
352 | newp = reallocarray(pfd, svc_max_pollfd, sizeof(*pfd)); |
353 | if (newp == NULL) { |
354 | free(pfd); |
355 | perror("svc_run: - realloc failed"); |
356 | return; |
357 | } |
358 | pfd = newp; |
359 | saved_max_pollfd = svc_max_pollfd; |
360 | } |
361 | memcpy(pfd, svc_pollfd, sizeof(*pfd) * svc_max_pollfd); |
| 34 | | Null pointer passed as 1st argument to memory copy function |
|
362 | |
363 | nready = poll(pfd, svc_max_pollfd, INFTIM); |
364 | switch (nready) { |
365 | case -1: |
366 | if (errno == EINTR) |
367 | continue; |
368 | perror("svc_run: - poll failed"); |
369 | free(pfd); |
370 | return; |
371 | case 0: |
372 | continue; |
373 | default: |
374 | svc_getreq_poll(pfd, nready); |
375 | } |
376 | } |
377 | } |
378 | |
379 | static void |
380 | usage(void) |
381 | { |
382 | (void)fprintf(stderr, "usage: ypserv [-1dx] [-a aclfile]\n"); |
383 | exit(1); |
384 | } |
385 | |
386 | int |
387 | main(int argc, char *argv[]) |
388 | { |
389 | int xflag = 0, allowv1 = 0, ch, sock, proto; |
390 | struct sockaddr_in saddr; |
391 | socklen_t asize = sizeof(saddr); |
392 | extern char *optarg; |
393 | SVCXPRT *transp = NULL; |
394 | |
395 | while ((ch = getopt(argc, argv, "1a:dx")) != -1) |
| 1 | Assuming the condition is false | |
|
| 2 | | Loop condition is false. Execution continues on line 414 | |
|
396 | switch (ch) { |
397 | case '1': |
398 | allowv1 = TRUE; |
399 | break; |
400 | case 'a': |
401 | aclfile = optarg; |
402 | break; |
403 | case 'd': |
404 | usedns = TRUE; |
405 | break; |
406 | case 'x': |
407 | xflag = TRUE; |
408 | break; |
409 | default: |
410 | usage(); |
411 | break; |
412 | } |
413 | |
414 | if (geteuid() != 0) { |
| 3 | | Assuming the condition is false | |
|
| |
415 | (void)fprintf(stderr, "ypserv: must be root to run.\n"); |
416 | exit(1); |
417 | } |
418 | |
419 | if (aclfile != NULL) |
| |
420 | (void)acl_init(aclfile); |
421 | else |
422 | (void)acl_securenet(YP_SECURENET_FILE); |
423 | |
424 | if (xflag) |
| |
425 | exit(1); |
426 | |
427 | if (getsockname(0, (struct sockaddr *)&saddr, &asize) == 0) { |
| 7 | | Assuming the condition is true | |
|
| |
428 | socklen_t ssize = sizeof(int); |
429 | |
430 | if (saddr.sin_family != AF_INET) |
| 9 | | Assuming field 'sin_family' is equal to AF_INET | |
|
| |
431 | exit(1); |
432 | if (getsockopt(0, SOL_SOCKET, SO_TYPE, |
| 11 | | Assuming the condition is false | |
|
| |
433 | &_rpcfdtype, &ssize) == -1) |
434 | exit(1); |
435 | sock = 0; |
436 | _rpcpmstart = 1; |
437 | proto = 0; |
438 | openlog("ypserv", LOG_PID, LOG_DAEMON); |
439 | } else { |
440 | #ifndef RPC_SVC_FG |
441 | int i; |
442 | pid_t pid; |
443 | |
444 | pid = fork(); |
445 | if (pid < 0) { |
446 | perror("cannot fork"); |
447 | exit(1); |
448 | } |
449 | if (pid) |
450 | exit(0); |
451 | closefrom(0); |
452 | i = open("/dev/console", O_RDWR); |
453 | (void) dup2(i, 1); |
454 | (void) dup2(i, 2); |
455 | i = open("/dev/tty", O_RDWR); |
456 | if (i >= 0) { |
457 | (void) ioctl(i, TIOCNOTTY, NULL); |
458 | (void) close(i); |
459 | } |
460 | openlog("ypserv", LOG_PID, LOG_DAEMON); |
461 | #endif |
462 | sock = RPC_ANYSOCK; |
463 | (void) pmap_unset(YPPROG, YPVERS); |
464 | (void) pmap_unset(YPPROG, YPOLDVERS); |
465 | } |
466 | |
467 | ypopenlog(); |
468 | ypdb_init(); |
469 | |
470 | chdir("/"); |
471 | |
472 | (void)signal(SIGCHLD, sig_child); |
473 | (void)signal(SIGHUP, sig_hup); |
474 | |
475 | if (_rpcfdtype == 0 || _rpcfdtype == SOCK_DGRAM) { |
| 13 | | Assuming '_rpcfdtype' is not equal to 0 | |
|
| 14 | | Assuming '_rpcfdtype' is equal to SOCK_DGRAM | |
|
| |
476 | transp = svcudp_create(sock); |
477 | if (transp == NULL) { |
| 16 | | Assuming 'transp' is not equal to NULL | |
|
| |
478 | _msgout("cannot create udp service."); |
479 | exit(1); |
480 | } |
481 | if (transp->xp_port >= IPPORT_RESERVED) { |
| 18 | | Assuming field 'xp_port' is < IPPORT_RESERVED | |
|
| |
482 | _msgout("cannot allocate udp privileged port."); |
483 | exit(1); |
484 | } |
485 | if (!_rpcpmstart) |
| 20 | | Assuming '_rpcpmstart' is 0 | |
|
| |
486 | proto = IPPROTO_UDP; |
487 | if (allowv1) { |
| |
488 | if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) { |
489 | _msgout("unable to register (YPPROG, YPOLDVERS, udp)."); |
490 | exit(1); |
491 | } |
492 | } |
493 | if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) { |
| 23 | | Assuming the condition is false | |
|
494 | _msgout("unable to register (YPPROG, YPVERS, udp)."); |
495 | exit(1); |
496 | } |
497 | } |
498 | |
499 | if (_rpcfdtype == 0 || _rpcfdtype == SOCK_STREAM) { |
| |
500 | if (_rpcpmstart) |
501 | transp = svcfd_create(sock, 0, 0); |
502 | else |
503 | transp = svctcp_create(sock, 0, 0); |
504 | if (transp == NULL) { |
505 | _msgout("cannot create tcp service."); |
506 | exit(1); |
507 | } |
508 | if (transp->xp_port >= IPPORT_RESERVED) { |
509 | _msgout("cannot allocate tcp privileged port."); |
510 | exit(1); |
511 | } |
512 | if (!_rpcpmstart) |
513 | proto = IPPROTO_TCP; |
514 | if (allowv1) { |
515 | if (!svc_register(transp, YPPROG, YPOLDVERS, ypprog_1, proto)) { |
516 | _msgout("unable to register (YPPROG, YPOLDVERS, tcp)."); |
517 | exit(1); |
518 | } |
519 | } |
520 | if (!svc_register(transp, YPPROG, YPVERS, ypprog_2, proto)) { |
521 | _msgout("unable to register (YPPROG, YPVERS, tcp)."); |
522 | exit(1); |
523 | } |
524 | } |
525 | |
526 | if (transp == NULL) { |
| |
527 | _msgout("could not create a handle"); |
528 | exit(1); |
529 | } |
530 | if (_rpcpmstart) { |
| |
531 | (void) signal(SIGALRM, closedown); |
532 | (void) alarm(_RPCSVC_CLOSEDOWN); |
533 | } |
534 | my_svc_run(); |
| |
535 | _msgout("svc_run returned"); |
536 | exit(1); |
537 | |
538 | } |
539 | |
540 | void |
541 | sig_child(int signo) |
542 | { |
543 | int save_errno = errno; |
544 | |
545 | while (wait3(NULL, WNOHANG, NULL) > 0) |
546 | ; |
547 | errno = save_errno; |
548 | } |
549 | |
550 | void |
551 | sig_hup(int signo) |
552 | { |
553 | wantsighup = 1; |
554 | } |