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