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
56struct sactab *
57findpm(tag)
58register 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
76void
77sigpoll()
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
473void
474sendack(ap)
475struct 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
494void
495sendpmmsg(sp, sm)
496register struct sactab *sp;
497register 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
518int
519sendsig(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
555pid_t
556checklock(sp)
557register 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