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