1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
24 /*
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
27 */
28
29 #pragma ident "%Z%%M% %I% %E% SMI"
30
31
32 #include <stdio.h>
33 #include <unistd.h>
34 #include <stdlib.h>
35 #include <fcntl.h>
36 #include <sys/types.h>
37 #include <sys/stropts.h>
38 #include <signal.h>
39 #include <sys/stat.h>
40 #include <poll.h>
41 #include "misc.h"
42 #include "msgs.h"
43 #include "extern.h"
44 #include <sac.h>
45 #include "adm.h"
46 #include "structs.h"
47
48
49 /*
50 * findpm - find a port monitor entry
51 *
52 * args: tag - tag of desired port monitor
53 */
54
55
56 struct sactab *
findpm(tag)57 findpm(tag)
58 register char *tag;
59 {
60 register struct sactab *sp; /* working pointer */
61
62 for (sp = Sactab; sp; sp = sp->sc_next) {
63 if (!strcmp(tag, sp->sc_tag))
64 return(sp);
65 }
66 return(NULL);
67 }
68
69
70 /*
71 * sigpoll - handle messages coming in on the command pipe (SIGPOLL signal
72 * handler)
73 */
74
75
76 void
sigpoll()77 sigpoll()
78 {
79 struct pollfd fds; /* array of fds to poll */
80 struct admcmd cmd; /* incoming command */
81 register struct admcmd *ap = &cmd; /* and a pointer to it */
82 struct admack ack; /* acknowledgment */
83 register struct admack *ak = &ack; /* and a pointer to it */
84 register struct sactab *sp; /* working pointer */
85 struct sacmsg sacmsg; /* message to port monitor */
86 char **data; /* "dumped" sactab */
87 char *p; /* scratch pointer */
88 register int i; /* loop control variable */
89 int ret; /* return value */
90 sigset_t cset; /* for signal handling */
91 sigset_t tset; /* for signal handling */
92
93 # ifdef DEBUG
94 debug("in sigpoll");
95 # endif
96 fds.fd = Cfd;
97 fds.events = POLLIN;
98 fds.revents = 0;
99 if (poll(&fds, 1, 0) < 0)
100 error(E_POLL, EXIT);
101 switch (fds.revents) {
102 case POLLIN:
103 if (read(Cfd, ap, sizeof(struct admcmd)) < 0) {
104 error(E_READ, EXIT);
105 }
106 switch (ap->ac_mtype) {
107
108 /*
109 * request to start a port monitor
110 */
111
112 case AC_START:
113 # ifdef DEBUG
114 (void) sprintf(Scratch, "Got AC_START for <%s>", ap->ac_tag);
115 log(Scratch);
116 # endif
117 if ((sp = findpm(ap->ac_tag)) == NULL) {
118 ak->ak_pid = ap->ac_pid;
119 ak->ak_resp = AK_NOPM;
120 ak->ak_size = 0;
121 sendack(ak);
122 break;
123 }
124 switch (sp->sc_sstate) {
125 case UNKNOWN:
126 ak->ak_pid = ap->ac_pid;
127 ak->ak_resp = AK_RECOVER;
128 ak->ak_size = 0;
129 sendack(ak);
130 break;
131 case FAILED:
132 case NOTRUNNING:
133 sp->sc_rscnt = 0; /* fresh start in life */
134 if (ret = startpm(sp)) {
135 ak->ak_pid = ap->ac_pid;
136 if (ret == -1)
137 ak->ak_resp = AK_PMLOCK;
138 else
139 ak->ak_resp = AK_REQFAIL;
140 ak->ak_size = 0;
141 sendack(ak);
142 break;
143 }
144 ak->ak_pid = ap->ac_pid;
145 ak->ak_resp = AK_ACK;
146 ak->ak_size = 0;
147 sendack(ak);
148 break;
149 case ENABLED:
150 case DISABLED:
151 case STARTING:
152 case STOPPING:
153 ak->ak_pid = ap->ac_pid;
154 ak->ak_resp = AK_PMRUN;
155 ak->ak_size = 0;
156 sendack(ak);
157 break;
158 }
159 break;
160
161 /*
162 * request to kill a port monitor
163 */
164
165 case AC_KILL:
166 # ifdef DEBUG
167 (void) sprintf(Scratch, "Got AC_KILL for <%s>", ap->ac_tag);
168 log(Scratch);
169 # endif
170 if ((sp = findpm(ap->ac_tag)) == NULL) {
171 ak->ak_pid = ap->ac_pid;
172 ak->ak_resp = AK_NOPM;
173 ak->ak_size = 0;
174 sendack(ak);
175 break;
176 }
177 switch (sp->sc_sstate) {
178 case UNKNOWN:
179 ak->ak_pid = ap->ac_pid;
180 ak->ak_resp = AK_RECOVER;
181 ak->ak_size = 0;
182 sendack(ak);
183 break;
184 case NOTRUNNING:
185 case FAILED:
186 case STOPPING:
187 ak->ak_pid = ap->ac_pid;
188 ak->ak_resp = AK_PMNOTRUN;
189 ak->ak_size = 0;
190 sendack(ak);
191 break;
192 case STARTING:
193 case ENABLED:
194 case DISABLED:
195 (void) sigprocmask(SIG_SETMASK, NULL, &cset);
196 tset = cset;
197 (void) sigaddset(&tset, SIGALRM);
198 (void) sigaddset(&tset, SIGCLD);
199 (void) sigprocmask(SIG_SETMASK, &tset, NULL);
200 if (sendsig(sp, SIGTERM)) {
201 (void) sprintf(Scratch, "could not send SIGTERM to <%s>", sp->sc_tag);
202 log(Scratch);
203 ak->ak_pid = ap->ac_pid;
204 ak->ak_resp = AK_NOCONTACT;
205 ak->ak_size = 0;
206 sendack(ak);
207 (void) sigprocmask(SIG_SETMASK, &cset, NULL);
208 break;
209 }
210 /* signal sent ok */
211 sp->sc_lstate = NOTRUNNING;
212 sp->sc_sstate = NOTRUNNING;
213 sp->sc_pstate = STOPPING;
214 ak->ak_pid = ap->ac_pid;
215 ak->ak_resp = AK_ACK;
216 ak->ak_size = 0;
217 sendack(ak);
218 (void) sprintf(Scratch, "terminating <%s>", sp->sc_tag);
219 log(Scratch);
220 (void) sigprocmask(SIG_SETMASK, &cset, NULL);
221 break;
222 }
223 break;
224
225 /*
226 * request to enable a port monitor
227 */
228
229 case AC_ENABLE:
230 # ifdef DEBUG
231 (void) sprintf(Scratch, "Got AC_ENABLE for <%s>", ap->ac_tag);
232 log(Scratch);
233 # endif
234 if ((sp = findpm(ap->ac_tag)) == NULL) {
235 ak->ak_pid = ap->ac_pid;
236 ak->ak_resp = AK_NOPM;
237 ak->ak_size = 0;
238 sendack(ak);
239 break;
240 }
241 switch (sp->sc_sstate) {
242 case UNKNOWN:
243 ak->ak_pid = ap->ac_pid;
244 ak->ak_resp = AK_RECOVER;
245 ak->ak_size = 0;
246 sendack(ak);
247 break;
248 case NOTRUNNING:
249 case FAILED:
250 case STOPPING:
251 ak->ak_pid = ap->ac_pid;
252 ak->ak_resp = AK_PMNOTRUN;
253 ak->ak_size = 0;
254 sendack(ak);
255 break;
256 case STARTING:
257 case DISABLED:
258 sacmsg.sc_type = SC_ENABLE;
259 sacmsg.sc_size = 0;
260 sp->sc_sstate = ENABLED;
261 sp->sc_lstate = ENABLED;
262 sendpmmsg(sp, &sacmsg);
263 ak->ak_pid = ap->ac_pid;
264 ak->ak_resp = AK_ACK;
265 ak->ak_size = 0;
266 sendack(ak);
267 break;
268 case ENABLED:
269 ak->ak_pid = ap->ac_pid;
270 ak->ak_resp = AK_ACK;
271 ak->ak_size = 0;
272 sendack(ak);
273 break;
274 }
275 break;
276
277 /*
278 * request to disable a port monitor
279 */
280
281 case AC_DISABLE:
282 # ifdef DEBUG
283 (void) sprintf(Scratch, "Got AC_DISABLE for <%s>", ap->ac_tag);
284 log(Scratch);
285 # endif
286 if ((sp = findpm(ap->ac_tag)) == NULL) {
287 ak->ak_pid = ap->ac_pid;
288 ak->ak_resp = AK_NOPM;
289 ak->ak_size = 0;
290 sendack(ak);
291 break;
292 }
293 switch (sp->sc_sstate) {
294 case UNKNOWN:
295 ak->ak_pid = ap->ac_pid;
296 ak->ak_resp = AK_RECOVER;
297 ak->ak_size = 0;
298 sendack(ak);
299 break;
300 case NOTRUNNING:
301 case FAILED:
302 case STOPPING:
303 ak->ak_pid = ap->ac_pid;
304 ak->ak_resp = AK_PMNOTRUN;
305 ak->ak_size = 0;
306 sendack(ak);
307 break;
308 case STARTING:
309 case ENABLED:
310 sacmsg.sc_type = SC_DISABLE;
311 sacmsg.sc_size = 0;
312 sp->sc_sstate = DISABLED;
313 sp->sc_lstate = DISABLED;
314 sendpmmsg(sp, &sacmsg);
315 ak->ak_pid = ap->ac_pid;
316 ak->ak_resp = AK_ACK;
317 ak->ak_size = 0;
318 sendack(ak);
319 break;
320 case DISABLED:
321 ak->ak_pid = ap->ac_pid;
322 ak->ak_resp = AK_ACK;
323 ak->ak_size = 0;
324 sendack(ak);
325 break;
326 }
327 break;
328
329 /*
330 * request for port monitor status information
331 */
332
333 case AC_STATUS:
334 # ifdef DEBUG
335 log("Got AC_STATUS");
336 # endif
337 /* get all the info in one convenient place */
338 data = dump_table();
339 if ((data == NULL) && (Nentries > 0)) {
340 /* something bad happened in dump_table */
341 ak->ak_pid = ap->ac_pid;
342 ak->ak_resp = AK_REQFAIL;
343 ak->ak_size = 0;
344 sendack(ak);
345 break;
346 }
347 /* count how big it is */
348 ak->ak_size = 0;
349 for (i = 0; i < Nentries; ++i)
350 ak->ak_size += strlen(data[i]);
351 # ifdef DEBUG
352 (void) sprintf(Scratch, "ak_size is %d", ak->ak_size);
353 debug(Scratch);
354 # endif
355 /* get a contiguous chunk */
356 if ((p = malloc((unsigned) (ak->ak_size + 1))) == NULL) {
357 error(E_MALLOC, CONT);
358 for (i = 0; i < Nentries; ++i)
359 free(data[i]);
360 free((char *) data);
361 ak->ak_pid = ap->ac_pid;
362 ak->ak_resp = AK_REQFAIL;
363 ak->ak_size = 0;
364 sendack(ak);
365 break;
366 }
367 /* condense the data into the contiguous chunk */
368 *p = '\0';
369 for (i = 0; i < Nentries; ++i) {
370 (void) strcat(p, data[i]);
371 free(data[i]);
372 }
373 # ifdef DEBUG
374 debug(p);
375 # endif
376 if (data)
377 free((char *) data);
378 /* ak->ak_size was set above */
379 ak->ak_pid = ap->ac_pid;
380 ak->ak_resp = AK_ACK;
381 sendack(ak);
382 if (ak->ak_size)
383 if (write(Cfd, p, (unsigned) ak->ak_size) != ak->ak_size)
384 log("could not send info");
385 free(p);
386 break;
387
388 /*
389 * request for sac to read sactab
390 */
391
392 case AC_SACREAD:
393 # ifdef DEBUG
394 log("Got AC_SACREAD");
395 # endif
396 ak->ak_pid = ap->ac_pid;
397 ak->ak_resp = AK_ACK;
398 ak->ak_size = 0;
399 read_table(TRUE);
400 sendack(ak);
401 break;
402
403 /*
404 * request for port monitor to read _pmtab
405 */
406
407 case AC_PMREAD:
408 # ifdef DEBUG
409 (void) sprintf(Scratch, "Got AC_PMREAD for <%s>", ap->ac_tag);
410 log(Scratch);
411 # endif
412 if ((sp = findpm(ap->ac_tag)) == NULL) {
413 ak->ak_pid = ap->ac_pid;
414 ak->ak_resp = AK_NOPM;
415 ak->ak_size = 0;
416 sendack(ak);
417 break;
418 }
419 switch (sp->sc_sstate) {
420 case UNKNOWN:
421 ak->ak_pid = ap->ac_pid;
422 ak->ak_resp = AK_RECOVER;
423 ak->ak_size = 0;
424 sendack(ak);
425 break;
426 case NOTRUNNING:
427 case FAILED:
428 case STOPPING:
429 ak->ak_pid = ap->ac_pid;
430 ak->ak_resp = AK_PMNOTRUN;
431 ak->ak_size = 0;
432 sendack(ak);
433 break;
434 case STARTING:
435 case ENABLED:
436 case DISABLED:
437 sacmsg.sc_type = SC_READDB;
438 sacmsg.sc_size = 0;
439 sendpmmsg(sp, &sacmsg);
440 ak->ak_pid = ap->ac_pid;
441 ak->ak_resp = AK_ACK;
442 ak->ak_size = 0;
443 sendack(ak);
444 break;
445 }
446 break;
447 /*
448 * garbled message
449 */
450
451 default:
452 (void) sprintf(Scratch, "Got unknown message for <%s>", ap->ac_tag);
453 log(Scratch);
454 ak->ak_pid = ap->ac_pid;
455 ak->ak_resp = AK_UNKNOWN;
456 ak->ak_size = 0;
457 sendack(ak);
458 break;
459 }
460 break;
461 default:
462 error(E_POLL, EXIT);
463 }
464 }
465
466
467 /*
468 * sendack - send a response to the administrative command
469 *
470 * args: ap - pointer to acknowlegment message
471 */
472
473 void
sendack(ap)474 sendack(ap)
475 struct admack *ap;
476 {
477 # ifdef DEBUG
478 debug("in sendack");
479 # endif
480 if (write(Cfd, ap, sizeof(struct admack)) != sizeof(struct admack))
481 log("Could not send ack");
482 }
483
484
485 /*
486 * sendpmmsg - send a message to a PM. Note: sc_size is always 0 in
487 * this version so just send the header.
488 *
489 * args: sp - pointer to sac's port monitor information for
490 * designated port monitor
491 * sm - pointer to message to send
492 */
493
494 void
sendpmmsg(sp,sm)495 sendpmmsg(sp, sm)
496 register struct sactab *sp;
497 register struct sacmsg *sm;
498 {
499 char buf[SIZE]; /* scratch buffer */
500
501 # ifdef DEBUG
502 debug("in sendpmmsg");
503 # endif
504 if (write(sp->sc_fd, sm, sizeof(struct sacmsg)) != sizeof(struct sacmsg)) {
505 (void) sprintf(buf, "message to <%s> failed", sp->sc_tag);
506 log(buf);
507 }
508 }
509
510 /*
511 * sendsig - send a signal to the port monitor
512 *
513 * args: sp - pointer to sac's port monitor infomation for
514 * designated port monitor
515 * signo - signal number to send
516 */
517
518 int
sendsig(struct sactab * sp,int signo)519 sendsig(struct sactab *sp, int signo)
520 {
521 pid_t pid; /* pid of designated port monitor */
522 pid_t checklock();
523
524 # ifdef DEBUG
525 (void) sprintf(Scratch, "in sendsig - sending signo %d to %s", signo, sp->sc_tag);
526 debug(Scratch);
527 # endif
528 if (pid = checklock(sp)) {
529 if (kill(pid, signo) < 0) {
530 # ifdef DEBUG
531 debug("in sendsig - kill failed");
532 # endif
533 return(-1);
534 }
535 else
536 return(0);
537 }
538 else {
539 # ifdef DEBUG
540 debug("in sendsig - checklock failed");
541 # endif
542 return(-1);
543 }
544 }
545
546
547 /*
548 * checklock - check to see if a _pid file is locked
549 * if so, return pid in file, else 0
550 *
551 * args: sp - pointer to sac's port monitor infomation for
552 * designated port monitor
553 */
554
555 pid_t
checklock(sp)556 checklock(sp)
557 register struct sactab *sp;
558 {
559 int fd; /* scratch file descriptor */
560 char buf[SIZE]; /* scratch buffer */
561 int ret; /* return value */
562
563 # ifdef DEBUG
564 debug("in checklock");
565 # endif
566 (void) sprintf(Scratch, "%s/%s/_pid", HOME, sp->sc_tag);
567 fd = open(Scratch, O_RDONLY);
568 if (fd < 0) {
569 (void) sprintf(Scratch, "can not open _pid file for <%s>", sp->sc_tag);
570 log(Scratch);
571 return((pid_t)0);
572 }
573 if (lockf(fd, F_TEST, 0) < 0) {
574 if ((ret = read(fd, buf, SIZE - 1)) < 0) {
575 (void) close(fd);
576 return((pid_t)0);
577 }
578 (void) close(fd);
579 /* in case pid wasn't null-terminated */
580 buf[ret] = '\0';
581 return((pid_t)atol(buf));
582 }
583 (void) close(fd);
584 return((pid_t)0);
585 }
586