4 * Service process (daemon) implementation.
6 * Portable Windows Library
8 * Copyright (c) 1993-1998 Equivalence Pty. Ltd.
10 * The contents of this file are subject to the Mozilla Public License
11 * Version 1.0 (the "License"); you may not use this file except in
12 * compliance with the License. You may obtain a copy of the License at
13 * http://www.mozilla.org/MPL/
15 * Software distributed under the License is distributed on an "AS IS"
16 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
17 * the License for the specific language governing rights and limitations
20 * The Original Code is Portable Windows Library.
22 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
24 * Portions are Copyright (C) 1993 Free Software Foundation, Inc.
25 * All Rights Reserved.
27 * Contributor(s): ______________________________________.
30 * Revision 1.84 2004/02/22 03:31:50 ykiryanov
31 * Added current thread id routine to BeOS code
33 * Revision 1.83 2003/09/17 09:02:14 csoutheren
34 * Removed memory leak detection code
36 * Revision 1.82 2003/01/14 04:43:21 robertj
37 * Improved output on error in getting service status.
39 * Revision 1.81 2002/12/12 00:54:29 robertj
40 * Fixed issue with setting max file handles causing a log file to be created
41 * as root (real uid) rather than as the user determined by the -u arg.
42 * Utilised new PProcess functions for setting user and group.
44 * Revision 1.80 2002/12/02 08:27:43 robertj
45 * Fixed incorrectly set #if statement from RTEMS patch.
47 * Revision 1.79 2002/12/02 03:57:18 robertj
48 * More RTEMS support patches, thank you Vladimir Nesic.
50 * Revision 1.78 2002/11/02 00:32:21 robertj
51 * Further fixes to VxWorks (Tornado) port, thanks Andreas Sikkema.
53 * Revision 1.77 2002/10/30 03:14:15 robertj
54 * Added tab character between time and thread in system log (for db import).
56 * Revision 1.76 2002/10/23 04:26:27 robertj
57 * Fixed extra debug levels in system log dump.
59 * Revision 1.75 2002/10/17 13:44:27 robertj
60 * Port to RTEMS, thanks Vladimir Nesic.
62 * Revision 1.74 2002/10/17 12:57:24 robertj
63 * Added ability to increase maximum file handles on a process.
65 * Revision 1.73 2002/10/10 04:43:44 robertj
66 * VxWorks port, thanks Martijn Roest
68 * Revision 1.72 2002/10/03 01:27:51 robertj
69 * Added fail safe _exit() as it appears raise(SIGQUIT) does not always dump
70 * core and exit the app causing endless SEGV's to appear the log file!
72 * Revision 1.71 2002/10/01 06:03:44 robertj
73 * Attempt to prevent recursive signals for SEGV etc
75 * Revision 1.70 2002/09/06 13:29:06 robertj
76 * Added missing help line for status command.
78 * Revision 1.69 2002/07/15 06:39:23 craigs
79 * Added function to allow raising of per-process file handle limit
81 * Revision 1.68 2002/06/13 08:50:11 rogerh
82 * GCC 3.1 uses slightly different #includes
84 * Revision 1.67 2002/06/05 12:29:16 craigs
87 * Revision 1.66 2002/04/17 03:31:48 robertj
88 * Renamed system log file member variable to be common with Windows version.
90 * Revision 1.65 2002/03/18 08:03:30 robertj
91 * Fixed hex output of thread pid.
92 * Added ability to have -tk option wich attempt to terminate a daemon and
93 * if no response in 10 seconds kills it.
94 * Fixed leaving .pid file behind when using -k option.
96 * Revision 1.64 2002/02/19 07:12:36 rogerh
99 * Revision 1.63 2001/12/16 23:40:16 robertj
100 * Fixed system log so does not crash if current thread not created by PWLib.
102 * Revision 1.62 2001/12/09 23:45:20 craigs
103 * Set debugMode flag when in .... debug mode!
105 * Revision 1.61 2001/09/20 05:35:47 robertj
106 * Fixed crash (race condition) if shutdown service via signal and exit main.
108 * Revision 1.60 2001/08/11 15:38:43 rogerh
109 * Add Mac OS Carbon changes from John Woods <jfw@jfwhome.funhouse.com>
111 * Revision 1.59 2001/08/07 03:05:54 robertj
112 * Expanded thread name field width in system log.
114 * Revision 1.58 2001/07/09 04:26:08 yurik
115 * Fixed lack of pthread_self function on BeOS
117 * Revision 1.57 2001/07/04 08:54:23 robertj
118 * Added dump of thread in SEGV signal handler, this one seems to work.
120 * Revision 1.56 2001/07/03 04:41:25 yurik
121 * Corrections to Jac's submission from 6/28
123 * Revision 1.55 2001/06/30 06:59:07 yurik
124 * Jac Goudsmit from Be submit these changes 6/28. Implemented by Yuri Kiryanov
126 * Revision 1.54 2001/05/03 01:13:10 robertj
127 * Closed stdin if in background, should never block in tty I/O if daemon!
129 * Revision 1.53 2001/04/20 05:41:35 craigs
130 * Added ability to set core dump size from command line under Linux
132 * Revision 1.52 2001/04/20 05:08:42 robertj
133 * Removed dump of thread in SEGV signal, it does not work.
135 * Revision 1.51 2001/04/17 03:13:21 robertj
136 * Added dump of thread address in SEGV etc log output.
138 * Revision 1.50 2001/04/05 03:09:29 robertj
139 * Changed so output to PError goes to system log. Useful for asserts.
141 * Revision 1.49 2001/03/29 03:25:03 robertj
142 * Added dumping to log file of SEGV etc if running as daemon.
144 * Revision 1.48 2001/03/28 23:47:26 robertj
145 * Added start log message and version numbers to start and stop log messages
147 * Revision 1.47 2001/03/28 05:36:14 robertj
148 * Added milliseconds to system log time output.
150 * Revision 1.46 2001/03/24 00:49:02 robertj
151 * Added status indication command for services
153 * Revision 1.45 2001/03/23 01:05:32 robertj
154 * Added check that log file is writable after setuid but before fork.
156 * Revision 1.44 2001/03/22 22:48:25 robertj
157 * Fixed errors in usage help text.
159 * Revision 1.43 2001/03/20 06:44:25 robertj
160 * Lots of changes to fix the problems with terminating threads that are I/O
161 * blocked, especially when doing orderly shutdown of service via SIGTERM.
163 * Revision 1.42 2001/03/20 01:04:46 robertj
164 * Fixed some difficulties with terminating a service process from signals or
165 * from simply dropping out of Main().
167 * Revision 1.41 2001/03/19 02:41:13 robertj
168 * Extra trace output on exiting service.
170 * Revision 1.40 2001/03/19 00:20:55 robertj
171 * Added test for if deamon actually stops
173 * Revision 1.39 2001/03/19 00:11:03 robertj
174 * Added information message when killing service.
176 * Revision 1.38 2001/03/14 01:30:35 robertj
177 * Do setgid before so setuid, ie when still root.
179 * Revision 1.37 2001/03/14 01:16:11 robertj
180 * Fixed signals processing, now uses housekeeping thread to handle signals
181 * synchronously. This also fixes issues with stopping PServiceProcess.
183 * Revision 1.36 2001/03/13 03:47:18 robertj
184 * Added ability to set pid file from command line.
186 * Revision 1.35 2001/03/09 06:31:22 robertj
187 * Added ability to set default PConfig file or path to find it.
189 * Revision 1.34 2000/05/02 03:17:13 robertj
190 * Added display of thread name in SystemLog, thanks Ashley Unitt.
192 * Revision 1.33 2000/04/03 18:36:50 robertj
193 * Fix for BeOS support (stupid prototype in system header files).
195 * Revision 1.32 1999/09/14 13:02:53 robertj
196 * Fixed PTRACE to PSYSTEMLOG conversion problem under Unix.
198 * Revision 1.31 1999/08/17 09:29:22 robertj
199 * Added long name versions of parameters.
201 * Revision 1.30 1999/08/12 12:12:47 robertj
202 * GCC 2.95 compatibility.
204 * Revision 1.29 1999/06/23 14:19:46 robertj
205 * Fixed core dump problem with SIGINT/SIGTERM terminating process.
207 * Revision 1.28 1999/05/13 04:44:18 robertj
208 * Added SIGHUP and SIGWINCH handlers to increase and decrease the log levels.
210 * Revision 1.27 1999/03/02 05:41:59 robertj
213 * Revision 1.26 1999/01/11 12:10:32 robertj
214 * Improved operating system version display.
216 * Revision 1.26 1999/01/11 05:20:12 robertj
217 * Added OS to the -v display text.
219 * Revision 1.25 1998/12/21 06:37:14 robertj
220 * Fixed GNu warning on solaris x86
222 * Revision 1.24 1998/12/16 12:41:25 robertj
223 * Fixed bug where .ini file is not written when service run as a daemon.
225 * Revision 1.23 1998/11/30 21:52:00 robertj
226 * New directory structure.
228 * Revision 1.22 1998/11/06 03:44:55 robertj
229 * Fixed bug in argument list parsing, not doing it to member variable.
230 * Added check for daemon already running before starting a new daemon.
232 * Revision 1.21 1998/10/11 02:26:46 craigs
233 * Added thread ID to output messages
235 * Revision 1.20 1998/09/24 04:12:20 robertj
236 * Added open software license.
242 #pragma implementation "svcproc.h"
243 #include <ptlib/svcproc.h>
251 #define LOG_WARNING 4
272 #include <sys/resource.h>
278 #define MAX_LOG_LINE_LEN 1024
281 static int PwlibLogToUnixLog
[PSystemLog::NumLogLevels
] = {
282 LOG_CRIT
, // LogFatal,
283 LOG_ERR
, // LogError,
284 LOG_WARNING
, // LogWarning,
285 LOG_INFO
, // LogInfo,
286 LOG_DEBUG
, // LogDebug
295 static const char * const PLevelName
[PSystemLog::NumLogLevels
+1] = {
309 #ifdef P_MAC_MPTHREADS
310 // alas, this can't be statically initialized
311 // XXX This ought to be an MPCriticalRegionID, but they're broken in
312 // XXX Mac OS X 10.0.x!
313 static MPSemaphoreID logMutex
;
316 static void SetUpLogMutex()
319 MPSemaphoreID tempCrit
;
320 long err
= MPCreateSemaphore(1, 1, &tempCrit
);
322 if (!OTCompareAndSwap32(0, (UInt32
)tempCrit
, (UInt32
*)&logMutex
)) {
324 MPDeleteSemaphore(tempCrit
);
331 static pthread_mutex_t logMutex
= PTHREAD_MUTEX_INITIALIZER
;
335 void PSystemLog::Output(Level level
, const char * cmsg
)
337 PString systemLogFileName
= PServiceProcess::Current().systemLogFileName
;
338 if (systemLogFileName
.IsEmpty()) {
341 logMsg((char *)(const char)cmsg
,0,0,0,0,0,0);
343 syslog(PwlibLogToUnixLog
[level
], "%s", cmsg
);
348 pthread_mutex_lock(&logMutex
);
350 #ifdef P_MAC_MPTHREADS
352 (void)MPWaitOnSemaphore(logMutex
, kDurationForever
);
356 if (systemLogFileName
== "-")
359 out
= new ofstream(systemLogFileName
, ios::app
);
362 *out
<< now
.AsString("yyyy/MM/dd hh:mm:ss.uuu\t");
364 PThread
* thread
= PThread::Current();
365 if (thread
== NULL
) {
366 #ifdef P_MAC_MPTHREADS
367 unsigned tid
= (unsigned)MPCurrentTaskID();
368 #elif defined(P_VXWORKS)
369 unsigned tid
= ::taskIdSelf();
370 #elif defined(BE_THREADS)
371 thread_id tid
= ::find_thread(NULL
);
373 unsigned tid
= (unsigned) pthread_self();
375 *out
<< "ThreadID=0x"
376 << setfill('0') << ::hex
378 << setfill(' ') << ::dec
;
380 PString threadName
= thread
->GetThreadName();
381 if (threadName
.GetLength() <= 23)
382 *out
<< setw(23) << threadName
;
384 *out
<< threadName
.Left(10) << "..." << threadName
.Right(10);
388 << PLevelName
[level
+1]
396 pthread_mutex_unlock(&logMutex
);
398 #ifdef P_MAC_MPTHREADS
399 MPSignalSemaphore(logMutex
);
405 int PSystemLog::Buffer::overflow(int c
)
407 if (pptr() >= epptr()) {
408 int ppos
= pptr() - pbase();
409 char * newptr
= string
.GetPointer(string
.GetSize() + 10);
410 setp(newptr
, newptr
+ string
.GetSize() - 1);
421 int PSystemLog::Buffer::underflow()
427 int PSystemLog::Buffer::sync()
429 PSystemLog::Output(log
->logLevel
, string
);
432 char * base
= string
.GetPointer(10);
433 setp(base
, base
+ string
.GetSize() - 1);
438 PServiceProcess::PServiceProcess(const char * manuf
,
444 : PProcess(manuf
, name
, majorVersion
, minorVersion
, status
, buildNumber
)
446 currentLogLevel
= PSystemLog::Warning
;
447 isTerminating
= FALSE
;
451 PServiceProcess::~PServiceProcess()
453 if (!pidFileToRemove
)
454 PFile::Remove(pidFileToRemove
);
457 // close the system log
458 if (systemLogFileName
.IsEmpty())
464 PServiceProcess
& PServiceProcess::Current()
466 PProcess
& process
= PProcess::Current();
467 PAssert(process
.IsDescendant(PServiceProcess::Class()), "Not a service process!");
468 return (PServiceProcess
&)process
;
473 static int KillProcess(int pid
, int sig
)
475 if (kill(pid
, sig
) != 0)
483 cout
<< " to daemon at pid " << pid
<< ' ' << flush
;
485 for (PINDEX retry
= 1; retry
<= 10; retry
++) {
486 PThread::Sleep(1000);
487 if (kill(pid
, 0) != 0) {
488 cout
<< "\nDaemon stopped." << endl
;
491 cout
<< '.' << flush
;
493 cout
<< "\nDaemon has not stopped." << endl
;
500 void PServiceProcess::_PXShowSystemWarning(PINDEX code
, const PString
& str
)
502 PSYSTEMLOG(Warning
, "PWLib\t" << GetOSClass() << " error #" << code
<< '-' << str
);
506 int PServiceProcess::InitialiseService()
509 PSetErrorStream(new PSystemLog(PSystemLog::StdError
));
510 PTrace::SetStream(new PSystemLog(PSystemLog::Debug3
));
511 PTrace::ClearOptions(PTrace::FileAndLine
);
512 PTrace::SetOptions(PTrace::SystemLogStream
);
516 // parse arguments so we can grab what we want
517 PArgList
& args
= GetArguments();
519 args
.Parse("v-version."
535 // if only displaying version information, do it and finish
536 if (args
.HasOption('v')) {
537 cout
<< "Product Name: " << productName
<< endl
538 << "Manufacturer: " << manufacturer
<< endl
539 << "Version : " << GetVersion(TRUE
) << endl
540 << "System : " << GetOSName() << '-'
541 << GetOSHardware() << ' '
542 << GetOSVersion() << endl
;
547 if (args
.HasOption('p'))
548 pidfilename
= args
.GetOptionString('p');
551 pidfilename
= _PATH_VARRUN
;
554 if (!pidfilename
&& PDirectory::Exists(pidfilename
))
555 pidfilename
= PDirectory(pidfilename
) + PProcess::Current().GetFile().GetFileName() + ".pid";
557 if (args
.HasOption('k') || args
.HasOption('t') || args
.HasOption('s')) {
561 ifstream
pidfile(pidfilename
);
562 if (!pidfile
.is_open()) {
563 cout
<< "Could not open pid file: \"" << pidfilename
<< "\""
564 " - " << strerror(errno
) << endl
;
570 cout
<< "Illegal format pid file \"" << pidfilename
<< '"' << endl
;
575 if (args
.HasOption('s')) {
576 cout
<< "Process at " << pid
<< ' ';
577 if (kill(pid
, 0) == 0)
578 cout
<< "is running.";
579 else if (errno
== ESRCH
)
580 cout
<< "does not exist.";
582 cout
<< " status could not be determined, error: " << strerror(errno
);
587 int sig
= args
.HasOption('t') ? SIGTERM
: SIGKILL
;
588 switch (KillProcess(pid
, sig
)) {
592 PFile::Remove(pidfilename
);
595 if (args
.HasOption('t') && args
.HasOption('k')) {
596 switch (KillProcess(pid
, SIGKILL
)) {
600 PFile::Remove(pidfilename
);
610 cout
<< "Could not stop process " << pid
<<
611 " - " << strerror(errno
) << endl
;
615 // Set the gid we are running under
616 if (args
.HasOption('g')) {
617 PString gidstr
= args
.GetOptionString('g');
618 if (!SetGroupName(gidstr
)) {
619 cout
<< "Could not set GID to \"" << gidstr
<< "\" - " << strerror(errno
) << endl
;
624 // Set the uid we are running under
625 if (args
.HasOption('u')) {
626 PString uidstr
= args
.GetOptionString('u');
627 if (!SetUserName(uidstr
)) {
628 cout
<< "Could not set UID to \"" << uidstr
<< "\" - " << strerror(errno
) << endl
;
633 BOOL helpAndExit
= FALSE
;
635 // if displaying help, then do it
636 if (args
.HasOption('h'))
638 else if (!args
.HasOption('d') && !args
.HasOption('x')) {
639 cout
<< "error: must specify one of -v, -h, -t, -k, -d or -x" << endl
;
643 // set flag for console messages
644 if (args
.HasOption('c')) {
645 systemLogFileName
= '-';
649 if (args
.HasOption('l')) {
650 systemLogFileName
= args
.GetOptionString('l');
651 if (systemLogFileName
.IsEmpty()) {
652 cout
<< "error: must specify file name for -l" << endl
;
655 else if (PDirectory::Exists(systemLogFileName
))
656 systemLogFileName
= PDirectory(systemLogFileName
) + PProcess::Current().GetFile().GetFileName() + ".log";
660 cout
<< "usage: [-c] -v|-d|-h|-x\n"
661 " -h --help output this help message and exit\n"
662 " -v --version display version information and exit\n"
663 #if !defined(BE_THREADS) && !defined(P_RTEMS)
664 " -d --daemon run as a daemon\n"
666 " -u --uid uid set user id to run as\n"
667 " -g --gid gid set group id to run as\n"
668 " -p --pid-file name or directory for pid file\n"
669 " -t --terminate orderly terminate process in pid file\n"
670 " -k --kill preemptively kill process in pid file\n"
671 " -s --status check to see if daemon is running\n"
672 " -c --console output messages to stdout rather than syslog\n"
673 " -l --log-file file output messages to file or directory instead of syslog\n"
674 " -x --execute execute as a normal program\n"
675 " -i --ini-file set the ini file to use, may be explicit file or\n"
676 " a ':' separated set of directories to search.\n"
677 " -H --handlemax n set maximum number of file handles (set before uid/gid)\n"
679 " -C --core-size set the maximum core file size\n"
685 // open the system logger for this program
686 if (systemLogFileName
.IsEmpty())
687 openlog((char *)(const char *)GetName(), LOG_PID
, LOG_DAEMON
);
688 else if (systemLogFileName
== "-")
689 cout
<< "All output for " << GetName() << " is to console." << endl
;
691 ofstream
logfile(systemLogFileName
, ios::app
);
692 if (!logfile
.is_open()) {
693 cout
<< "Could not open log file \"" << systemLogFileName
<< "\""
694 " - " << strerror(errno
) << endl
;
698 PSYSTEMLOG(StdError
, "Starting service process \"" << GetName() << "\" v" << GetVersion(TRUE
));
700 if (args
.HasOption('i'))
701 SetConfigurationPath(args
.GetOptionString('i'));
703 if (args
.HasOption('H')) {
705 seteuid(getuid()); // Switch back to starting uid for next call
706 SetMaxHandles(args
.GetOptionString('H').AsInteger());
710 // set the core file size
711 if (args
.HasOption('C')) {
714 if (getrlimit(RLIMIT_CORE
, &rlim
) != 0)
715 cout
<< "Could not get current core file size : error = " << errno
<< endl
;
718 seteuid(getuid()); // Switch back to starting uid for next call
719 int v
= args
.GetOptionString('C').AsInteger();
721 if (setrlimit(RLIMIT_CORE
, &rlim
) != 0)
722 cout
<< "Could not set current core file size to " << v
<< " : error = " << errno
<< endl
;
724 getrlimit(RLIMIT_CORE
, &rlim
);
725 cout
<< "Core file size set to " << rlim
.rlim_cur
<< "/" << rlim
.rlim_max
<< endl
;
732 #if !defined(BE_THREADS) && !defined(P_RTEMS)
733 if (!args
.HasOption('d'))
736 // Run as a daemon, ie fork
739 ifstream
pidfile(pidfilename
);
740 if (pidfile
.is_open()) {
743 if (pid
!= 0 && kill(pid
, 0) == 0) {
744 cout
<< "Already have daemon running with pid " << pid
<< endl
;
750 // Need to get rid of the config write thread before fork, as on
751 // pthreads platforms the forked process does not have the thread
756 case 0 : // The forked process
760 cout
<< "Fork failed creating daemon process." << endl
;
763 default : // Parent process
764 cout
<< "Daemon started with pid " << pid
<< endl
;
766 // Write out the child pid to magic file in /var/run (at least for linux)
767 ofstream
pidfile(pidfilename
);
768 if (pidfile
.is_open())
771 cout
<< "Could not write pid to file \"" << pidfilename
<< "\""
772 " - " << strerror(errno
) << endl
;
777 // Set ourselves as out own process group so we don't get signals
778 // from our parent's terminal (hopefully!)
783 pidFileToRemove
= pidfilename
;
785 // Only if we are running in the background as a daemon, we intercept
786 // the core dumping signals so get a message in the log file.
787 signal(SIGSEGV
, PXSignalHandler
);
788 signal(SIGFPE
, PXSignalHandler
);
789 signal(SIGBUS
, PXSignalHandler
);
791 // Also if in background, don't want to get blocked on input from stdin
792 ::close(STDIN_FILENO
);
794 #endif // !BE_THREADS && !P_RTEMS
799 int PServiceProcess::_main(void *)
801 if ((terminationValue
= InitialiseService()) < 0) {
802 // Make sure housekeeping thread is going so signals are handled.
805 terminationValue
= 1;
807 terminationValue
= 0;
813 return terminationValue
;
817 BOOL
PServiceProcess::OnPause()
822 void PServiceProcess::OnContinue()
826 void PServiceProcess::OnStop()
831 void PServiceProcess::Terminate()
834 // If we are the process itself and another thread is terminating us,
835 // just stop and wait forever for us to go away
836 if (PThread::Current() == this)
837 Sleep(PMaxTimeInterval
);
838 PSYSTEMLOG(Error
, "Nested call to process termination!");
842 isTerminating
= TRUE
;
844 PSYSTEMLOG(Warning
, "Stopping service process \"" << GetName() << "\" v" << GetVersion(TRUE
));
846 // Avoid strange errors caused by threads (and the process itself!) being destoyed
847 // before they have EVER been scheduled
850 // Do the services stop code
854 // close the system log
855 if (systemLogFileName
.IsEmpty())
859 // Now end the program
860 exit(terminationValue
);
863 void PServiceProcess::PXOnAsyncSignal(int sig
)
867 // Override the default behavious for these signals as that just
868 // summarily exits the program. Allow PXOnSignal() to do orderly exit.
877 sigmsg
= "segmentation fault (SIGSEGV)";
881 sigmsg
= "floating point exception (SIGFPE)";
884 #ifndef __BEOS__ // In BeOS, SIGBUS is the same value as SIGSEGV
886 sigmsg
= "bus error (SIGBUS)";
890 PProcess::PXOnAsyncSignal(sig
);
894 signal(SIGSEGV
, SIG_DFL
);
895 signal(SIGFPE
, SIG_DFL
);
896 signal(SIGBUS
, SIG_DFL
);
898 static BOOL inHandler
= FALSE
;
900 raise(SIGQUIT
); // Dump core
901 _exit(-1); // Fail safe if raise() didn't dump core and exit
906 #ifdef P_MAC_MPTHREADS
907 unsigned tid
= (unsigned)MPCurrentTaskID();
908 #elif defined(P_VXWORKS)
909 unsigned tid
= ::taskIdSelf();
910 #elif defined(BE_THREADS)
911 thread_id tid
= ::find_thread(NULL
);
913 unsigned tid
= (unsigned) pthread_self();
915 PThread
* thread_ptr
= activeThreads
.GetAt(tid
);
918 sprintf(msg
, "\nCaught %s, thread_id=%u", sigmsg
, tid
);
920 if (thread_ptr
!= NULL
) {
921 PString thread_name
= thread_ptr
->GetThreadName();
922 if (thread_name
.IsEmpty())
923 sprintf(&msg
[strlen(msg
)], " obj_ptr=%p", thread_ptr
);
925 strcat(msg
, " name=");
926 strcat(msg
, thread_name
);
930 strcat(msg
, ", aborting.\n");
932 if (systemLogFileName
.IsEmpty()) {
934 logMsg((char *)msg
,0,0,0,0,0,0);
936 syslog(LOG_CRIT
, msg
);
942 int fd
= open(systemLogFileName
, O_WRONLY
|O_APPEND
, FWRITE
|FAPPEND
);
944 int fd
= open(systemLogFileName
, O_WRONLY
|O_APPEND
);
947 write(fd
, msg
, strlen(msg
));
952 raise(SIGQUIT
); // Dump core
953 _exit(-1); // Fail safe if raise() didn't dump core and exit
957 void PServiceProcess::PXOnSignal(int sig
)
974 if (currentLogLevel
< PSystemLog::NumLogLevels
-1) {
975 currentLogLevel
= (PSystemLog::Level
)(currentLogLevel
+1);
976 PSystemLog
s(PSystemLog::StdError
);
977 s
<< "Log level increased to " << PLevelName
[currentLogLevel
+1];
983 if (currentLogLevel
> PSystemLog::Fatal
) {
984 currentLogLevel
= (PSystemLog::Level
)(currentLogLevel
-1);
985 PSystemLog
s(PSystemLog::StdError
);
986 s
<< "Log level decreased to " << PLevelName
[currentLogLevel
+1];