00001 /* 00002 * Daemon.cc 00003 * 00004 * Smalltalk like class library for C++ 00005 * Abstract daemon application. 00006 * 00007 * Copyright (c) 2004 Milan Cermak 00008 */ 00009 /* 00010 * This library is free software; you can redistribute it and/or 00011 * modify it under the terms of the GNU Lesser General Public 00012 * License as published by the Free Software Foundation; either 00013 * version 2.1 of the License, or (at your option) any later version. 00014 * 00015 * This library is distributed in the hope that it will be useful, 00016 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00017 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 00018 * Lesser General Public License for more details. 00019 * 00020 * You should have received a copy of the GNU Lesser General Public 00021 * License along with this library; if not, write to the Free Software 00022 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 00023 */ 00024 #include <stdio.h> 00025 #include <pwd.h> 00026 #include <sys/types.h> 00027 #include <unistd.h> 00028 #include <signal.h> 00029 00030 #include <stlib/tools/Daemon.h> 00031 #include <stlib/tools/Filename.h> 00032 #include <stlib/tools/FileEncodedStreamFactory.h> 00033 00034 #include <stlib/EncodedStream.h> 00035 #include <stlib/Number.h> 00036 #include <stlib/String.h> 00037 #include <stlib/FileOpenFailed.h> 00038 00039 using namespace Tools; 00040 00041 Daemon::Daemon(void) 00042 { 00043 close_std_streams = false; 00044 change_current_directory = false; 00045 pid_path = new String("/var/run"); 00046 } 00047 00048 /* Accessing protocol */ 00049 String *Daemon::processIdPath(void) 00050 { 00051 return pid_path; 00052 } 00053 00054 void Daemon::processIdPath(String *path) 00055 { 00056 pid_path = path; 00057 } 00058 00059 void Daemon::redirectStreamsToNull(void) 00060 { 00061 close_std_streams = true; 00062 } 00063 00064 void Daemon::changeRootDirectory(void) 00065 { 00066 change_current_directory = true; 00067 } 00068 00069 void Daemon::runUnderUser(int uid) 00070 { 00071 if (uid > 0) setuid(uid); 00072 } 00073 00074 void Daemon::runUnderUserNamed(String *name) 00075 { 00076 struct passwd *pass; 00077 pass = getpwnam(name->asCString()); 00078 runUnderUser(pass->pw_uid); 00079 } 00080 00081 /* Signaling protocol */ 00082 void Daemon::hookupSignal(int signo) 00083 { 00084 signal(signo, globalSignalHandler); 00085 } 00086 00087 void Daemon::hookupInterruptSignal(void) 00088 { 00089 hookupSignal(SIGINT); 00090 } 00091 00092 void Daemon::hookupTerminateSignal(void) 00093 { 00094 hookupSignal(SIGTERM); 00095 } 00096 00097 /* Processing protocol */ 00098 void Daemon::run(void) 00099 { 00100 /* Is server already running */ 00101 if (loadProcessId()) { 00102 cerr->nextPutAll("One server is already running.\n"); 00103 return; 00104 } 00105 if (daemon(change_current_directory ? 0 : 1, 00106 close_std_streams ? 0 : 1) < 0) { 00107 cerr->nextPutAll("Cannot start daemon process.\n"); 00108 return; 00109 } 00110 saveProcessId(); 00111 Application::run(); 00112 /* Delete PID file */ 00113 processIdFilename()->erase(); 00114 } 00115 00116 /* Private protocol */ 00117 Filename *Daemon::processIdFilename(void) 00118 { 00119 return (new Filename(pid_path))->construct(name()->concatenateWith(".pid")); 00120 } 00121 00122 int Daemon::loadProcessId(void) 00123 { 00124 Stream *pidfile; 00125 int pid; 00126 00127 try { 00128 pidfile = processIdFilename()->withEncoding("default")->readStream(); 00129 pid = dynamic_cast<String *>(pidfile->nextLine())->asNumber()->asLong(); 00130 pidfile->close(); 00131 return(pid); 00132 } 00133 catch (FileOpenFailed *ex) { 00134 return 0; 00135 } 00136 } 00137 00138 void Daemon::saveProcessId(void) 00139 { 00140 Stream *pidfile; 00141 00142 pidfile = processIdFilename()->withEncoding("default")->writeStream(); 00143 pidfile->print((long int) getpid()); 00144 pidfile->lf(); 00145 pidfile->close(); 00146 } 00147 00148 void Daemon::globalSignalHandler(int signo) 00149 { 00150 dynamic_cast<Daemon *>(Application::current())->signalHandler(signo); 00151 }