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
isRunning(int running=-1)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
log(void * param,LPCTSTR message,WORD eventType)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
exitcleanup()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
terminationHandler(int signum,siginfo_t * sinfo,void * dummy)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
setTerminationHandler()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 **/
lock_is_real(const char * lockfile)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 **/
lock_pid_file(const char * lockfile)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
main(int argc,char ** argv)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