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/*
23 * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26/*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
27/*	  All Rights Reserved  	*/
28
29
30#pragma ident	"%Z%%M%	%I%	%E% SMI"
31
32
33#include <stdlib.h>
34#include <stdio.h>
35#include <errno.h>
36#include <fcntl.h>
37#include <signal.h>
38#include <string.h>
39#include <unistd.h>
40#include "ttymon.h"
41#include "tmextern.h"
42#include "sac.h"
43
44/*
45 *	openpid	- open the pid and put ttymon's pid in it
46 *		- put an advisory lock on the file
47 *		- to prevent another instance of ttymon in same directory
48 *		- SAC also makes use of the lock
49 *		- fd 0 is reserved for pid file
50 */
51void
52openpid()
53{
54	extern	int Lckfd;
55	char lockbuf[16];	/* large enough for a PID string */
56
57	(void)close(0);
58	/* open for read first, otherwise, may delete the pid already there*/
59	if ((Lckfd = open(PIDFILE, O_RDONLY)) != -1) {
60	     	if (lockf(Lckfd, F_TEST, 0L) == -1)
61			fatal("pid file is locked. ttymon may already be "
62			    "running!");
63		(void)close(Lckfd);
64	}
65
66	if ((Lckfd = open(PIDFILE, O_WRONLY|O_CREAT|O_TRUNC, 0644 )) != 0)
67		fatal("open pid file failed: %s", strerror(errno));
68
69	if (lockf(Lckfd, F_LOCK, 0L) == -1)
70		fatal("lock pid file failed: %s", strerror(errno));
71
72	(void) snprintf(lockbuf, sizeof (lockbuf), "%ld", getpid());
73	(void) write(Lckfd, lockbuf, strlen(lockbuf) + 1);
74#ifdef	DEBUG
75	log("fd(pid)\t = %d", Lckfd);
76#endif
77}
78
79/*
80 * openpipes() -- open pmpipe and sacpipe to communicate with SAC
81 *	       -- Pfd, Sfd are global file descriptors for pmpipe, sacpipe
82 */
83
84void
85openpipes()
86{
87	extern	int Pfd, Sfd;
88
89	Sfd = open(SACPIPE, O_WRONLY);
90	if (Sfd < 0)
91		fatal("open sacpipe failed: %s", strerror(errno));
92
93	Pfd = open(PMPIPE, O_RDWR|O_NONBLOCK);
94	if (Pfd < 0)
95		fatal("open pmpipe failed: %s", strerror(errno));
96
97#ifdef	DEBUG
98	log("fd(sacpipe)\t = %d",Sfd);
99	log("fd(pmpipe)\t = %d",Pfd);
100#endif
101}
102
103/*
104 * remove_env(env) - remove an environment variable from the environment
105 */
106static	void
107remove_env(env)
108char	*env;
109{
110	extern	char	**environ;
111	char	**p;
112	char	**rp = NULL;
113
114	p = environ;
115	if (p == NULL)
116		return;
117	while (*p) {
118		if (strncmp(*p, env,strlen(env)) == 0)
119			rp = p;
120		p++;
121	}
122	if (rp) {
123		*rp = *--p;
124		*p = NULL;
125	}
126}
127
128/*
129 * get_environ() -- get env variables PMTAG, ISTATE
130 *		 -- set global variables Tag, State
131 */
132
133void
134get_environ()
135{
136	extern 	char State, *Istate, *Tag;
137
138	if ((Tag = getenv("PMTAG")) == NULL)
139		fatal("PMTAG is missing");
140
141	if ((Istate = getenv("ISTATE")) == NULL)
142		fatal("ISTATE is missing");
143
144	State = (!strcmp(Istate, "enabled")) ? PM_ENABLED : PM_DISABLED;
145
146	/*
147	 * remove the environment variables so they will not
148	 * be passed to the children
149	 */
150	remove_env("ISTATE");
151	remove_env("PMTAG");
152}
153
154/*
155 * sacpoll	- the event handler when sac event is posted
156 */
157void
158sacpoll()
159{
160	int 	ret;
161	char	oldState;
162	struct 	sacmsg sacmsg;
163	struct 	pmmsg pmmsg;
164	sigset_t	cset;
165	sigset_t	tset;
166
167#ifdef	DEBUG
168	debug("in sacpoll");
169#endif
170
171	/* we don't want to be interrupted by sigchild now */
172	(void)sigprocmask(SIG_SETMASK, NULL, &cset);
173	tset = cset;
174	(void)sigaddset(&tset, SIGCLD);
175	(void)sigprocmask(SIG_SETMASK, &tset, NULL);
176
177	/*
178	 *	read sac messages, one at a time until no message
179	 *	is left on the pipe.
180	 *	the pipe is open with O_NONBLOCK, read will return -1
181	 *	and errno = EAGAIN if nothing is on the pipe
182	 */
183	for (;;) {
184
185		ret = read(Pfd, &sacmsg, sizeof(sacmsg));
186		if (ret < 0) {
187			switch(errno) {
188			case EAGAIN:
189				/* no more data on the pipe */
190				(void)sigprocmask(SIG_SETMASK, &cset, NULL);
191				return;
192			case EINTR:
193				break;
194			default:
195				fatal("pmpipe read failed: %s",
196				    strerror(errno));
197				break;  /*NOTREACHED*/
198			}
199		}
200		else if (ret == 0) {
201			/* no more data on the pipe */
202			(void)sigprocmask(SIG_SETMASK, &cset, NULL);
203			return;
204		}
205		else {
206			pmmsg.pm_size = 0;
207			(void) strcpy(pmmsg.pm_tag, Tag);
208			pmmsg.pm_maxclass = TM_MAXCLASS;
209			pmmsg.pm_type = PM_STATUS;
210			switch(sacmsg.sc_type) {
211			case SC_STATUS:
212				break;
213			case SC_ENABLE:
214				log("Got SC_ENABLE message");
215				oldState = State;
216				State = PM_ENABLED;
217				if (State != oldState) {
218#ifdef	DEBUG
219					debug("state changed to ENABLED");
220#endif
221					state_change();
222				}
223				break;
224			case SC_DISABLE:
225				log("Got SC_DISABLE message");
226				oldState = State;
227				State = PM_DISABLED;
228				if (State != oldState) {
229#ifdef	DEBUG
230					debug("state changed to DISABLED");
231#endif
232					state_change();
233				}
234				break;
235			case SC_READDB:
236				log("Got SC_READDB message");
237				Reread_flag = 1;
238				break;
239			default:
240				log("Got unknown message %d", sacmsg.sc_type);
241				pmmsg.pm_type = PM_UNKNOWN;
242				break;
243			} /* end switch */
244			pmmsg.pm_state = State;
245
246			while (write(Sfd, &pmmsg, sizeof(pmmsg)) != sizeof(pmmsg)) {
247				if (errno == EINTR)
248					continue;
249				log("sanity response to SAC failed: %s",
250				    strerror(errno));
251				break;
252			}
253		}
254	} /* end for loop */
255}
256