]> git.vomp.tv Git - vompclient.git/blob - main.cc
Log conversion
[vompclient.git] / main.cc
1 /*
2     Copyright 2004-2021 Chris Tallon
3
4     This file is part of VOMP.
5
6     VOMP is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     VOMP is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with VOMP.  If not, see <https://www.gnu.org/licenses/>.
18 */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <signal.h>
24
25 // For open
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29
30 #include <thread>
31 #include <string>
32
33 #ifndef WIN32
34   #include <unistd.h>
35   #include <endian.h>
36 #endif
37
38 #include "defines.h"
39
40 #ifdef HANDLE_VT_SWITCHING
41   #include <sys/ioctl.h>
42   #include <linux/vt.h>
43 #endif
44
45 #include "config.h"
46 #include "log.h"
47 #include "oldlog.h"
48 #include "util.h"
49 #include "control.h"
50
51 #ifdef VOMP_PLATTFORM_NMT
52   #include "lednmt.h"
53   #include "osddirectfb.h"
54   #include "audionmt.h"
55   #include "videonmt.h"
56 #endif
57
58
59 #ifndef WIN32 // FIXME do we need any if WIN32 stuff in here? windows has own winmain file
60 void threadSignalReceiverFunction();
61 #endif
62
63 [[ noreturn ]] void shutdown(int code);
64 const std::string& getCommandLineServer();  // NCONFIG
65
66 Config* config;
67 Log* logger;
68 LogNT* loggerNT;
69 Control* control;
70
71 // Temporary, will move to Config system NCONFIG
72 std::string argvServer;
73
74 #ifdef HANDLE_VT_SWITCHING
75 int fdtty;
76 struct vt_mode old_vtmode;
77 #endif
78
79 static const char* TAG = "Main";
80
81 // Linux main function and sighandler
82 #ifndef WIN32
83 int main(int argc, char** argv)
84 {
85   bool daemonize = true;
86   bool debugEnabled = false;
87   bool crashed = false;
88
89
90   config = new Config();
91   if (!config->loadFile())
92   {
93     printf("Parse error in config.json\n");
94     shutdown(1);
95   }
96
97
98   int c;
99   while ((c = getopt(argc, argv, "cdns:")) != -1)
100   {
101     switch (c)
102     {
103       case 'c':
104         crashed = true;
105         break;
106       case 'd':
107         debugEnabled = true; // and...
108         [[fallthrough]];
109       case 'n':
110         daemonize = false;
111         break;
112       case 's':
113         argvServer = optarg;
114         break;
115       case '?':
116         printf("Unknown option\n");
117         return 1;
118       default:
119         printf("Option error\n");
120         return 1;
121     }
122   }
123
124   // Start Log --------------------------------------------------------------------------------------------------
125   logger = new Log();
126   if (!logger)
127   {
128     printf("Failed to create Log object\n");
129     shutdown(1);
130   }
131
132   if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0)) // NCONFIG x2
133   {
134     printf("Could not initialise log object. Aborting.\n");
135     shutdown(1);
136   }
137
138   logger->log("Main", Log::INFO, "Old log starting up...");
139
140
141
142   loggerNT = new LogNT();
143   if (!loggerNT)
144   {
145     printf("Failed to create LogNT object\n");
146     shutdown(1);
147   }
148
149   std::string logFileName("stdout");
150   config->getString("log", "filename", logFileName);
151   if (!loggerNT->init(logFileName, debugEnabled ? 1 : 0)) // NCONFIG x2
152   {
153     printf("Could not initialise log object. Aborting.\n");
154     shutdown(1);
155   }
156
157   //logger->log("Main", Log::INFO, "Starting up...");
158   loggerNT->info(TAG, "Starting up...");
159
160   // Daemonize --------------------------------------------------------------------------------------------------
161
162   if (daemonize) // NCONFIG
163   {
164     // Fork away
165     pid_t forkTest = fork();
166     if (forkTest == -1)
167     { printf("Cannot fork (1).\n"); exit(1); }
168     if (forkTest != 0) _exit(0); // PID returned, I am the parent
169     // otherwise, I am the child
170     setsid();
171     forkTest = fork();
172     if (forkTest == -1)
173     { printf("Cannot fork (2).\n"); exit(1); }
174     if (forkTest != 0) _exit(0); // PID returned, I am the parent
175     // otherwise, I am the child
176     close(0);
177     close(1);
178     close(2);
179   }
180
181   // Set up signal handling ------------------------------------------------------------------------------------------
182
183   // Block all signals
184   sigset_t set;
185   sigfillset(&set);
186   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
187   if (sigBlockResult)
188   {
189     //logger->log("Main", Log::EMERG, "Could not block signals: %i", sigBlockResult);
190     loggerNT->crit(TAG, "Could not block signals: {}", sigBlockResult);
191     shutdown(1);
192   }
193
194   // Start signal receiver thread
195   std::thread threadSignalReceiver(threadSignalReceiverFunction);
196   threadSignalReceiver.detach();
197
198   loggerNT->info(TAG, "Signal handlers set up successfully");
199
200   // VT Switching -----------------------------------------------------------------------------------------------
201
202 #ifdef HANDLE_VT_SWITCHING
203   if (
204
205
206     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
207
208
209   )
210   {
211     loggerNT->warn(TAG, "Could not open /dev/tty. Please change permissions");
212   }
213   else
214   {
215     int free_vt;
216     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
217     {
218       loggerNT->crit(TAG, "Could not retrieve free virtual console, please change permissions");
219     }
220     else
221     {
222       ioctl(fdtty, VT_ACTIVATE, free_vt);
223       ioctl(fdtty, VT_WAITACTIVE, free_vt);
224       ioctl(fdtty, VT_LOCKSWITCH, 1);
225     }
226   }
227 #endif
228
229   // Test area ------------------------------------------------------------------------------------------------------
230
231   //shutdown(0);
232
233   // Run control ----------------------------------------------------------------------------------------------------
234
235   control = new Control();
236   if (!control)
237   {
238     loggerNT->crit(TAG, "Control module failed to create");
239     shutdown(1);
240   }
241
242   if (!control->init(crashed))
243   {
244     loggerNT->crit(TAG, "Control module failed to initialise");
245     delete control;
246     control = NULL;
247     shutdown(1);
248   }
249
250   control->run();
251   control->shutdown();
252
253   shutdown(0);
254 }
255
256 // -------------------------------------------------------------------------------------------------------------------
257
258 void threadSignalReceiverFunction()
259 {
260   int sig;
261   sigset_t set;
262   sigfillset(&set);
263   while(1)
264   {
265     if(sigwait(&set, &sig))
266     {
267       loggerNT->crit(TAG, "Sigwait returned fail - signal handler exiting");
268       return;
269     }
270
271     loggerNT->info(TAG, "Signal received: {}", sig);
272
273     if ((sig == SIGINT) || (sig == SIGTERM)) control->stop();
274   }
275 }
276
277 #endif
278
279 // -------------------------------------------------------------------------------------------------------------------
280
281 [[ noreturn ]] void shutdown(int code)
282 {
283   // FIXME, send a del all to boxstack first, then get rid of it after control?
284   if (control) // shut down control here in case views have posted messages
285   {
286     delete control;
287     control = NULL;
288     loggerNT->info(TAG, "Control module shut down");
289   }
290
291 #ifdef HANDLE_VT_SWITCHING
292   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
293   close(fdtty);
294 #endif
295
296   if (logger)
297   {
298     loggerNT->info(TAG, "Log module shutting down... bye!\n\n");
299     logger->shutdown();
300     delete logger;
301   }
302
303   if (config)
304   {
305     delete config;
306   }
307
308   exit(code);
309 }
310
311 // -------------------------------------------------------------------------------------------------------------------
312
313 long long getTimeMS()
314 {
315   struct timespec ts;
316   clock_gettime(VOMP_LINUX_CLOCK, &ts);
317   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
318 }
319
320 int getClockRealTime(struct timespec *tp) // FIXME - del if all goes chrono
321 {
322   return clock_gettime(CLOCK_REALTIME, tp);
323 }
324
325 const std::string& getCommandLineServer() // NCONFIG
326 {
327   return argvServer;
328 }