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