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