]> git.stg.codes - stg.git/blob - projects/rscriptd/main.cpp
Fix build on Darwin.
[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 auto & WriteServLog = STG::Logger::get();
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 auto & WriteServLog = STG::Logger::get();
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 int ForkAndWait()
180 {
181 #ifndef NO_DAEMON
182 pid_t childPid = fork();
183
184 switch (childPid)
185     {
186     case -1:    // Failure
187         return -1;
188         break;
189
190     case 0:     // Child
191         //close(0);
192         close(1);
193         close(2);
194         setsid();
195         break;
196
197     default:    // Parent
198         exit(1);
199         break;
200     }
201 #endif
202 return 0;
203 }
204 //-----------------------------------------------------------------------------
205 int main(int argc, char * argv[])
206 {
207 CONFIGFILE * cfg = NULL;
208 LISTENER * listener = NULL;
209 int msgID = -11;
210 int execNum = 0;
211 int execMsgKey = 0;
212
213 std::string logFileName;
214 std::string confDir;
215 std::string password;
216 std::string onConnect;
217 std::string onDisconnect;
218 int port;
219 int userTimeout;
220
221 if (getuid())
222     {
223     printf("You must be root. Exit.\n");
224     exit(1);
225     }
226
227 if (argc == 2)
228     cfg = new CONFIGFILE(argv[1]);
229 else
230     cfg = new CONFIGFILE("/etc/rscriptd/rscriptd.conf");
231
232 if (cfg->Error())
233     {
234     auto & WriteServLog = STG::Logger::get();
235     WriteServLog.setFileName("/var/log/rscriptd.log");
236     WriteServLog("Error reading config file!");
237     delete cfg;
238     return EXIT_FAILURE;
239     }
240
241 cfg->ReadString("LogFileName", &logFileName, "/var/log/rscriptd.log");
242 cfg->ReadInt("ExecutersNum", &execNum, 1);
243 cfg->ReadInt("ExecMsgKey", &execMsgKey, 5555);
244 cfg->ReadString("ConfigDir", &confDir, "/etc/rscriptd");
245 cfg->ReadString("Password", &password, "");
246 cfg->ReadInt("Port", &port, 5555);
247 cfg->ReadInt("UserTimeout", &userTimeout, 60);
248 cfg->ReadString("ScriptOnConnect", &onConnect, "/etc/rscriptd/OnConnect");
249 cfg->ReadString("ScriptOnDisconnect", &onDisconnect, "/etc/rscriptd/OnDisconnect");
250
251 if (ForkAndWait() < 0)
252     {
253     auto & WriteServLog = STG::Logger::get();
254     WriteServLog("Fork error!");
255     delete cfg;
256     return EXIT_FAILURE;
257     }
258
259 auto & WriteServLog = STG::Logger::get();
260 PIDFile pidFile("/var/run/rscriptd.pid");
261 WriteServLog.setFileName(logFileName);
262 WriteServLog("rscriptd v. %s", SERVER_VERSION);
263
264 for (int i = 0; i < execNum; i++)
265     {
266     int ret = StartScriptExecuter(argv[0], execMsgKey, &msgID);
267     if (ret < 0)
268         {
269         STG::Logger::get()("Start Script Executer error!");
270         delete cfg;
271         return EXIT_FAILURE;
272         }
273     if (ret == 1)
274         {
275         delete cfg;
276         return EXIT_SUCCESS;
277         }
278     }
279
280 listener = new LISTENER();
281 listener->SetPort(port);
282 listener->SetPassword(password);
283 listener->SetUserTimeout(userTimeout);
284 listener->SetScriptOnConnect(onConnect);
285 listener->SetScriptOnDisconnect(onDisconnect);
286
287 listener->Start();
288
289 WriteServLog("rscriptd started successfully.");
290 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
291
292 sigset_t signalSet;
293 sigfillset(&signalSet);
294 pthread_sigmask(SIG_BLOCK, &signalSet, NULL);
295
296 while (true)
297     {
298     sigfillset(&signalSet);
299     int sig = 0;
300     printfd(__FILE__, "Before sigwait\n");
301     sigwait(&signalSet, &sig);
302     printfd(__FILE__, "After sigwait. Signal: %d\n", sig);
303     bool stop = false;
304     switch (sig)
305         {
306         case SIGTERM:
307             stop = true;
308             break;
309         case SIGINT:
310             stop = true;
311             break;
312         default:
313             WriteServLog("Ignore signel %d", sig);
314             break;
315         }
316     if (stop)
317         break;
318     }
319
320 listener->Stop();
321
322 WriteServLog("+++++++++++++++++++++++++++++++++++++++++++++");
323
324 StopScriptExecuter(msgID);
325
326 WriteServLog("rscriptd stopped successfully.");
327 WriteServLog("---------------------------------------------");
328
329 delete listener;
330 delete cfg;
331 return EXIT_SUCCESS;
332 }
333 //-----------------------------------------------------------------------------