Print this page
10143 smatch fix for ttymon
Split |
Close |
Expand all |
Collapse all |
--- old/usr/src/cmd/ttymon/tmhandler.c
+++ new/usr/src/cmd/ttymon/tmhandler.c
1 1 /*
2 2 * CDDL HEADER START
3 3 *
4 4 * The contents of this file are subject to the terms of the
5 5 * Common Development and Distribution License, Version 1.0 only
6 6 * (the "License"). You may not use this file except in compliance
7 7 * with the License.
8 8 *
9 9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 10 * or http://www.opensolaris.org/os/licensing.
11 11 * See the License for the specific language governing permissions
12 12 * and limitations under the License.
13 13 *
14 14 * When distributing Covered Code, include this CDDL HEADER in each
15 15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 16 * If applicable, add the following below this CDDL HEADER, with the
17 17 * fields enclosed by brackets "[]" replaced with your own identifying
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 19 *
20 20 * CDDL HEADER END
21 21 */
22 22 /*
23 23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 24 * Use is subject to license terms.
25 25 */
26 26 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
27 27 /* All Rights Reserved */
28 +/*
29 + * Copyright (c) 2018, Joyent, Inc.
30 + */
28 31
29 32
30 -#pragma ident "%Z%%M% %I% %E% SMI"
31 -
32 -
33 33 #include <stdlib.h>
34 34 #include <stdio.h>
35 35 #include <fcntl.h>
36 36 #include <errno.h>
37 37 #include <poll.h>
38 38 #include <string.h>
39 39 #include <termio.h>
40 40 #include <signal.h>
41 41 #include <sys/types.h>
42 42 #include <sys/stropts.h>
43 43 #include <unistd.h>
44 44 #include <sys/wait.h>
45 45 #include "ttymon.h"
46 46 #include "tmstruct.h"
47 47 #include "tmextern.h"
48 48 #include "sac.h"
49 49
50 50 extern int Retry;
51 51 static struct pmtab *find_pid();
52 52 static void kill_children();
53 53
54 54 static struct pmtab *find_fd();
55 55 static void pcsync_close();
56 56 extern void sigalarm();
57 57 extern void tmchild();
58 58
59 59 /*
60 60 * fork_tmchild - fork child on the device
61 61 */
62 62 static void
63 63 fork_tmchild(pmptr)
64 64 struct pmtab *pmptr;
65 65 {
66 66 pid_t pid;
67 67 sigset_t cset;
68 68 sigset_t tset;
69 69 int pcpipe0[2], pcpipe1[2];
70 70 int p0;
71 71
72 72 #ifdef DEBUG
73 73 debug("in fork_tmchild");
74 74 #endif
75 75 pmptr->p_inservice = FALSE;
76 76
77 77 /*
78 78 * initialize pipe.
79 79 * Child has pcpipe[0] pipe fd for reading and writing
80 80 * and closes pcpipe[1]. Parent has pcpipe[1] pipe fd for
81 81 * reading and writing and closes pcpipe[0].
82 82 *
83 83 * This way if the child process exits the parent's block
84 84 * read on pipe will return immediately as the other end of
85 85 * the pipe has closed. Similarly if the parent process exits
86 86 * child's blocking read on the pipe will return immediately.
87 87 */
88 88
89 89 if (((p0 = pipe(pcpipe0)) == -1) || (pipe(pcpipe1) == -1)) {
90 90 if (p0 == 0) {
91 91 close(pcpipe0[0]);
92 92 close(pcpipe0[1]);
93 93 }
94 94 log("pipe() failed: %s", strerror(errno));
95 95 pmptr->p_status = VALID;
96 96 pmptr->p_pid = 0;
97 97 Retry = TRUE;
98 98 }
99 99
100 100 /* protect following region from SIGCLD */
101 101 (void)sigprocmask(SIG_SETMASK, NULL, &cset);
102 102 tset = cset;
103 103 (void)sigaddset(&tset, SIGCLD);
104 104 (void)sigprocmask(SIG_SETMASK, &tset, NULL);
105 105 if( (pid=fork()) == 0 ) {
106 106 /*
107 107 * Close all file descriptors except pmptr->p_fd
108 108 * Wait for the parent process to close its fd
109 109 */
110 110 pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd);
111 111 /* The CHILD */
112 112 tmchild(pmptr);
113 113 /* tmchild should never return */
114 114 fatal("tmchild for <%s> returns unexpected", pmptr->p_device);
115 115 }
116 116 else if (pid < 0) {
117 117 log("fork failed: %s", strerror(errno));
118 118 pmptr->p_status = VALID;
119 119 pmptr->p_pid = 0;
120 120 Retry = TRUE;
121 121 }
122 122 else {
123 123 /*
124 124 * The PARENT - store pid of child and close the device
125 125 */
126 126 pmptr->p_pid = pid;
127 127 }
128 128 if (pmptr->p_fd > 0) {
129 129 (void)close(pmptr->p_fd);
130 130 pmptr->p_fd = 0;
131 131 }
132 132 (void)sigprocmask(SIG_SETMASK, &cset, NULL);
133 133 /*
134 134 * Wait for child to close file descriptors
135 135 */
136 136 pcsync_close(pcpipe0, pcpipe1, pid, pmptr->p_fd);
137 137 }
138 138
139 139 /*
140 140 * got_carrier - carrier is detected on the stream
141 141 * - depends on the flags, different action is taken
142 142 * - R_FLAG - wait for data
143 143 * - C_FLAG - if port is not disabled, fork tmchild
144 144 * - A_FLAG - wait for data
145 145 * - otherwise - write out prompt, then wait for data
146 146 */
147 147 void
148 148 got_carrier(pmptr)
149 149 struct pmtab *pmptr;
150 150 {
151 151 flush_input(pmptr->p_fd);
152 152
153 153 if (pmptr->p_ttyflags & R_FLAG) {
154 154 #ifdef DEBUG
155 155 debug("R_FLAG");
156 156 #endif
157 157 return;
158 158 }
159 159 else if ((pmptr->p_ttyflags & (C_FLAG|B_FLAG)) &&
160 160 (State != PM_DISABLED) &&
161 161 (!(pmptr->p_flags & X_FLAG))) {
162 162 fork_tmchild(pmptr);
163 163 }
164 164 else if (pmptr->p_ttyflags & A_FLAG) {
165 165 #ifdef DEBUG
166 166 debug("A_FLAG");
167 167 #endif
168 168 return;
169 169 }
170 170 else if (pmptr->p_timeout) {
171 171 fork_tmchild(pmptr);
172 172 }
173 173 else if ( ! (pmptr->p_ttyflags & X_FLAG) ) {
174 174 write_prompt(pmptr->p_fd,pmptr,TRUE,TRUE);
175 175 }
176 176 }
177 177
178 178 /*
179 179 * got_data - data is detected on the stream, fork tmchild
180 180 */
181 181 static void
182 182 got_data(pmptr)
183 183 struct pmtab *pmptr;
184 184 {
185 185 struct sigaction sigact;
186 186
187 187 if (tm_checklock(pmptr->p_fd) != 0) {
188 188 pmptr->p_status = LOCKED;
189 189 (void)close(pmptr->p_fd);
190 190 pmptr->p_fd = 0;
191 191 Nlocked++;
192 192 if (Nlocked == 1) {
193 193 sigact.sa_flags = 0;
194 194 sigact.sa_handler = sigalarm;
195 195 (void)sigemptyset(&sigact.sa_mask);
196 196 (void)sigaction(SIGALRM, &sigact, NULL);
197 197 (void)alarm(ALARMTIME);
198 198 }
199 199 }
200 200 else
201 201 fork_tmchild(pmptr);
202 202 }
203 203 /*
204 204 * got_hup - stream hangup is detected, close the device
205 205 */
206 206 static void
207 207 got_hup(pmptr)
208 208 struct pmtab *pmptr;
209 209 {
210 210 #ifdef DEBUG
211 211 debug("in got hup");
212 212 #endif
213 213 (void)close(pmptr->p_fd);
214 214 pmptr->p_fd = 0;
215 215 pmptr->p_inservice = 0;
216 216 Retry = TRUE;
217 217 }
218 218
219 219
220 220 /*
221 221 * do_poll - poll device
222 222 * - if POLLHUP received, close the device
223 223 * - if POLLIN received, fork tmchild.
224 224 */
225 225 void
226 226 do_poll(fdp,nfds)
227 227 struct pollfd *fdp;
228 228 int nfds;
229 229 {
230 230 int i,n;
231 231 struct pmtab *pmptr;
232 232
233 233 n = poll(fdp, (unsigned long)nfds, -1); /* blocked poll */
234 234 #ifdef DEBUG
235 235 debug("poll return");
236 236 #endif
237 237 if (n < 0) {
238 238 if (errno == EINTR) /* interrupt by signal */
239 239 return;
240 240 fatal("do_poll: poll failed: %s", strerror(errno));
241 241 }
242 242 for (i = 0; (i < nfds)&&(n); i++,fdp++) {
243 243 if (fdp->revents != 0) {
244 244 n--;
245 245 if ((pmptr = find_fd(fdp->fd)) == NULL) {
246 246 log("do_poll: cannot find fd %d in pmtab",
247 247 fdp->fd);
248 248 continue;
249 249 }
250 250 else if (fdp->revents & POLLHUP) {
251 251 got_hup(pmptr);
252 252 }
253 253 else if (fdp->revents & POLLIN) {
254 254 #ifdef DEBUG
255 255 debug("got POLLIN");
256 256 #endif
257 257 got_data(pmptr);
258 258 } else if (fdp->revents & POLLERR) {
259 259 fatal("ttymon[%d]: do_poll: POLLERR on fd %d",
260 260 getpid(), fdp->fd);
261 261 }
262 262 }
263 263 }
264 264 }
265 265
266 266 /*
267 267 * sigchild - handler for SIGCLD
268 268 * - find the pid of dead child
269 269 * - clean utmp if U_FLAG is set
270 270 */
271 271 void
272 272 /*ARGSUSED*/
273 273 sigchild(n)
274 274 int n; /* this is declared to make cc happy, but it is not used */
275 275 {
276 276 struct pmtab *pmptr;
277 277 struct sigaction sigact;
278 278 siginfo_t info;
279 279 int status;
280 280 pid_t pid;
281 281 int rcode;
282 282
283 283 #ifdef DEBUG
284 284 debug("in sigchild");
285 285 #endif
286 286
287 287 /* find all processes that died */
288 288 for (;;) {
289 289 rcode = waitid(P_ALL, 0, &info, WNOHANG|WEXITED);
290 290 if (rcode == -1 && errno == EINTR)
291 291 continue;
292 292
293 293 /* If no more children have exited, just return */
294 294 if (rcode == -1 || (pid = info.si_pid) == 0)
295 295 break;
296 296
297 297 /* construct status as returned from waitid() */
298 298 status = info.si_status & 0377;
299 299 switch (info.si_code) {
300 300 case CLD_EXITED:
301 301 status <<= 8;
302 302 break;
303 303 case CLD_DUMPED:
304 304 status |= WCOREFLG;
305 305 break;
306 306 case CLD_KILLED:
307 307 break;
308 308 }
309 309
310 310 if ((pmptr = find_pid(pid)) == NULL) {
311 311 #ifdef DEBUG
312 312 log("cannot find dead child (%ld) in pmtab", pid);
313 313 #endif
314 314 /*
315 315 * This may happen if the entry is deleted from pmtab
316 316 * before the service exits.
317 317 * We try to cleanup utmp entry
318 318 */
319 319 cleanut(pid, status);
320 320 } else {
321 321 if (pmptr->p_flags & U_FLAG)
322 322 cleanut(pid, status);
323 323 pmptr->p_status = VALID;
324 324 pmptr->p_fd = 0;
325 325 pmptr->p_pid = 0;
326 326 pmptr->p_inservice = 0;
327 327 Retry = TRUE;
328 328 }
329 329 }
330 330 }
331 331
332 332 /*
333 333 * sigterm - handler for SIGTERM
334 334 */
335 335 void
336 336 sigterm()
337 337 {
338 338 fatal("caught SIGTERM");
339 339 }
340 340
341 341 /*
342 342 * state_change - this is called when ttymon changes
343 343 * its internal state between enabled and disabled
344 344 */
345 345 void
346 346 state_change()
347 347 {
348 348 struct pmtab *pmptr;
349 349
350 350 #ifdef DEBUG
351 351 debug("in state_change");
352 352 #endif
353 353
354 354 /*
355 355 * closing PCpipe will cause attached non-service children
356 356 * to get SIGPOLL and exit
357 357 */
358 358 (void)close(PCpipe[0]);
359 359 (void)close(PCpipe[1]);
360 360
361 361 /* reopen PCpipe */
362 362 setup_PCpipe();
363 363
364 364 /*
365 365 * also close all open ports so ttymon can start over
366 366 * with new internal state
367 367 */
368 368 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
369 369 if ((pmptr->p_fd > 0) && (pmptr->p_pid == 0)) {
370 370 (void)close(pmptr->p_fd);
371 371 pmptr->p_fd = 0;
372 372 }
373 373 }
374 374 Retry = TRUE;
375 375
376 376 }
377 377
378 378 /*
379 379 * re_read - reread pmtab
380 380 * - kill tmchild if entry changed
381 381 */
382 382 void
383 383 re_read()
384 384 {
385 385 extern struct pollfd *Pollp;
386 386 sigset_t cset;
387 387 sigset_t tset;
388 388
389 389 (void)sigprocmask(SIG_SETMASK, NULL, &cset);
390 390 tset = cset;
391 391 (void)sigaddset(&tset, SIGCLD);
392 392 (void)sigprocmask(SIG_SETMASK, &tset, NULL);
393 393 if (Nlocked > 0) {
394 394 alarm(0);
395 395 Nlocked = 0;
396 396 }
397 397 read_pmtab();
398 398 kill_children();
399 399 (void)sigprocmask(SIG_SETMASK, &cset, NULL);
400 400 purge();
401 401
402 402 if (Nentries > Npollfd) {
403 403 #ifdef DEBUG
404 404 debug("Nentries > Npollfd, reallocating pollfds");
405 405 #endif
406 406 /* need to malloc more pollfd structure */
407 407 free((char *)Pollp);
408 408 Npollfd = Nentries + 10;
409 409 if (Npollfd > Maxfds)
410 410 Npollfd = Maxfds;
411 411 if ((Pollp = (struct pollfd *)
412 412 malloc((unsigned)(Npollfd * sizeof(struct pollfd))))
413 413 == (struct pollfd *)NULL)
414 414 fatal("malloc for Pollp failed");
415 415 }
416 416 Retry = TRUE;
417 417 }
418 418
419 419 /*
420 420 * find_pid(pid) - find the corresponding pmtab entry for the pid
421 421 */
422 422 static struct pmtab *
423 423 find_pid(pid)
424 424 pid_t pid;
425 425 {
426 426 struct pmtab *pmptr;
427 427
428 428 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
429 429 if (pmptr->p_pid == pid) {
430 430 return(pmptr);
431 431 }
432 432 }
433 433 return((struct pmtab *)NULL);
434 434 }
435 435
436 436 /*
437 437 * find_fd(fd) - find the corresponding pmtab entry for the fd
438 438 */
439 439 static struct pmtab *
440 440 find_fd(fd)
441 441 int fd;
442 442 {
443 443 struct pmtab *pmptr;
444 444
445 445 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
446 446 if (pmptr->p_fd == fd) {
447 447 return(pmptr);
448 448 }
449 449 }
450 450 return((struct pmtab *)NULL);
451 451 }
452 452
453 453 /*
454 454 * kill_children() - if the pmtab entry has been changed,
455 455 * kill tmchild if it is not in service.
456 456 * - close the device if there is no tmchild
457 457 */
458 458 static void
459 459 kill_children()
460 460 {
461 461 struct pmtab *pmptr;
462 462 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
463 463 if (pmptr->p_status == VALID)
464 464 continue;
465 465 if ((pmptr->p_fd > 0) && (pmptr->p_pid == 0)) {
466 466 (void)close(pmptr->p_fd);
467 467 pmptr->p_fd = 0;
468 468 }
469 469 else if ((pmptr->p_fd == 0) && (pmptr->p_pid > 0)
470 470 && (pmptr->p_inservice == FALSE)) {
471 471 (void)kill(pmptr->p_pid, SIGTERM);
472 472 }
473 473 }
474 474 }
475 475
476 476 static void
477 477 mark_service(pid)
478 478 pid_t pid;
479 479 {
480 480 struct pmtab *pmptr;
481 481 #ifdef DEBUG
482 482 debug("in mark_service");
483 483 #endif
484 484 if ((pmptr = find_pid(pid)) == NULL) {
485 485 log("mark_service: cannot find child (%ld) in pmtab", pid);
486 486 return;
487 487 }
488 488 pmptr->p_inservice = TRUE;
489 489 return;
490 490 }
491 491
492 492 /*
493 493 * read_pid(fd) - read pid info from PCpipe
494 494 */
495 495 static void
496 496 read_pid(fd)
497 497 int fd;
498 498 {
499 499 int ret;
500 500 pid_t pid;
501 501
502 502 for (;;) {
503 503 if ((ret = read(fd,&pid,sizeof(pid))) < 0) {
504 504 if (errno == EINTR)
505 505 continue;
506 506 if (errno == EAGAIN)
507 507 return;
508 508 fatal("read PCpipe failed: %s", strerror(errno));
509 509 }
510 510 if (ret == 0)
511 511 return;
512 512 if (ret != sizeof(pid))
513 513 fatal("read return size incorrect, ret = %d", ret);
514 514
515 515 mark_service(pid);
516 516 }
517 517 }
518 518
519 519 /*
520 520 * sipoll_catch() - signal handle of SIGPOLL for ttymon
521 521 * - it will check both PCpipe and pmpipe
522 522 */
523 523 void
524 524 sigpoll_catch()
525 525 {
526 526 int ret;
527 527 struct pollfd pfd[2];
528 528
529 529 #ifdef DEBUG
530 530 debug("in sigpoll_catch");
531 531 #endif
532 532
533 533 pfd[0].fd = PCpipe[0];
534 534 pfd[1].fd = Pfd;
535 535 pfd[0].events = POLLIN;
536 536 pfd[1].events = POLLIN;
537 537 if ((ret = poll(pfd, 2, 0)) < 0)
538 538 fatal("sigpoll_catch: poll failed: %s", strerror(errno));
539 539
540 540 if (ret > 0) {
541 541 if (pfd[0].revents & POLLIN)
542 542 read_pid(pfd[0].fd);
543 543 if (pfd[1].revents & POLLIN)
544 544 sacpoll();
545 545 }
546 546 }
547 547
548 548 /*ARGSUSED*/
549 549 void
550 550 sigalarm(signo)
551 551 int signo;
552 552 {
553 553 struct pmtab *pmptr;
554 554 struct sigaction sigact;
555 555 int fd;
556 556 extern int check_session();
557 557
558 558 #ifdef DEBUG
559 559 debug("in sigalarm, Nlocked = %d", Nlocked);
560 560 #endif
561 561 for (pmptr = PMtab; pmptr; pmptr = pmptr->p_next) {
562 562 if ((pmptr->p_status == LOCKED) && (pmptr->p_fd == 0)) {
563 563 if ((fd=open(pmptr->p_device,O_RDWR|O_NONBLOCK)) == -1){
564 564 log("open (%s) failed: %s", pmptr->p_device,
565 565 strerror(errno));
566 566 pmptr->p_status = VALID;
567 567 Nlocked--;
568 568 Retry = TRUE;
569 569 }
570 570 else {
571 571 if (tm_checklock(fd) == 0) {
572 572 Nlocked--;
573 573 pmptr->p_fd = fd;
574 574 Retry = TRUE;
575 575 }
576 576 else
577 577 (void)close(fd);
578 578 }
579 579 }
580 580 else if ((pmptr->p_status == SESSION) && (pmptr->p_fd == 0)) {
581 581 if ((fd=open(pmptr->p_device,O_RDWR|O_NONBLOCK)) == -1){
582 582 log("open (%s) failed: %s", pmptr->p_device,
583 583 strerror(errno));
584 584 pmptr->p_status = VALID;
585 585 Nlocked--;
586 586 Retry = TRUE;
587 587 }
588 588 else {
589 589 if (check_session(fd) == 0) {
590 590 Nlocked--;
591 591 pmptr->p_fd = fd;
592 592 Retry = TRUE;
593 593 }
594 594 else
595 595 (void)close(fd);
596 596 }
597 597 }
598 598 else if ((pmptr->p_status == UNACCESS) && (pmptr->p_fd == 0)) {
599 599 if ((fd=open(pmptr->p_device,O_RDWR|O_NONBLOCK)) == -1){
600 600 log("open (%s) failed: %s", pmptr->p_device,
601 601 strerror(errno));
602 602 pmptr->p_status = VALID;
603 603 Nlocked--;
604 604 Retry = TRUE;
605 605 }
606 606 else {
607 607 Nlocked--;
608 608 pmptr->p_fd = fd;
609 609 Retry = TRUE;
610 610 }
611 611 }
612 612 }
613 613 if (Nlocked > 0) {
614 614 sigact.sa_flags = 0;
615 615 sigact.sa_handler = sigalarm;
616 616 (void)sigemptyset(&sigact.sa_mask);
617 617 (void)sigaction(SIGALRM, &sigact, NULL);
618 618 (void)alarm(ALARMTIME);
619 619 }
620 620 else {
621 621 sigact.sa_flags = 0;
622 622 sigact.sa_handler = SIG_IGN;
623 623 (void)sigemptyset(&sigact.sa_mask);
624 624 (void)sigaction(SIGALRM, &sigact, NULL);
625 625 }
↓ open down ↓ |
583 lines elided |
↑ open up ↑ |
626 626 }
627 627
628 628 /*
629 629 * pcsync_close - For the child process close all open fd's except
630 630 * the one that is passed to the routine. Coordinate the reads and
631 631 * writes to the pipes by the parent and child process to ensure
632 632 * the parent and child processes have closed all the file descriptors
633 633 * that are not needed any more.
634 634 */
635 635 static void
636 -pcsync_close(p0, p1, pid, fd)
637 -int *p0;
638 -int *p1;
639 -int pid;
636 +pcsync_close(int *p0, int *p1, int pid, int fd)
640 637 {
641 638 char ch;
642 639
643 640 if (pid == 0) { /* Child */
644 641 struct pmtab *tp;
645 642 for (tp = PMtab; tp; tp = tp->p_next)
646 643 if ((tp->p_fd > 0) && (tp->p_fd != fd))
647 644 close(tp->p_fd);
648 645 close(p0[1]); close(p1[0]);
649 646 if (read(p0[0], &ch, 1) == 1)
650 647 write(p1[1], "a", 1);
651 648 close(p0[0]); close(p1[1]);
652 649 } else { /* Parent */
653 650 close(p0[0]); close(p1[1]);
654 651 if (write(p0[1], "a", 1) == 1)
655 652 read(p1[0], &ch, 1);
656 653 close(p0[1]); close(p1[0]);
657 654 }
658 655 }
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX