xref: /titanic_41/usr/src/cmd/lms/main.cpp (revision d2b5b2d357ee3172eacb6860be1891259902203d)
1 /*******************************************************************************
2  * Copyright (C) 2004-2008 Intel Corp. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *  - Redistributions of source code must retain the above copyright notice,
8  *    this list of conditions and the following disclaimer.
9  *
10  *  - Redistributions in binary form must reproduce the above copyright notice,
11  *    this list of conditions and the following disclaimer in the documentation
12  *    and/or other materials provided with the distribution.
13  *
14  *  - Neither the name of Intel Corp. nor the names of its
15  *    contributors may be used to endorse or promote products derived from this
16  *    software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS''
19  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21  * ARE DISCLAIMED. IN NO EVENT SHALL Intel Corp. OR THE CONTRIBUTORS
22  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
23  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
24  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
25  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
26  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
27  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
28  * POSSIBILITY OF SUCH DAMAGE.
29  *******************************************************************************/
30 
31 #ifdef HAVE_CONFIG_H
32 #include "config.h"
33 #endif
34 #include "iatshareddata.h"
35 #include <cstdlib>
36 #include <cstdio>
37 #include <cerrno>
38 #include <csignal>
39 #include <syslog.h>
40 #include <unistd.h>
41 #include <sys/types.h>
42 #include <sys/stat.h>
43 #include <fcntl.h>
44 #include <sys/file.h>
45 #include "types.h"
46 #include "Protocol.h"
47 #include "version.h"
48 #include "ATVersion.h"
49 #include "glue.h"
50 
51 #ifdef __sun
52 #include <signal.h>
53 #endif
54 
55 #ifdef DAEMON
56 #include "daemonize.h"
57 #endif //DAEMON
58 
59 #define LOCK_PATH IATSTATERUNDIR
60 /* Change this to whatever your daemon is called */
61 #define DAEMON_PID_FILE "lms.pid"
62 
63 #define QUICK_CONNECT_COUNT 30
64 #define SLEEP_TIMEOUT 30
65 #define QUICK_SLEEP_TIMEOUT 5
66 
67 
68 bool isRunning(int running = -1)
69 {
70 	static int _running = 0;
71 	if (running >= 0)
72 	{
73 		_running = running;
74 	}
75 	if (_running == 1)
76 	{
77 		return true;
78 	}
79 	else
80 	{
81 		return false;
82 	}
83 }
84 
85 void log(void *param, LPCTSTR message, WORD eventType)
86 {
87 #ifdef DEBUGLOG
88 	syslog((int)eventType, "%s", message);
89 #endif
90 }
91 
92 //This needs to be global for termination action
93 Protocol prot;
94 int lock_pid_file_fd = -1;
95 glue plugin;
96 
97 void exitcleanup()
98 {
99 	prot.Deinit();
100 	prot.DestroySockets();
101 	//syslog(EVENTLOG_INFORMATION_TYPE, "Service stopped\n");
102 	closelog();
103 	if (-1 != lock_pid_file_fd) {
104 		close(lock_pid_file_fd);
105 		lock_pid_file_fd = -1;
106 		unlink(LOCK_PATH DAEMON_PID_FILE);
107 	}
108 
109 	plugin.deinit();
110 }
111 
112 //Action termination
113 #ifdef __sun
114 extern "C"
115 #endif
116 void terminationHandler(int signum, siginfo_t *sinfo, void *dummy)
117 {
118 	PRINT("LMS Service received - Signal:%d   Err:(%d) Code:(%d)\n", signum, sinfo->si_errno, sinfo->si_code);
119 	if (isRunning()) {
120 		syslog(EVENTLOG_WARNING_TYPE, "Received termination signal (%d)\n", signum);
121 
122 		isRunning(0);
123 
124 		exit(EXIT_SUCCESS);
125 	}
126 }
127 
128 void setTerminationHandler()
129 {
130 	int sigSet = 0;
131 	// Termination signal handler.
132 	struct sigaction terminateAction;
133 	// Set up the structure to specify the termination action.
134 	terminateAction.sa_sigaction = terminationHandler;
135 	sigemptyset(&terminateAction.sa_mask);
136 	terminateAction.sa_flags = SA_SIGINFO;
137 	sigSet &= sigaction(SIGTERM, &terminateAction, NULL);
138 	sigSet &= sigaction(SIGQUIT, &terminateAction, NULL);
139 	sigSet &= sigaction(SIGINT,  &terminateAction, NULL);
140 	sigSet &= sigaction(SIGHUP,  &terminateAction, NULL);
141 	sigSet &= sigaction(SIGPIPE, &terminateAction, NULL);
142 	sigSet &= sigaction(SIGALRM, &terminateAction, NULL);
143 	sigSet &= sigaction(SIGUSR1, &terminateAction, NULL);
144 	sigSet &= sigaction(SIGUSR2, &terminateAction, NULL);
145 
146 	if (sigSet != 0) {
147 		syslog(EVENTLOG_WARNING_TYPE, "Failed to register terminate signal handler\n");
148 	}
149 }
150 
151 /*
152  *  return: 1 if the lock is real, 0 if not real, -1 on error
153  **/
154 int lock_is_real(const char *lockfile)
155 {
156 	int lfp;
157 	char pid_buf[32];
158 	ssize_t count = 0;
159 	int lockpid;
160 
161 	lfp = open(lockfile, O_RDONLY);
162 	if (lfp < 0) {
163 		syslog(LOG_ERR,
164 			"unable to open lock file %s, code=%d (%s)",
165 			lockfile, errno, strerror(errno));
166 		return -1;
167 	}
168 
169 	count = read(lfp, pid_buf, sizeof(pid_buf)-1);
170 	if (count < 1) {
171 		syslog(LOG_ERR,
172 			"unable to read lock file %s, code=%d (%s)",
173 			lockfile, errno, strerror(errno));
174 		close(lfp);
175 		return -1;
176 	}
177 	close(lfp);
178 	pid_buf[count] = '\0';
179 
180 	lockpid = atoi(pid_buf);
181 	if (lockpid <= 1) {
182 		syslog(LOG_ERR, "bad pid in lock file %s", lockfile);
183 		return 0;
184 	}
185 
186 	/* See if the process still exists */
187 	if (kill(lockpid, 0) == 0) {
188 		/* Process exists, lock is real */
189 		return 1;
190 	}
191 	else {
192 		/* Process is gone */
193 		return 0;
194 	}
195 }
196 
197 /**
198  * 	lock_pid_file - creates a pid file and writes current process pid into it
199  *
200  *  lockfile - name of a file to be created
201  *
202  *  return: 0 on success, -1 on fatal error, -2 on error
203  **/
204 int lock_pid_file(const char *lockfile)
205 {
206 	int lfp = -1;
207 	size_t towrite = 0;
208 	ssize_t written = 0;
209 	int error = 0;
210 	int haserror = 0;
211 	char pid_buf[32];
212 
213 	/* Create the lock file as the current user */
214 	if (lockfile && lockfile[0]) {
215 #ifdef __sun
216 		lfp = open(lockfile, O_RDWR | O_CREAT | O_EXCL, 0644);
217 		if (lfp < 0) {
218 			if (errno == EEXIST) {
219 				if (lock_is_real(lockfile)) {
220 					syslog(LOG_ERR,
221 					"The LMS service is already running!");
222 				}
223 				else {
224 					unlink(lockfile);
225 				}
226 				return -2;
227 			}
228 			else {
229 				syslog(LOG_ERR,
230 					"unable to lock file %s, code=%d (%s)",
231 					lockfile, errno, strerror(errno));
232 				return -1;
233 			}
234 		}
235 		snprintf(pid_buf, sizeof(pid_buf), "%u", getpid());
236 		towrite = strnlen(pid_buf, 31);
237 		written = write(lfp, pid_buf, towrite);
238 #else
239 		lfp = open(lockfile, O_RDWR | O_CREAT, 0644);
240 		if (lfp < 0) {
241 			syslog(LOG_ERR,
242 			       "unable to create lock file %s, code=%d (%s)",
243 			       lockfile, errno, strerror(errno));
244 			return -1;
245 		}
246 
247 		if (-1 == flock(lfp, LOCK_EX | LOCK_NB)) {
248 			error = errno;
249 			if (EWOULDBLOCK == errno) {
250 				syslog(LOG_ERR, "The LMS service is already running!");
251 				close(lfp);
252 			} else {
253 				syslog(LOG_ERR,
254 				       "unable to lock file %s, code=%d (%s)",
255 				       lockfile, error, strerror(error));
256 				close(lfp);
257 				unlink(lockfile);
258 				return -2;
259 			}
260 			return -1;
261 		}
262 		if (-1 == ftruncate(lfp, 0)) {
263 			syslog(LOG_ERR,
264 			       "unable to fruncate lock file %s, code=%d (%s)",
265 			       lockfile, errno, strerror(errno));
266 			close(lfp);
267 			unlink(lockfile);
268 			return -2;
269 		}
270 		snprintf(pid_buf, sizeof(pid_buf), "%u", getpid());
271 		towrite = strnlen(pid_buf, 31);
272 		written = write(lfp, pid_buf, towrite);
273 		if (-1 == written) {
274 			error = errno;
275 			haserror = 1;
276 		} else if (towrite != (size_t)written) {
277 			haserror = 1;
278 		} else if (-1 == fsync(lfp)) {
279 			error = errno;
280 			haserror = 1;
281 		}
282 		if (1 == haserror) {
283 			syslog(LOG_ERR,
284 			       "unable to write pid into lock file %s, code=%d (%s)",
285 			       lockfile, error, strerror(error));
286 			close(lfp);
287 			unlink(lockfile);
288 			return -2;
289 		}
290 #endif // __sun
291 		lock_pid_file_fd = lfp;
292 	}
293 	return 0;
294 }
295 
296 
297 int main(int argc, char **argv)
298 {
299 	bool alreadyFailed = false;
300 	bool firstLoop = true;
301 	bool init = false;
302 	int connectCount = 0;
303 	int lockresult = -1;
304 
305 	if (ATVersion::ShowVersionIfArg(argc, const_cast<const char **>(argv), VER_PRODUCTVERSION_STR)) {
306 		return 0;
307 	}
308 
309 	umask(022);
310 
311 	openlog("LMS", LOG_CONS, LOG_DAEMON);
312 
313 #ifdef DAEMON
314 	daemonize();
315 #else
316 	setTerminationHandler();
317 #endif
318 
319 	lockresult = lock_pid_file(LOCK_PATH DAEMON_PID_FILE);
320 	if (-2 == lockresult) {
321 		lockresult = lock_pid_file(LOCK_PATH DAEMON_PID_FILE);
322 	}
323 	if (0 != lockresult) {
324 		exit(EXIT_FAILURE);
325 	}
326 
327 	isRunning(1);
328 	//syslog(EVENTLOG_INFORMATION_TYPE, "Service started\n");
329 
330 	atexit(exitcleanup);
331 
332 	plugin.init();
333 
334 	while (isRunning()) {
335 		if (!prot.IsInitialized()) {
336 			if (init) {
337 #ifdef DEBUGLOG
338 				log(NULL, "LMS Service lost connection to AMT via HECI driver", EVENTLOG_ERROR_TYPE);
339 #endif
340 				init = false;
341 			}
342 
343 			if (!prot.Init(log, NULL)) {
344 				if (firstLoop) {
345 					syslog(EVENTLOG_ERROR_TYPE, "Cannot connect to AMT via HECI driver");
346 					firstLoop = false;
347 				}
348 				// Failed to connect to the HECI driver.
349 				// Sleep for a second and try again.
350 				connectCount++;
351 				if (connectCount >= QUICK_CONNECT_COUNT) {
352 					sleep(SLEEP_TIMEOUT);
353 				} else {
354 					sleep(QUICK_SLEEP_TIMEOUT);
355 				}
356 				continue;
357 			}
358 			init = true;
359 			firstLoop = false;
360 			connectCount = 0;
361 #ifdef DEBUGLOG
362 			log(NULL, "Connected to AMT via HECI driver\n", EVENTLOG_INFORMATION_TYPE);
363 #endif
364 		}
365 
366 		if (!prot.SocketsCreated()) {
367 			if (!prot.CreateSockets()) {
368 				if (!alreadyFailed) {
369 #ifdef DEBUGLOG
370 					log(NULL, "LMS Service has a problem in achieving network resources.", EVENTLOG_ERROR_TYPE);
371 #endif
372 					alreadyFailed = true;
373 				}
374 				continue;
375 			} else {
376 				alreadyFailed = false;
377 			}
378 		}
379 		// Select on active sockets (IANA ports and open connections).
380 		prot.Select();
381 	}
382 
383 	return 0;
384 }
385