00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00037 #include "OW_config.h"
00038 #include "OW_Platform.hpp"
00039 #include "OW_ConfigOpts.hpp"
00040 #include "OW_Format.hpp"
00041 #include "OW_PidFile.hpp"
00042 #include "OW_ExceptionIds.hpp"
00043 #include "OW_PlatformSignal.hpp"
00044 #include "OW_ServiceEnvironmentIFC.hpp"
00045 #include "OW_Logger.hpp"
00046
00047 #ifdef OW_NETWARE
00048 #include "OW_Condition.hpp"
00049 #include "OW_NonRecursiveMutex.hpp"
00050 #include "OW_NonRecursiveMutexLock.hpp"
00051 #endif
00052
00053 extern "C"
00054 {
00055 #include <sys/types.h>
00056 #include <sys/stat.h>
00057 #include <errno.h>
00058 #if defined(OW_HAVE_GETOPT_H) && !defined(OW_GETOPT_AND_UNISTD_CONFLICT)
00059 #include <getopt.h>
00060 #else
00061 #include <stdlib.h>
00062 #endif
00063 #ifdef WIN32
00064 #include <process.h>
00065 #define getpid _getpid
00066 #else
00067 #include <unistd.h>
00068 #endif
00069 #include <signal.h>
00070 #include <fcntl.h>
00071 #if defined (OW_HAVE_PWD_H)
00072 #include <pwd.h>
00073 #endif
00074 #if defined (OW_HAVE_SYS_RESOURCE_H)
00075 #include <sys/resource.h>
00076 #endif
00077 #if defined(OW_HAVE_GRP_H)
00078 #include <grp.h>
00079 #endif
00080
00081 #ifdef OW_NETWARE
00082 #include <nks/vm.h>
00083 #include <nks/netware.h>
00084 #include <netware.h>
00085 #include <event.h>
00086 #include <library.h>
00087 #endif
00088 }
00089 #include <cstring>
00090 #include <cstdio>
00091 #include <iostream>
00092
00093 using namespace std;
00094
00095 namespace OW_NAMESPACE
00096 {
00097
00098 using std::ostream;
00099 using std::endl;
00100
00101 OW_DEFINE_EXCEPTION_WITH_ID(Daemon);
00102
00103 namespace Platform
00104 {
00105
00106 extern "C" {
00107 static void theSigHandler(int sig, siginfo_t* info, void* context);
00108 }
00109
00110 namespace
00111 {
00112 const String COMPONENT_NAME("ow.owcimomd");
00113
00114 const int DAEMONIZE_PIPE_TIMEOUT = 25;
00115
00116 void handleSignal(int sig);
00117 void setupSigHandler(bool dbgFlg);
00118
00119 UnnamedPipeRef plat_upipe;
00120
00121 UnnamedPipeRef daemonize_upipe;
00122
00123 char** g_argv = 0;
00124
00125 #ifdef OW_NETWARE
00126 Condition g_shutdownCond;
00127 bool g_shutDown = false;
00128 NonRecursiveMutex g_shutdownGuard;
00129 void* WarnFuncRef = NULL;
00130 rtag_t EventRTag;
00131 event_handle_t DownEvent;
00132 bool FromEventHandler = false;
00133 #endif
00134
00135 }
00136
00138 void
00139 daemonInit( int argc, char* argv[] )
00140 {
00141 g_argv = argv;
00142 }
00147 void
00148 daemonize(bool dbgFlg, const String& daemonName, const ServiceEnvironmentIFCRef& env)
00149 {
00150 #ifndef WIN32
00151 #ifdef OW_NETWARE
00152 {
00153 NonRecursiveMutexLock l(g_shutdownGuard);
00154 g_shutDown = false;
00155 }
00156 #endif
00157 initDaemonizePipe();
00158
00159
00160 if (geteuid() == 0 && !env->getConfigItem(ConfigOpts::DROP_ROOT_PRIVILEGES_opt, OW_DEFAULT_DROP_ROOT_PRIVILEGES).equalsIgnoreCase("false"))
00161 {
00162 const char OWCIMOMD_USER[] = "owcimomd";
00163
00164 struct passwd* owcimomdInfo = ::getpwnam(OWCIMOMD_USER);
00165 if (!owcimomdInfo)
00166 {
00167 OW_THROW_ERRNO_MSG(DaemonException, "Platform::daemonize(): getpwnam(\"owcimomd\")");
00168 }
00169 if (::setgid(owcimomdInfo->pw_gid) != 0)
00170 {
00171 OW_THROW_ERRNO_MSG(DaemonException, "Platform::daemonize(): setgid");
00172 }
00173 if (::initgroups(owcimomdInfo->pw_name, owcimomdInfo->pw_gid) != 0)
00174 {
00175 OW_THROW_ERRNO_MSG(DaemonException, "Platform::daemonize(): initgroups");
00176 }
00177 if (::setuid(owcimomdInfo->pw_uid) != 0)
00178 {
00179 OW_THROW_ERRNO_MSG(DaemonException, "Platform::daemonize(): setuid");
00180 }
00181 }
00182
00183
00184 int pid = -1;
00185 #if !defined(OW_NETWARE)
00186 String pidFile(env->getConfigItem(ConfigOpts::PIDFILE_opt, OW_DEFAULT_PIDFILE));
00187 pid = PidFile::checkPid(pidFile.c_str());
00188
00189 if (pid != -1)
00190 {
00191 OW_THROW(DaemonException,
00192 Format("Another instance of %1 is already running [%2]",
00193 daemonName, pid).c_str());
00194 }
00195 #endif
00196 if (!dbgFlg)
00197 {
00198 #if !defined(OW_NETWARE) && !defined(WIN32)
00199 pid = fork();
00200 switch (pid)
00201 {
00202 case 0:
00203 break;
00204 case -1:
00205 OW_THROW_ERRNO_MSG(DaemonException,
00206 "FAILED TO DETACH FROM THE TERMINAL - First fork");
00207 default:
00208 int status = DAEMONIZE_FAIL;
00209 if (daemonize_upipe->readInt(&status) < 1
00210 || status != DAEMONIZE_SUCCESS)
00211 {
00212 cerr << "Error starting CIMOM. Check the log files." << endl;
00213 _exit(1);
00214 }
00215 _exit(0);
00216 }
00217 if (setsid() < 0)
00218 {
00219 OW_THROW(DaemonException,
00220 "FAILED TO DETACH FROM THE TERMINAL - setsid failed");
00221 }
00222 pid = fork();
00223 switch (pid)
00224 {
00225 case 0:
00226 break;
00227 case -1:
00228 {
00229
00230 int saved_errno = errno;
00231 sendDaemonizeStatus(DAEMONIZE_FAIL);
00232
00233 errno = saved_errno;
00234 OW_THROW_ERRNO_MSG(DaemonException,
00235 "FAILED TO DETACH FROM THE TERMINAL - Second fork");
00236 exit(1);
00237 }
00238 default:
00239 _exit(0);
00240 }
00241 #endif
00242 chdir("/");
00243 close(0);
00244 close(1);
00245 close(2);
00246 open("/dev/null", O_RDONLY);
00247 open("/dev/null", O_WRONLY);
00248 dup(1);
00249 }
00250 else
00251 {
00252 pid = getpid();
00253 }
00254 umask(0077);
00255 #if !defined(OW_NETWARE)
00256 if (PidFile::writePid(pidFile.c_str()) == -1)
00257 {
00258
00259 int saved_errno = errno;
00260 sendDaemonizeStatus(DAEMONIZE_FAIL);
00261
00262 errno = saved_errno;
00263 OW_THROW_ERRNO_MSG(DaemonException,
00264 Format("Failed to write the pid file (%1)", pidFile).c_str());
00265 }
00266 #endif
00267 OW_LOG_INFO(env->getLogger(COMPONENT_NAME), Format("Platform::daemonize() pid = %1", ::getpid()));
00268 #endif
00269 initSig();
00270 #ifndef WIN32
00271 setupSigHandler(dbgFlg);
00272 #endif
00273
00274 #ifdef OW_HAVE_PTHREAD_ATFORK
00275
00276
00277 ::pthread_atfork(NULL, NULL, &shutdownSig);
00278 #endif
00279 }
00281 int
00282 daemonShutdown(const String& daemonName, const ServiceEnvironmentIFCRef& env)
00283 {
00284 #ifndef WIN32
00285 #if defined(OW_NETWARE)
00286 (void)daemonName;
00287 {
00288 NonRecursiveMutexLock l(g_shutdownGuard);
00289 g_shutDown = true;
00290 g_shutdownCond.notifyAll();
00291 pthread_yield();
00292 }
00293 if(!FromEventHandler)
00294 {
00295 UnRegisterEventNotification(DownEvent);
00296 }
00297 #else
00298 String pidFile(env->getConfigItem(ConfigOpts::PIDFILE_opt, OW_DEFAULT_PIDFILE));
00299 PidFile::removePid(pidFile.c_str());
00300 #endif
00301 #endif
00302 shutdownSig();
00303 return 0;
00304 }
00305
00307 void rerunDaemon()
00308 {
00309 #ifndef WIN32
00310 #ifdef OW_HAVE_PTHREAD_KILL_OTHER_THREADS_NP
00311
00312
00313
00314 pthread_kill_other_threads_np();
00315 #endif
00316
00317 #ifdef OW_DARWIN
00318
00319
00320
00321 if (::fork() != 0)
00322 {
00323 _exit(1);
00324 }
00325
00326 #endif
00327
00328
00329
00330
00331
00332
00333 rlimit rl;
00334 int i = sysconf(_SC_OPEN_MAX);
00335 if (getrlimit(RLIMIT_NOFILE, &rl) != -1)
00336 {
00337 if ( i < 0 )
00338 {
00339 i = rl.rlim_max;
00340 }
00341 else
00342 {
00343 i = std::min<int>(rl.rlim_max, i);
00344 }
00345 }
00346
00347 struct flock lck;
00348 ::memset (&lck, '\0', sizeof (lck));
00349 lck.l_type = F_UNLCK;
00350 lck.l_whence = 0;
00351 lck.l_start = 0L;
00352 lck.l_len = 0L;
00353
00354 while (i > 2)
00355 {
00356
00357
00358 ::fcntl(i, F_SETLK, &lck);
00359
00360
00361 ::fcntl(i, F_SETFD, FD_CLOEXEC);
00362 i--;
00363 }
00364
00365
00366
00367
00368 sigset_t emptymask;
00369 sigemptyset(&emptymask);
00370 ::sigprocmask(SIG_SETMASK, &emptymask, 0);
00371 #endif
00372
00373
00374
00375 ::execv(g_argv[0], g_argv);
00376
00377
00378 OW_THROW_ERRNO_MSG(DaemonException, "execv() failed");
00379 }
00380
00382 void restartDaemon()
00383 {
00384 #ifdef WIN32
00385 rerunDaemon();
00386 #else
00387 ::kill(::getpid(), SIGHUP);
00388 #endif
00389 }
00390
00391 #ifndef WIN32
00392
00393 namespace
00394 {
00395
00397 #if !defined(OW_HAVE_SIGHANDLER_T)
00398 typedef void (*sighandler_t)(int);
00399 #endif
00400
00401 void
00402 handleSignalAux(int sig, sighandler_t handler)
00403 {
00404 struct sigaction temp;
00405 memset(&temp, '\0', sizeof(temp));
00406 sigaction(sig, 0, &temp);
00407 temp.sa_handler = handler;
00408 sigemptyset(&temp.sa_mask);
00409
00410
00411
00412
00413
00414
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425 temp.sa_flags = 0;
00426 sigaction(sig, &temp, NULL);
00427 }
00428
00429
00430
00431
00432 typedef void (*full_sighandler_t)(int,siginfo_t*,void*);
00433
00434
00435
00436
00437
00438 void
00439 handleSignalAux(int sig, full_sighandler_t handler)
00440 {
00441 struct sigaction temp;
00442 memset(&temp, '\0', sizeof(temp));
00443 sigaction(sig, 0, &temp);
00444 temp.sa_sigaction = handler;
00445 sigemptyset(&temp.sa_mask);
00446
00447
00448
00449
00450
00451
00452
00453
00454
00455
00456
00457
00458
00459
00460
00461 temp.sa_flags = SA_SIGINFO;
00462 sigaction(sig, &temp, NULL);
00463 }
00464
00465 void
00466 handleSignal(int sig)
00467 {
00468 handleSignalAux(sig, theSigHandler);
00469 }
00470 void
00471 ignoreSignal(int sig)
00472 {
00473 handleSignalAux(sig, SIG_IGN);
00474 }
00475
00476 }
00477
00478 #endif
00479
00481 extern "C" {
00482 static void
00483 theSigHandler(int sig, siginfo_t* info, void* context)
00484 {
00485 int savedErrno = errno;
00486 try
00487 {
00488 Signal::SignalInformation extractedSignal;
00489 if( info )
00490 {
00491 Signal::extractSignalInformation( *info, extractedSignal );
00492 }
00493
00494 switch (sig)
00495 {
00496 case SIGTERM:
00497 case SIGINT:
00498 #if defined(OW_NETWARE)
00499 case SIGABRT:
00500 #endif
00501 extractedSignal.signalAction = SHUTDOWN;
00502 pushSig(extractedSignal);
00503 break;
00504 #ifndef OW_WIN32
00505 case SIGHUP:
00506 extractedSignal.signalAction = REINIT;
00507 pushSig(extractedSignal);
00508 break;
00509 #endif
00510 }
00511 }
00512 catch (...)
00513 {
00514 }
00515 errno = savedErrno;
00516
00517 }
00518
00519 #ifndef WIN32
00520
00521 static void
00522 fatalSigHandler(int sig, siginfo_t* info, void* context)
00523 {
00524
00525
00526 Platform::rerunDaemon();
00527 }
00528
00529 #ifdef OW_NETWARE
00530 static void
00531 netwareExitHandler(void*)
00532 {
00533 theSigHandler(SIGTERM);
00534 pthread_yield();
00535 NonRecursiveMutexLock l(g_shutdownGuard);
00536 while(!g_shutDown)
00537 {
00538 g_shutdownCond.wait(l);
00539 }
00540 }
00541
00542 static int
00543 netwareShutDownEventHandler(void*,
00544 void*, void*)
00545 {
00546 FromEventHandler = true;
00547 theSigHandler(SIGTERM);
00548 pthread_yield();
00549 NonRecursiveMutexLock l(g_shutdownGuard);
00550 while(!g_shutDown)
00551 {
00552 g_shutdownCond.wait(l);
00553 }
00554 return 0;
00555 }
00556 #endif
00557
00558 #endif
00559 }
00560 #ifndef WIN32
00561
00562 namespace
00563 {
00565 void
00566 setupSigHandler(bool dbgFlg)
00567 {
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582 if (dbgFlg)
00583 {
00584 handleSignal(SIGINT);
00585 }
00586 else
00587 {
00588 ignoreSignal(SIGINT);
00589 }
00590 handleSignal(SIGTERM);
00591 handleSignal(SIGHUP);
00592
00593
00594
00595
00596
00597
00598 ignoreSignal(SIGTTIN);
00599 ignoreSignal(SIGTTOU);
00600 ignoreSignal(SIGTSTP);
00601 #ifdef SIGPOLL
00602 ignoreSignal(SIGPOLL);
00603 #endif
00604 #ifdef SIGIO
00605 ignoreSignal(SIGIO);
00606 #endif
00607 ignoreSignal(SIGPIPE);
00608
00609 #ifdef SIGIOT // NetWare doesn't have this signal
00610 ignoreSignal(SIGIOT);
00611 #endif
00612 ignoreSignal(SIGCONT);
00613 #ifdef SIGURG // NetWare doesn't have this signal
00614 ignoreSignal(SIGURG);
00615 #endif
00616 #ifdef SIGXCPU // NetWare doesn't have this signal
00617 ignoreSignal(SIGXCPU);
00618 #endif
00619 #ifdef SIGXFSZ // NetWare doesn't have this signal
00620 ignoreSignal(SIGXFSZ);
00621 #endif
00622 #ifdef SIGVTALRM // NetWare doesn't have this signal
00623 ignoreSignal(SIGVTALRM);
00624 #endif
00625 #ifdef SIGPROF // NetWare doesn't have this signal
00626 ignoreSignal(SIGPROF);
00627 #endif
00628 #ifdef SIGPWR // FreeBSD doesn't have SIGPWR
00629 ignoreSignal(SIGPWR);
00630 #endif
00631
00632
00633
00634
00635 #ifdef OW_NETWARE
00636 int rv;
00637 if ((rv = NXVmRegisterExitHandler(netwareExitHandler, 0) != 0))
00638 {
00639 OW_THROW(DaemonException,
00640 Format("FAILED TO REGISTER EXIT HANDLER "
00641 "NXVmRegisterExitHandler returned %1", rv).c_str());
00642 }
00643 EventRTag = AllocateResourceTag(getnlmhandle(), "Server down event",
00644 EventSignature);
00645 if(!EventRTag)
00646 {
00647 OW_THROW(DaemonException, "AllocationResourceTag FAILED");
00648 }
00649 NX_WRAP_INTERFACE((void*)netwareShutDownEventHandler, 3, &WarnFuncRef);
00650 DownEvent = RegisterForEventNotification(EventRTag,
00651 EVENT_DOWN_SERVER | EVENT_CONSUMER_MT_SAFE,
00652 EVENT_PRIORITY_APPLICATION, (Warn_t)WarnFuncRef, (Report_t)0, 0);
00653 if(!DownEvent)
00654 {
00655 OW_THROW(DaemonException, "FAILED to register for shutdown event");
00656 }
00657 #endif
00658 }
00659
00660 }
00661
00663 void installFatalSignalHandlers()
00664 {
00665 handleSignalAux(SIGABRT, fatalSigHandler);
00666
00667 handleSignalAux(SIGILL, fatalSigHandler);
00668 #ifdef SIGBUS // NetWare doesn't have this signal
00669 handleSignalAux(SIGBUS, fatalSigHandler);
00670 #endif
00671 handleSignalAux(SIGSEGV, fatalSigHandler);
00672 handleSignalAux(SIGFPE, fatalSigHandler);
00673 }
00674
00676 void removeFatalSignalHandlers()
00677 {
00678 handleSignalAux(SIGABRT, SIG_DFL);
00679
00680 handleSignalAux(SIGILL, SIG_DFL);
00681 #ifdef SIGBUS // NetWare doesn't have this signal
00682 handleSignalAux(SIGBUS, SIG_DFL);
00683 #endif
00684 handleSignalAux(SIGSEGV, SIG_DFL);
00685 handleSignalAux(SIGFPE, SIG_DFL);
00686 }
00687 #else // WIN32
00688
00689 BOOL WINAPI CtrlHandlerRoutine(DWORD dwCtrlType)
00690 {
00691 theSigHandler(SIGTERM, 0, 0);
00692 return TRUE;
00693 }
00694
00695 void installFatalSignalHandlers()
00696 {
00697 ::SetConsoleCtrlHandler(CtrlHandlerRoutine, TRUE);
00698 }
00699
00700 void removeFatalSignalHandlers()
00701 {
00702 ::SetConsoleCtrlHandler(CtrlHandlerRoutine, FALSE);
00703 }
00704
00705 #endif // WIN32
00706
00708 void initDaemonizePipe()
00709 {
00710 daemonize_upipe = UnnamedPipe::createUnnamedPipe();
00711 daemonize_upipe->setTimeouts(DAEMONIZE_PIPE_TIMEOUT);
00712 }
00713
00715 void sendDaemonizeStatus(int status)
00716 {
00717 if (daemonize_upipe)
00718 {
00719 daemonize_upipe->writeInt(status);
00720 }
00721 }
00722
00724 void initSig()
00725 {
00726 plat_upipe = UnnamedPipe::createUnnamedPipe();
00727 plat_upipe->setBlocking(UnnamedPipe::E_NONBLOCKING);
00728 }
00730 void pushSig(const Signal::SignalInformation& sig)
00731 {
00732 if (plat_upipe)
00733 {
00734 Signal::flattenSignalInformation(sig, plat_upipe);
00735 }
00736
00737 }
00739 int popSig(Signal::SignalInformation& sig)
00740 {
00741 int tmp = -2;
00742 if (plat_upipe)
00743 {
00744 if( !Signal::unflattenSignalInformation(sig, plat_upipe) )
00745 {
00746 return -1;
00747 }
00748 tmp = sig.signalAction;
00749 }
00750 return tmp;
00751 }
00753 void shutdownSig()
00754 {
00755 plat_upipe = 0;
00756 }
00757
00759 SelectableIFCRef getSigSelectable()
00760 {
00761 return plat_upipe;
00762 }
00763
00764
00766
00767 }
00768 }
00769