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