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