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