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