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