]> git.stg.codes - stg.git/blob - projects/rscriptd/main.cpp
Remove wait after fork in rscriptd
[stg.git] / projects / rscriptd / main.cpp
1 /*
2  *    This program is free software; you can redistribute it and/or modify
3  *    it under the terms of the GNU General Public License as published by
4  *    the Free Software Foundation; either version 2 of the License, or
5  *    (at your option) any later version.
6  *
7  *    This program is distributed in the hope that it will be useful,
8  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
9  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  *    GNU General Public License for more details.
11  *
12  *    You should have received a copy of the GNU General Public License
13  *    along with this program; if not, write to the Free Software
14  *    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
15  */
16
17 /*
18  *    Author : Boris Mikhailenko <stg34@stargazer.dp.ua>
19  *    Author : Maxim Mamontov <faust@stargazer.dp.ua>
20  */
21
22  /*
23  $Revision: 1.19 $
24  $Author: faust $
25  $Date: 2010/09/10 06:37:45 $
26  */
27
28 #include <sys/types.h>
29 #include <sys/ipc.h>
30 #include <sys/msg.h>
31 #include <sys/stat.h>
32 #include <sys/wait.h>
33 #include <fcntl.h> // creat
34 #include <unistd.h>
35
36 #include <cstdlib>
37 #include <cstdio>
38 #include <csignal>
39 #include <set>
40
41 #include "stg/common.h"
42 #include "stg/logger.h"
43 #include "stg/scriptexecuter.h"
44 #include "stg/conffiles.h"
45 #include "stg/version.h"
46 #include "listener.h"
47 #include "pidfile.h"
48
49 using namespace std;
50
51 #ifdef DEBUG
52 # define MAIN_DEBUG  1
53 # define NO_DAEMON    1
54 #endif
55
56 #define START_FILE "/._ST_ART_ED_"
57
58 static bool childExited = false;
59 set<pid_t> executersPid;
60 static pid_t stgChildPid;
61 volatile time_t stgTime = time(NULL);
62
63 class STG_STOPPER
64 {
65 public:
66     STG_STOPPER() { nonstop = true; }
67     bool GetStatus() const { return nonstop; };
68     void Stop(const char * __file__, int __line__)
69         {
70         #ifdef NO_DAEMON
71         printfd(__FILE__, "rscriptd stopped at %s:%d\n", __file__, __line__);
72         #endif
73         nonstop = false;
74         }
75 private:
76     bool nonstop;
77 };
78 //-----------------------------------------------------------------------------
79 STG_STOPPER nonstop;
80 //-----------------------------------------------------------------------------
81 void CatchPROF(int)
82 {
83 }
84 //-----------------------------------------------------------------------------
85 void CatchUSR1(int)
86 {
87 }
88 //-----------------------------------------------------------------------------
89 void CatchTERM(int sig)
90 {
91 /*
92  *Function Name:CatchINT
93  *Parameters: sig_num - signal number
94  *Description: INT signal handler
95  *Returns: Nothing
96  */
97 STG_LOGGER & WriteServLog = GetStgLogger();
98 WriteServLog("Shutting down... %d", sig);
99
100 nonstop.Stop(__FILE__, __LINE__);
101
102 struct sigaction newsa, oldsa;
103 sigset_t sigmask;
104
105 sigemptyset(&sigmask);
106 sigaddset(&sigmask, SIGTERM);
107 newsa.sa_handler = SIG_IGN;
108 newsa.sa_mask = sigmask;
109 newsa.sa_flags = 0;
110 sigaction(SIGTERM, &newsa, &oldsa);
111
112 sigemptyset(&sigmask);
113 sigaddset(&sigmask, SIGINT);
114 newsa.sa_handler = SIG_IGN;
115 newsa.sa_mask = sigmask;
116 newsa.sa_flags = 0;
117 sigaction(SIGINT, &newsa, &oldsa);
118 }
119 //-----------------------------------------------------------------------------
120 void CatchPIPE(int)
121 {
122 STG_LOGGER & WriteServLog = GetStgLogger();
123 WriteServLog("Broken pipe!");
124 }
125 //-----------------------------------------------------------------------------
126 void CatchHUP(int)
127 {
128 }
129 //-----------------------------------------------------------------------------
130 void CatchCHLD(int)
131 {
132 int status;
133 pid_t childPid;
134 childPid = waitpid(-1, &status, WNOHANG);
135
136 set<pid_t>::iterator pid;
137 pid = executersPid.find(childPid);
138 if (pid != executersPid.end())
139     {
140     executersPid.erase(pid);
141     }
142 if (childPid == stgChildPid)
143     {
144     childExited = true;
145     }
146 }
147 //-----------------------------------------------------------------------------
148 void SetSignalHandlers()
149 {
150 struct sigaction newsa, oldsa;
151 sigset_t sigmask;
152
153 sigemptyset(&sigmask);
154 sigaddset(&sigmask, SIGTERM);
155 newsa.sa_handler = CatchTERM;
156 newsa.sa_mask = sigmask;
157 newsa.sa_flags = 0;
158 sigaction(SIGTERM, &newsa, &oldsa);
159
160 sigemptyset(&sigmask);
161 sigaddset(&sigmask, SIGUSR1);
162 newsa.sa_handler = CatchUSR1;
163 newsa.sa_mask = sigmask;
164 newsa.sa_flags = 0;
165 sigaction(SIGUSR1, &newsa, &oldsa);
166
167 sigemptyset(&sigmask);
168 sigaddset(&sigmask, SIGINT);
169 newsa.sa_handler = CatchTERM;
170 newsa.sa_mask = sigmask;
171 newsa.sa_flags = 0;
172 sigaction(SIGINT, &newsa, &oldsa);
173
174 sigemptyset(&sigmask);
175 sigaddset(&sigmask, SIGPIPE);
176 newsa.sa_handler = CatchPIPE;
177 newsa.sa_mask = sigmask;
178 newsa.sa_flags = 0;
179 sigaction(SIGPIPE, &newsa, &oldsa);
180
181 sigemptyset(&sigmask);
182 sigaddset(&sigmask, SIGHUP);
183 newsa.sa_handler = CatchHUP;
184 newsa.sa_mask = sigmask;
185 newsa.sa_flags = 0;
186 sigaction(SIGHUP, &newsa, &oldsa);
187
188 sigemptyset(&sigmask);
189 sigaddset(&sigmask, SIGCHLD);
190 newsa.sa_handler = CatchCHLD;
191 newsa.sa_mask = sigmask;
192 newsa.sa_flags = 0;
193 sigaction(SIGCHLD, &newsa, &oldsa);
194 }
195 //-----------------------------------------------------------------------------
196 int StartScriptExecuter(char * procName, int msgKey, int * msgID)
197 {
198 STG_LOGGER & WriteServLog = GetStgLogger();
199
200 if (*msgID == -11)   // If msgID == -11 - first call. Create queue
201     {
202     for (int i = 0; i < 2; i++)
203         {
204         *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
205
206         if (*msgID == -1)
207             {
208             *msgID = msgget(msgKey, 0);
209             if (*msgID == -1)
210                 {
211                 WriteServLog("Message queue not created.");
212                 return -1;
213                 }
214             else
215                 {
216                 msgctl(*msgID, IPC_RMID, NULL);
217                 }
218             }
219         else
220             {
221             WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
222             break;
223             }
224         }
225     }
226
227 pid_t executerPid = fork();
228
229 switch (executerPid)
230     {
231     case -1:    // Failure
232         WriteServLog("Fork error!");
233         return -1;
234
235     case 0:     // Child
236         //close(0);
237         //close(1);
238         //close(2);
239         //setsid();
240         Executer(msgKey, *msgID, executerPid, procName);
241         return 1;
242
243     default:    // Parent
244         if (executersPid.empty())
245             Executer(msgKey, *msgID, executerPid, NULL);
246         executersPid.insert(executerPid);
247     }
248 return 0;
249 }
250 //-----------------------------------------------------------------------------
251 #ifdef NO_DAEMON
252 int ForkAndWait(const string &)
253 #else
254 int ForkAndWait(const string & confDir)
255 #endif
256 {
257 #ifndef NO_DAEMON
258 stgChildPid = fork();
259
260 switch (stgChildPid)
261     {
262     case -1:    // Failure
263         return -1;
264         break;
265
266     case 0:     // Child
267         //close(0);
268         close(1);
269         close(2);
270         setsid();
271         break;
272
273     default:    // Parent
274         exit(1);
275         break;
276     }
277 #endif
278 return 0;
279 }
280 //-----------------------------------------------------------------------------
281 void KillExecuters()
282 {
283 set<pid_t>::iterator pid;
284 pid = executersPid.begin();
285 while (pid != executersPid.end())
286     {
287     printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
288     kill(*pid, SIGUSR1);
289     ++pid;
290     }
291 }
292 //-----------------------------------------------------------------------------
293 int main(int argc, char * argv[])
294 {
295
296 /*
297   Initialization order:
298   - Logger
299   - Config
300   - Set signal nandlers
301   - Fork and exit
302  */
303
304 CONFIGFILE * cfg = NULL;
305 LISTENER * listener = NULL;
306 int msgID = -11;
307 int execNum = 0;
308 int execMsgKey = 0;
309
310 string logFileName;
311 string confDir;
312 string password;
313 string onConnect;
314 string onDisconnect;
315 int port;
316 int userTimeout;
317
318 if (getuid())
319     {
320     printf("You must be root. Exit.\n");
321     exit(1);
322     }
323
324 if (argc == 2)
325     cfg = new CONFIGFILE(argv[1]);
326 else
327     cfg = new CONFIGFILE("/etc/rscriptd/rscriptd.conf");
328
329 if (cfg->Error())
330     {
331     STG_LOGGER & WriteServLog = GetStgLogger();
332     WriteServLog.SetLogFileName("/var/log/rscriptd.log");
333     WriteServLog("Error reading config file!");
334     delete cfg;
335     return EXIT_FAILURE;
336     }
337
338 cfg->ReadString("LogFileName", &logFileName, "/var/log/rscriptd.log");
339 cfg->ReadInt("ExecutersNum", &execNum, 1);
340 cfg->ReadInt("ExecMsgKey", &execMsgKey, 5555);
341 cfg->ReadString("ConfigDir", &confDir, "/etc/rscriptd");
342 cfg->ReadString("Password", &password, "");
343 cfg->ReadInt("Port", &port, 5555);
344 cfg->ReadInt("UserTimeout", &userTimeout, 60);
345 cfg->ReadString("ScriptOnConnect", &onConnect, "/etc/rscriptd/OnConnect");
346 cfg->ReadString("ScriptOnDisconnect", &onDisconnect, "/etc/rscriptd/OnDisconnect");
347
348 SetSignalHandlers();
349 if (ForkAndWait(confDir) < 0)
350     {
351     STG_LOGGER & WriteServLog = GetStgLogger();
352     WriteServLog("Fork error!");
353     delete cfg;
354     return EXIT_FAILURE;
355     }
356
357 STG_LOGGER & WriteServLog = GetStgLogger();
358 PIDFile pidFile("/var/run/rscriptd.pid");
359 WriteServLog.SetLogFileName(logFileName);
360 WriteServLog("rscriptd v. %s", SERVER_VERSION);
361
362 for (int i = 0; i < execNum; i++)
363     {
364     int ret = StartScriptExecuter(argv[0], execMsgKey, &msgID);
365     if (ret < 0)
366         {
367         STG_LOGGER & WriteServLog = GetStgLogger();
368         WriteServLog("Start Script Executer error!");
369         delete cfg;
370         return EXIT_FAILURE;
371         }
372     if (ret == 1)
373         {
374         delete cfg;
375         return EXIT_SUCCESS;
376         }
377     }
378
379 listener = new LISTENER();
380 listener->SetPort(port);
381 listener->SetPassword(password);
382 listener->SetUserTimeout(userTimeout);
383 listener->SetScriptOnConnect(onConnect);
384 listener->SetScriptOnDisconnect(onDisconnect);
385
386 listener->Start();
387
388 WriteServLog("rscriptd started successfully.");
389 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
390
391 while (nonstop.GetStatus())
392     {
393     usleep(100000);
394     }
395
396 listener->Stop();
397
398 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
399
400 int res = msgctl(msgID, IPC_RMID, NULL);
401 if (res)
402     WriteServLog("Queue was not removed. id=%d", msgID);
403 else
404     WriteServLog("Queue removed successfully.");
405
406 KillExecuters();
407
408 WriteServLog("rscriptd stopped successfully.");
409 WriteServLog("---------------------------------------------");
410
411 delete listener;
412 delete cfg;
413 return EXIT_SUCCESS;
414 }
415 //-----------------------------------------------------------------------------