Merge commit '00f1a4f432b3d8aad1aa270e91c44c57f03ef407'
[unleashed.git] / usr / src / cmd / saf / misc.c
blob84c0fb69ea632b931171dde1ce6c84c9d8c93a00
1 /*
2 * CDDL HEADER START
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.
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.
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]
20 * CDDL HEADER END
22 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
23 /* All Rights Reserved */
25 * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
26 * Use is subject to license terms.
29 #pragma ident "%Z%%M% %I% %E% SMI"
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"
50 * findpm - find a port monitor entry
52 * args: tag - tag of desired port monitor
56 struct sactab *
57 findpm(tag)
58 register char *tag;
60 register struct sactab *sp; /* working pointer */
62 for (sp = Sactab; sp; sp = sp->sc_next) {
63 if (!strcmp(tag, sp->sc_tag))
64 return(sp);
66 return(NULL);
71 * sigpoll - handle messages coming in on the command pipe (SIGPOLL signal
72 * handler)
76 void
77 sigpoll()
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 */
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);
106 switch (ap->ac_mtype) {
109 * request to start a port monitor
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;
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;
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;
159 break;
162 * request to kill a port monitor
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;
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;
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;
223 break;
226 * request to enable a port monitor
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;
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;
275 break;
278 * request to disable a port monitor
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;
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;
327 break;
330 * request for port monitor status information
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;
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;
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]);
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;
389 * request for sac to read sactab
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;
404 * request for port monitor to read _pmtab
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;
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;
446 break;
448 * garbled message
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;
460 break;
461 default:
462 error(E_POLL, EXIT);
468 * sendack - send a response to the administrative command
470 * args: ap - pointer to acknowlegment message
473 void
474 sendack(ap)
475 struct admack *ap;
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");
486 * sendpmmsg - send a message to a PM. Note: sc_size is always 0 in
487 * this version so just send the header.
489 * args: sp - pointer to sac's port monitor information for
490 * designated port monitor
491 * sm - pointer to message to send
494 void
495 sendpmmsg(sp, sm)
496 register struct sactab *sp;
497 register struct sacmsg *sm;
499 char buf[SIZE]; /* scratch buffer */
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);
511 * sendsig - send a signal to the port monitor
513 * args: sp - pointer to sac's port monitor infomation for
514 * designated port monitor
515 * signo - signal number to send
519 sendsig(struct sactab *sp, int signo)
521 pid_t pid; /* pid of designated port monitor */
522 pid_t checklock();
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);
535 else
536 return(0);
538 else {
539 # ifdef DEBUG
540 debug("in sendsig - checklock failed");
541 # endif
542 return(-1);
548 * checklock - check to see if a _pid file is locked
549 * if so, return pid in file, else 0
551 * args: sp - pointer to sac's port monitor infomation for
552 * designated port monitor
555 pid_t
556 checklock(sp)
557 register struct sactab *sp;
559 int fd; /* scratch file descriptor */
560 char buf[SIZE]; /* scratch buffer */
561 int ret; /* return value */
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);
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);
578 (void) close(fd);
579 /* in case pid wasn't null-terminated */
580 buf[ret] = '\0';
581 return((pid_t)atol(buf));
583 (void) close(fd);
584 return((pid_t)0);