📄 svcproc.cxx
字号:
/*
* svcproc.cxx
*
* Service process (daemon) implementation.
*
* Portable Windows Library
*
* Copyright (c) 1993-1998 Equivalence Pty. Ltd.
*
* The contents of this file are subject to the Mozilla Public License
* Version 1.0 (the "License"); you may not use this file except in
* compliance with the License. You may obtain a copy of the License at
* http://www.mozilla.org/MPL/
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* The Original Code is Portable Windows Library.
*
* The Initial Developer of the Original Code is Equivalence Pty. Ltd.
*
* Portions are Copyright (C) 1993 Free Software Foundation, Inc.
* All Rights Reserved.
*
* Contributor(s): ______________________________________.
*
* $Revision: 19008 $
* $Author: rjongbloed $
* $Date: 2007-11-29 09:17:41 +0000 (Thu, 29 Nov 2007) $
*/
#include <ptlib.h>
#pragma implementation "svcproc.h"
#include <ptlib/svcproc.h>
#ifdef P_VXWORKS
#include <logLib.h>
#define LOG_EMERG 0
#define LOG_ALERT 1
#define LOG_CRIT 2
#define LOG_ERR 3
#define LOG_WARNING 4
#define LOG_NOTICE 5
#define LOG_INFO 6
#define LOG_DEBUG 7
#else
#include <syslog.h>
#include <pwd.h>
#include <grp.h>
#endif
#include <stdarg.h>
#if (__GNUC__ >= 3)
#include <fstream>
#else
#include <fstream.h>
#endif
#include <signal.h>
#include "uerror.h"
#ifdef P_LINUX
#include <sys/resource.h>
#endif
#define new PNEW
extern void PXSignalHandler(int);
#define MAX_LOG_LINE_LEN 1024
#ifndef P_VXWORKS
static int PwlibLogToUnixLog[PSystemLog::NumLogLevels] = {
LOG_CRIT, // LogFatal,
LOG_ERR, // LogError,
LOG_WARNING, // LogWarning,
LOG_INFO, // LogInfo,
LOG_DEBUG, // LogDebug
LOG_DEBUG,
LOG_DEBUG,
LOG_DEBUG,
LOG_DEBUG,
LOG_DEBUG
};
#endif // !P_VXWORKS
static const char * const PLevelName[PSystemLog::NumLogLevels+1] = {
"Message",
"Fatal error",
"Error",
"Warning",
"Info",
"Debug",
"Debug2",
"Debug3",
"Debug4",
"Debug5",
"Debug6",
};
#ifdef P_MAC_MPTHREADS
// alas, this can't be statically initialized
// XXX This ought to be an MPCriticalRegionID, but they're broken in
// XXX Mac OS X 10.0.x!
static MPSemaphoreID logMutex;
// yuck.
static void SetUpLogMutex()
{
if (logMutex == 0) {
MPSemaphoreID tempCrit;
long err = MPCreateSemaphore(1, 1, &tempCrit);
PAssertOS(err == 0);
if (!OTCompareAndSwap32(0, (UInt32)tempCrit, (UInt32*)&logMutex)) {
// lost the race
MPDeleteSemaphore(tempCrit);
}
}
}
#endif
#ifdef P_PTHREADS
static pthread_mutex_t logMutex = PTHREAD_MUTEX_INITIALIZER;
#endif
void PSystemLog::Output(Level level, const char * cmsg)
{
PString systemLogFileName = PServiceProcess::Current().systemLogFileName;
if (systemLogFileName.IsEmpty()) {
#ifdef P_VXWORKS
printf("%s\n",cmsg);
logMsg((char *)(const char)cmsg,0,0,0,0,0,0);
#else
syslog(PwlibLogToUnixLog[level], "%s", cmsg);
#endif
}
else {
#ifdef P_PTHREADS
pthread_mutex_lock(&logMutex);
#endif
#ifdef P_MAC_MPTHREADS
SetUpLogMutex();
(void)MPWaitOnSemaphore(logMutex, kDurationForever);
#endif
ostream * out;
if (systemLogFileName == "-")
out = &cerr;
else
out = new ofstream(systemLogFileName, ios::app);
PTime now;
*out << now.AsString("yyyy/MM/dd hh:mm:ss.uuu\t");
PThread * thread = PThread::Current();
if (thread == NULL) {
#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
*out << "ThreadID=0x"
<< setfill('0') << ::hex
<< setw(8) << tid
<< setfill(' ') << ::dec;
} else {
PString threadName = thread->GetThreadName();
if (threadName.GetLength() <= 23)
*out << setw(23) << threadName;
else
*out << threadName.Left(10) << "..." << threadName.Right(10);
}
*out << '\t'
<< PLevelName[level+1]
<< '\t'
<< cmsg << endl;
if (out != &cerr)
delete out;
#ifdef P_PTHREADS
pthread_mutex_unlock(&logMutex);
#endif
#ifdef P_MAC_MPTHREADS
MPSignalSemaphore(logMutex);
#endif
}
}
int PSystemLog::Buffer::overflow(int c)
{
if (pptr() >= epptr()) {
int ppos = pptr() - pbase();
char * newptr = string.GetPointer(string.GetSize() + 10);
setp(newptr, newptr + string.GetSize() - 1);
pbump(ppos);
}
if (c != EOF) {
*pptr() = (char)c;
pbump(1);
}
return 0;
}
int PSystemLog::Buffer::underflow()
{
return EOF;
}
int PSystemLog::Buffer::sync()
{
PSystemLog::Output(log->logLevel, string);
string = PString();
char * base = string.GetPointer(10);
setp(base, base + string.GetSize() - 1);
return 0;
}
PServiceProcess::PServiceProcess(const char * manuf,
const char * name,
WORD majorVersion,
WORD minorVersion,
CodeStatus status,
WORD buildNumber)
: PProcess(manuf, name, majorVersion, minorVersion, status, buildNumber)
{
currentLogLevel = PSystemLog::Warning;
isTerminating = PFalse;
}
PServiceProcess::~PServiceProcess()
{
PSetErrorStream(NULL);
PTrace::SetStream(NULL);
PTrace::ClearOptions(PTrace::SystemLogStream);
if (!pidFileToRemove)
PFile::Remove(pidFileToRemove);
#ifndef P_VXWORKS
// close the system log
if (systemLogFileName.IsEmpty())
closelog();
#endif // !P_VXWORKS
}
PServiceProcess & PServiceProcess::Current()
{
PProcess & process = PProcess::Current();
PAssert(PIsDescendant(&process, PServiceProcess), "Not a service process!");
return (PServiceProcess &)process;
}
#ifndef P_VXWORKS
static int KillProcess(int pid, int sig)
{
if (kill(pid, sig) != 0)
return -1;
cout << "Sent SIG";
if (sig == SIGTERM)
cout << "TERM";
else
cout << "KILL";
cout << " to daemon at pid " << pid << ' ' << flush;
for (PINDEX retry = 1; retry <= 10; retry++) {
PThread::Sleep(1000);
if (kill(pid, 0) != 0) {
cout << "\nDaemon stopped." << endl;
return 0;
}
cout << '.' << flush;
}
cout << "\nDaemon has not stopped." << endl;
return 1;
}
#endif // !P_VXWORKS
void 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(PTrue);
#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(PFalse);
#endif
debugMode = PFalse;
// 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(PTrue) << 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)) {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -