]> git.stg.codes - stg.git/blob - projects/rscriptd/main.cpp
Some refactoring.
[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 <cerrno>
40 #include <cstring> // strerror
41 #include <set>
42
43 #include "stg/common.h"
44 #include "stg/logger.h"
45 #include "stg/scriptexecuter.h"
46 #include "stg/conffiles.h"
47 #include "stg/version.h"
48 #include "listener.h"
49 #include "pidfile.h"
50
51 using namespace std;
52
53 #ifdef DEBUG
54 # define MAIN_DEBUG  1
55 # define NO_DAEMON    1
56 #endif
57
58 #define START_FILE "/._ST_ART_ED_"
59
60 set<pid_t> executersPid;
61 volatile time_t stgTime = time(NULL);
62
63 //-----------------------------------------------------------------------------
64 void KillExecuters()
65 {
66 set<pid_t>::iterator pid;
67 pid = executersPid.begin();
68 while (pid != executersPid.end())
69     {
70     printfd(__FILE__, "KillExecuters pid=%d\n", *pid);
71     kill(*pid, SIGUSR1);
72     ++pid;
73     }
74 }
75 //-----------------------------------------------------------------------------
76 #ifdef LINUX
77 int StartScriptExecuter(char * procName, int msgKey, int * msgID)
78 #else
79 int StartScriptExecuter(char *, int msgKey, int * msgID)
80 #endif
81 {
82 STG_LOGGER & WriteServLog = GetStgLogger();
83
84 if (*msgID == -11)   // If msgID == -11 - first call. Create queue
85     {
86     for (int i = 0; i < 2; i++)
87         {
88         *msgID = msgget(msgKey, IPC_CREAT | IPC_EXCL | 0600);
89
90         if (*msgID == -1)
91             {
92             *msgID = msgget(msgKey, 0);
93             if (*msgID == -1)
94                 {
95                 WriteServLog("Message queue not created.");
96                 return -1;
97                 }
98             else
99                 {
100                 msgctl(*msgID, IPC_RMID, NULL);
101                 }
102             }
103         else
104             {
105             WriteServLog("Message queue created successfully. msgKey=%d msgID=%d", msgKey, *msgID);
106             break;
107             }
108         }
109     }
110
111 pid_t executerPid = fork();
112
113 switch (executerPid)
114     {
115     case -1:    // Failure
116         WriteServLog("Fork error!");
117         return -1;
118
119     case 0:     // Child
120         //close(0);
121         //close(1);
122         //close(2);
123         //setsid();
124 #ifdef LINUX
125         Executer(*msgID, executerPid, procName);
126 #else
127         Executer(*msgID, executerPid);
128 #endif
129         return 1;
130
131     default:    // Parent
132         if (executersPid.empty())
133 #ifdef LINUX
134             Executer(*msgID, executerPid, NULL);
135 #else
136             Executer(*msgID, executerPid);
137 #endif
138         executersPid.insert(executerPid);
139     }
140 return 0;
141 }
142 //-----------------------------------------------------------------------------
143 void StopScriptExecuter(int msgID)
144 {
145 STG_LOGGER & WriteServLog = GetStgLogger();
146
147 for (int i = 0; i < 5; ++i)
148     {
149     struct msqid_ds data;
150     if (msgctl(msgID, IPC_STAT, &data))
151         {
152         int e = errno;
153         printfd(__FILE__, "StopScriptExecuter() - msgctl for IPC_STAT failed: '%s'\n", strerror(e));
154         WriteServLog( "Failed to check queue emptiness: '%s'", strerror(e));
155         break;
156         }
157
158     WriteServLog("Messages in queue: %d", data.msg_qnum);
159
160     if (data.msg_qnum == 0)
161         break;
162
163     struct timespec ts = {1, 0};
164     nanosleep(&ts, NULL);
165     }
166
167 if (msgctl(msgID, IPC_RMID, NULL))
168     {
169     int e = errno;
170     printfd(__FILE__, "StopScriptExecuter() - msgctl for IPC_STAT failed: '%s'\n", strerror(e));
171     WriteServLog("Failed to remove queue: '%s'", strerror(e));
172     }
173 else
174     {
175     WriteServLog("Queue removed successfully.");
176     }
177
178 KillExecuters();
179 }
180 //-----------------------------------------------------------------------------
181 #ifdef NO_DAEMON
182 int ForkAndWait(const string &)
183 #else
184 int ForkAndWait(const string & confDir)
185 #endif
186 {
187 #ifndef NO_DAEMON
188 pid_t childPid = fork();
189
190 switch (childPid)
191     {
192     case -1:    // Failure
193         return -1;
194         break;
195
196     case 0:     // Child
197         //close(0);
198         close(1);
199         close(2);
200         setsid();
201         break;
202
203     default:    // Parent
204         exit(1);
205         break;
206     }
207 #endif
208 return 0;
209 }
210 //-----------------------------------------------------------------------------
211 int main(int argc, char * argv[])
212 {
213 CONFIGFILE * cfg = NULL;
214 LISTENER * listener = NULL;
215 int msgID = -11;
216 int execNum = 0;
217 int execMsgKey = 0;
218
219 string logFileName;
220 string confDir;
221 string password;
222 string onConnect;
223 string onDisconnect;
224 int port;
225 int userTimeout;
226
227 if (getuid())
228     {
229     printf("You must be root. Exit.\n");
230     exit(1);
231     }
232
233 if (argc == 2)
234     cfg = new CONFIGFILE(argv[1]);
235 else
236     cfg = new CONFIGFILE("/etc/rscriptd/rscriptd.conf");
237
238 if (cfg->Error())
239     {
240     STG_LOGGER & WriteServLog = GetStgLogger();
241     WriteServLog.SetLogFileName("/var/log/rscriptd.log");
242     WriteServLog("Error reading config file!");
243     delete cfg;
244     return EXIT_FAILURE;
245     }
246
247 cfg->ReadString("LogFileName", &logFileName, "/var/log/rscriptd.log");
248 cfg->ReadInt("ExecutersNum", &execNum, 1);
249 cfg->ReadInt("ExecMsgKey", &execMsgKey, 5555);
250 cfg->ReadString("ConfigDir", &confDir, "/etc/rscriptd");
251 cfg->ReadString("Password", &password, "");
252 cfg->ReadInt("Port", &port, 5555);
253 cfg->ReadInt("UserTimeout", &userTimeout, 60);
254 cfg->ReadString("ScriptOnConnect", &onConnect, "/etc/rscriptd/OnConnect");
255 cfg->ReadString("ScriptOnDisconnect", &onDisconnect, "/etc/rscriptd/OnDisconnect");
256
257 if (ForkAndWait(confDir) < 0)
258     {
259     STG_LOGGER & WriteServLog = GetStgLogger();
260     WriteServLog("Fork error!");
261     delete cfg;
262     return EXIT_FAILURE;
263     }
264
265 STG_LOGGER & WriteServLog = GetStgLogger();
266 PIDFile pidFile("/var/run/rscriptd.pid");
267 WriteServLog.SetLogFileName(logFileName);
268 WriteServLog("rscriptd v. %s", SERVER_VERSION);
269
270 for (int i = 0; i < execNum; i++)
271     {
272     int ret = StartScriptExecuter(argv[0], execMsgKey, &msgID);
273     if (ret < 0)
274         {
275         STG_LOGGER & WriteServLog = GetStgLogger();
276         WriteServLog("Start Script Executer error!");
277         delete cfg;
278         return EXIT_FAILURE;
279         }
280     if (ret == 1)
281         {
282         delete cfg;
283         return EXIT_SUCCESS;
284         }
285     }
286
287 listener = new LISTENER();
288 listener->SetPort(port);
289 listener->SetPassword(password);
290 listener->SetUserTimeout(userTimeout);
291 listener->SetScriptOnConnect(onConnect);
292 listener->SetScriptOnDisconnect(onDisconnect);
293
294 listener->Start();
295
296 WriteServLog("rscriptd started successfully.");
297 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
298
299 sigset_t signalSet;
300 sigfillset(&signalSet);
301 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
302
303 while (true)
304     {
305     sigfillset(&signalSet);
306     int sig = 0;
307     printfd(__FILE__, "Before sigwait\n");
308     sigwait(&signalSet, &sig);
309     printfd(__FILE__, "After sigwait. Signal: %d\n", sig);
310     bool stop = false;
311     switch (sig)
312         {
313         case SIGTERM:
314             stop = true;
315             break;
316         case SIGINT:
317             stop = true;
318             break;
319         default:
320             WriteServLog("Ignore signel %d", sig);
321             break;
322         }
323     if (stop)
324         break;
325     }
326
327 listener->Stop();
328
329 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
330
331 StopScriptExecuter(msgID);
332
333 WriteServLog("rscriptd stopped successfully.");
334 WriteServLog("---------------------------------------------");
335
336 delete listener;
337 delete cfg;
338 return EXIT_SUCCESS;
339 }
340 //-----------------------------------------------------------------------------