xref: /illumos-gate/usr/src/cmd/saf/misc.c (revision 71815ce76261aa773c97600750fdce92334d1990)
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 *
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
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
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
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
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
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