📄 svcproc.cxx
字号:
#endif // !P_VXWORKSvoid PServiceProcess::_PXShowSystemWarning(PINDEX code, const PString & str){ PSYSTEMLOG(Warning, "PWLib\t" << GetOSClass() << " error #" << code << '-' << str);}int PServiceProcess::InitialiseService(){#ifndef P_VXWORKS#if PMEMORY_CHECK PMemoryHeap::SetIgnoreAllocations(TRUE);#endif PSetErrorStream(new PSystemLog(PSystemLog::StdError)); PTrace::SetStream(new PSystemLog(PSystemLog::Debug3)); PTrace::ClearOptions(PTrace::FileAndLine); PTrace::SetOptions(PTrace::SystemLogStream); PTrace::SetLevel(4);#if PMEMORY_CHECK PMemoryHeap::SetIgnoreAllocations(FALSE);#endif debugMode = FALSE; // parse arguments so we can grab what we want PArgList & args = GetArguments(); args.Parse("v-version." "d-daemon." "c-console." "h-help." "x-execute." "p-pid-file:" "H-handlemax:" "i-ini-file:" "k-kill." "t-terminate." "s-status." "l-log-file:" "u-uid:" "g-gid:" "C-core-size:"); // if only displaying version information, do it and finish if (args.HasOption('v')) { cout << "Product Name: " << productName << endl << "Manufacturer: " << manufacturer << endl << "Version : " << GetVersion(TRUE) << endl << "System : " << GetOSName() << '-' << GetOSHardware() << ' ' << GetOSVersion() << endl; return 0; } PString pidfilename; if (args.HasOption('p')) pidfilename = args.GetOptionString('p');#ifdef _PATH_VARRUN else pidfilename = _PATH_VARRUN;#endif if (!pidfilename && PDirectory::Exists(pidfilename)) pidfilename = PDirectory(pidfilename) + PProcess::Current().GetFile().GetFileName() + ".pid"; if (args.HasOption('k') || args.HasOption('t') || args.HasOption('s')) { pid_t pid; { ifstream pidfile(pidfilename); if (!pidfile.is_open()) { cout << "Could not open pid file: \"" << pidfilename << "\"" " - " << strerror(errno) << endl; return 1; } pidfile >> pid; if (pid == 0) { cout << "Illegal format pid file \"" << pidfilename << '"' << endl; return 1; } } if (args.HasOption('s')) { cout << "Process at " << pid << ' '; if (kill(pid, 0) == 0) cout << "is running."; else if (errno == ESRCH) cout << "does not exist."; else cout << " status could not be determined, error: " << strerror(errno); cout << endl; return 0; } int sig = args.HasOption('t') ? SIGTERM : SIGKILL; switch (KillProcess(pid, sig)) { case -1 : break; case 0 : PFile::Remove(pidfilename); return 0; case 1 : if (args.HasOption('t') && args.HasOption('k')) { switch (KillProcess(pid, SIGKILL)) { case -1 : break; case 0 : PFile::Remove(pidfilename); return 0; case 1 : return 2; } } else return 2; } cout << "Could not stop process " << pid << " - " << strerror(errno) << endl; return 1; } // Set the gid we are running under if (args.HasOption('g')) { PString gidstr = args.GetOptionString('g'); if (!SetGroupName(gidstr)) { cout << "Could not set GID to \"" << gidstr << "\" - " << strerror(errno) << endl; return 1; } } // Set the uid we are running under if (args.HasOption('u')) { PString uidstr = args.GetOptionString('u'); if (!SetUserName(uidstr)) { cout << "Could not set UID to \"" << uidstr << "\" - " << strerror(errno) << endl; return 1; } } BOOL helpAndExit = FALSE; // if displaying help, then do it if (args.HasOption('h')) helpAndExit = TRUE; else if (!args.HasOption('d') && !args.HasOption('x')) { cout << "error: must specify one of -v, -h, -t, -k, -d or -x" << endl; helpAndExit = TRUE; } // set flag for console messages if (args.HasOption('c')) { systemLogFileName = '-'; debugMode = TRUE; } if (args.HasOption('l')) { systemLogFileName = args.GetOptionString('l'); if (systemLogFileName.IsEmpty()) { cout << "error: must specify file name for -l" << endl; helpAndExit = TRUE; } else if (PDirectory::Exists(systemLogFileName)) systemLogFileName = PDirectory(systemLogFileName) + PProcess::Current().GetFile().GetFileName() + ".log"; } if (helpAndExit) { cout << "usage: [-c] -v|-d|-h|-x\n" " -h --help output this help message and exit\n" " -v --version display version information and exit\n"#if !defined(BE_THREADS) && !defined(P_RTEMS) " -d --daemon run as a daemon\n"#endif " -u --uid uid set user id to run as\n" " -g --gid gid set group id to run as\n" " -p --pid-file name or directory for pid file\n" " -t --terminate orderly terminate process in pid file\n" " -k --kill preemptively kill process in pid file\n" " -s --status check to see if daemon is running\n" " -c --console output messages to stdout rather than syslog\n" " -l --log-file file output messages to file or directory instead of syslog\n" " -x --execute execute as a normal program\n" " -i --ini-file set the ini file to use, may be explicit file or\n" " a ':' separated set of directories to search.\n" " -H --handlemax n set maximum number of file handles (set before uid/gid)\n"#ifdef P_LINUX " -C --core-size set the maximum core file size\n"#endif << endl; return 0; } // open the system logger for this program if (systemLogFileName.IsEmpty()) openlog((char *)(const char *)GetName(), LOG_PID, LOG_DAEMON); else if (systemLogFileName == "-") cout << "All output for " << GetName() << " is to console." << endl; else { ofstream logfile(systemLogFileName, ios::app); if (!logfile.is_open()) { cout << "Could not open log file \"" << systemLogFileName << "\"" " - " << strerror(errno) << endl; return 1; } } PSYSTEMLOG(StdError, "Starting service process \"" << GetName() << "\" v" << GetVersion(TRUE)); if (args.HasOption('i')) SetConfigurationPath(args.GetOptionString('i')); if (args.HasOption('H')) { int uid = geteuid(); seteuid(getuid()); // Switch back to starting uid for next call SetMaxHandles(args.GetOptionString('H').AsInteger()); seteuid(uid); } // set the core file size if (args.HasOption('C')) {#ifdef P_LINUX struct rlimit rlim; if (getrlimit(RLIMIT_CORE, &rlim) != 0) cout << "Could not get current core file size : error = " << errno << endl; else { int uid = geteuid(); seteuid(getuid()); // Switch back to starting uid for next call int v = args.GetOptionString('C').AsInteger(); rlim.rlim_cur = v; if (setrlimit(RLIMIT_CORE, &rlim) != 0) cout << "Could not set current core file size to " << v << " : error = " << errno << endl; else { getrlimit(RLIMIT_CORE, &rlim); cout << "Core file size set to " << rlim.rlim_cur << "/" << rlim.rlim_max << endl; } seteuid(uid); }#endif }#if !defined(BE_THREADS) && !defined(P_RTEMS) if (!args.HasOption('d')) return -1; // Run as a daemon, ie fork if (!pidfilename) { ifstream pidfile(pidfilename); if (pidfile.is_open()) { pid_t pid; pidfile >> pid; if (pid != 0 && kill(pid, 0) == 0) { cout << "Already have daemon running with pid " << pid << endl; return 2; } } } // Need to get rid of the config write thread before fork, as on // pthreads platforms the forked process does not have the thread CommonDestruct(); pid_t pid = fork(); switch (pid) { case 0 : // The forked process break; case -1 : // Failed cout << "Fork failed creating daemon process." << endl; return 1; default : // Parent process cout << "Daemon started with pid " << pid << endl; if (!pidfilename) { // Write out the child pid to magic file in /var/run (at least for linux) ofstream pidfile(pidfilename); if (pidfile.is_open()) pidfile << pid; else cout << "Could not write pid to file \"" << pidfilename << "\"" " - " << strerror(errno) << endl; } return 0; } // Set ourselves as out own process group so we don't get signals // from our parent's terminal (hopefully!) PSETPGRP(); CommonConstruct(); pidFileToRemove = pidfilename; // Only if we are running in the background as a daemon, we intercept // the core dumping signals so get a message in the log file. signal(SIGSEGV, PXSignalHandler); signal(SIGFPE, PXSignalHandler); signal(SIGBUS, PXSignalHandler); // Also if in background, don't want to get blocked on input from stdin ::close(STDIN_FILENO);#endif // !BE_THREADS && !P_RTEMS#endif // !P_VXWORKS return -1;}int PServiceProcess::_main(void *){ if ((terminationValue = InitialiseService()) < 0) { // Make sure housekeeping thread is going so signals are handled. SignalTimerChange(); terminationValue = 1; if (OnStart()) { terminationValue = 0; Main(); Terminate(); } } return terminationValue;}BOOL PServiceProcess::OnPause(){ return TRUE;}void PServiceProcess::OnContinue(){}void PServiceProcess::OnStop(){}void PServiceProcess::Terminate(){ if (isTerminating) { // If we are the process itself and another thread is terminating us, // just stop and wait forever for us to go away if (PThread::Current() == this) Sleep(PMaxTimeInterval); PSYSTEMLOG(Error, "Nested call to process termination!"); return; } isTerminating = TRUE; PSYSTEMLOG(Warning, "Stopping service process \"" << GetName() << "\" v" << GetVersion(TRUE)); // Avoid strange errors caused by threads (and the process itself!) being destoyed // before they have EVER been scheduled Yield(); // Do the services stop code OnStop();#ifndef P_VXWORKS // close the system log if (systemLogFileName.IsEmpty()) closelog();#endif // !P_VXWORKS // Now end the program exit(terminationValue);}void PServiceProcess::PXOnAsyncSignal(int sig){ const char * sigmsg; // Override the default behavious for these signals as that just // summarily exits the program. Allow PXOnSignal() to do orderly exit. switch (sig) { case SIGINT : case SIGTERM : case SIGHUP : return; case SIGSEGV : sigmsg = "segmentation fault (SIGSEGV)"; break; case SIGFPE : sigmsg = "floating point exception (SIGFPE)"; break;#ifndef __BEOS__ // In BeOS, SIGBUS is the same value as SIGSEGV case SIGBUS : sigmsg = "bus error (SIGBUS)"; break;#endif default : PProcess::PXOnAsyncSignal(sig); return; } signal(SIGSEGV, SIG_DFL); signal(SIGFPE, SIG_DFL); signal(SIGBUS, SIG_DFL); static BOOL inHandler = FALSE; if (inHandler) { raise(SIGQUIT); // Dump core _exit(-1); // Fail safe if raise() didn't dump core and exit } inHandler = TRUE;#ifdef P_MAC_MPTHREADS unsigned tid = (unsigned)MPCurrentTaskID();#elif defined(P_VXWORKS) unsigned tid = ::taskIdSelf();#elif defined(BE_THREADS) thread_id tid = ::find_thread(NULL);#else unsigned tid = (unsigned) pthread_self();#endif PThread * thread_ptr = activeThreads.GetAt(tid); char msg[200]; sprintf(msg, "\nCaught %s, thread_id=%u", sigmsg, tid); if (thread_ptr != NULL) { PString thread_name = thread_ptr->GetThreadName(); if (thread_name.IsEmpty()) sprintf(&msg[strlen(msg)], " obj_ptr=%p", thread_ptr); else { strcat(msg, " name="); strcat(msg, thread_name); } } strcat(msg, ", aborting.\n"); if (systemLogFileName.IsEmpty()) {#ifdef P_VXWORKS logMsg((char *)msg,0,0,0,0,0,0);#else syslog(LOG_CRIT, msg); closelog();#endif // !P_VXWORKS } else {#ifdef P_VXWORKS int fd = open(systemLogFileName, O_WRONLY|O_APPEND, FWRITE|FAPPEND);#else int fd = open(systemLogFileName, O_WRONLY|O_APPEND);#endif // !P_VXWORKS if (fd >= 0) { write(fd, msg, strlen(msg)); close(fd); } } raise(SIGQUIT); // Dump core _exit(-1); // Fail safe if raise() didn't dump core and exit}void PServiceProcess::PXOnSignal(int sig){ switch (sig) { case SIGINT : case SIGTERM : Terminate(); break; case SIGUSR1 : OnPause(); break; case SIGUSR2 : OnContinue(); break; case SIGHUP : if (currentLogLevel < PSystemLog::NumLogLevels-1) { currentLogLevel = (PSystemLog::Level)(currentLogLevel+1); PSystemLog s(PSystemLog::StdError); s << "Log level increased to " << PLevelName[currentLogLevel+1]; } break;#ifdef SIGWINCH case SIGWINCH : if (currentLogLevel > PSystemLog::Fatal) { currentLogLevel = (PSystemLog::Level)(currentLogLevel-1); PSystemLog s(PSystemLog::StdError); s << "Log level decreased to " << PLevelName[currentLogLevel+1]; } break;#endif }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -