]> 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
65 Config* config;
66 Log* logger;
67 LogNT* loggerNT;
68 Control* control;
69
70 #ifdef HANDLE_VT_SWITCHING
71 int fdtty;
72 struct vt_mode old_vtmode;
73 #endif
74
75 static const char* TAG = "Main";
76
77 // Linux main function and sighandler
78 #ifndef WIN32
79 int main(int argc, char** argv)
80 {
81   bool crashed = false;
82
83
84   config = new Config();
85   if (!config->loadFile())
86   {
87     printf("Parse error in config.json\n");
88     shutdown(1);
89   }
90
91
92   int c;
93   while ((c = getopt(argc, argv, "cdns:")) != -1)
94   {
95     switch (c)
96     {
97       case 'c':
98         crashed = true;
99         break;
100       case 'd':
101         config->set("main", "debug", true); // and...
102         [[fallthrough]];
103       case 'n':
104         config->set("main", "daemonize", false);
105         break;
106       case 's':
107         config->set("main", "argv_server", optarg);
108         break;
109       case '?':
110         printf("Unknown option\n");
111         return 1;
112       default:
113         printf("Option error\n");
114         return 1;
115     }
116   }
117
118   // Start Log --------------------------------------------------------------------------------------------------
119   logger = new Log();
120   if (!logger)
121   {
122     printf("Failed to create Log object\n");
123     shutdown(1);
124   }
125
126   bool debugEnabled;
127   config->getBool("main", "debug", debugEnabled);
128   if (!logger->init(Log::DEBUG, "dummy", debugEnabled ? 1 : 0)) // NCONFIG x2
129   {
130     printf("Could not initialise log object. Aborting.\n");
131     shutdown(1);
132   }
133
134   logger->log("Main", Log::INFO, "Old log starting up...");
135
136
137
138   loggerNT = new LogNT();
139   if (!loggerNT)
140   {
141     printf("Failed to create LogNT object\n");
142     shutdown(1);
143   }
144
145   std::string logFileName("stdout");
146   config->getString("log", "filename", logFileName);
147   if (!loggerNT->init(logFileName, debugEnabled ? 1 : 0)) // NCONFIG x2
148   {
149     printf("Could not initialise log object. Aborting.\n");
150     shutdown(1);
151   }
152
153   //logger->log("Main", Log::INFO, "Starting up...");
154   loggerNT->info(TAG, "Starting up...");
155
156   // Daemonize --------------------------------------------------------------------------------------------------
157
158   bool daemonize;
159   config->getBool("main", "daemonize", daemonize);
160   if (daemonize)
161   {
162     // Fork away
163     pid_t forkTest = fork();
164     if (forkTest == -1)
165     { printf("Cannot fork (1).\n"); exit(1); }
166     if (forkTest != 0) _exit(0); // PID returned, I am the parent
167     // otherwise, I am the child
168     setsid();
169     forkTest = fork();
170     if (forkTest == -1)
171     { printf("Cannot fork (2).\n"); exit(1); }
172     if (forkTest != 0) _exit(0); // PID returned, I am the parent
173     // otherwise, I am the child
174     close(0);
175     close(1);
176     close(2);
177   }
178
179   // Set up signal handling ------------------------------------------------------------------------------------------
180
181   // Block all signals
182   sigset_t set;
183   sigfillset(&set);
184   int sigBlockResult = pthread_sigmask(SIG_SETMASK, &set, NULL);
185   if (sigBlockResult)
186   {
187     //logger->log("Main", Log::EMERG, "Could not block signals: %i", sigBlockResult);
188     loggerNT->crit(TAG, "Could not block signals: {}", sigBlockResult);
189     shutdown(1);
190   }
191
192   // Start signal receiver thread
193   std::thread threadSignalReceiver(threadSignalReceiverFunction);
194   threadSignalReceiver.detach();
195
196   loggerNT->info(TAG, "Signal handlers set up successfully");
197
198   // VT Switching -----------------------------------------------------------------------------------------------
199
200 #ifdef HANDLE_VT_SWITCHING
201   if (
202
203
204     (fdtty = open("/dev/tty", O_WRONLY),0) == -1   // FIXME. Why the ,0 ? Surely this kills the log line below
205
206
207   )
208   {
209     loggerNT->warn(TAG, "Could not open /dev/tty. Please change permissions");
210   }
211   else
212   {
213     int free_vt;
214     if (ioctl(fdtty, VT_OPENQRY, &free_vt) == -1 || free_vt == -1)
215     {
216       loggerNT->crit(TAG, "Could not retrieve free virtual console, please change permissions");
217     }
218     else
219     {
220       ioctl(fdtty, VT_ACTIVATE, free_vt);
221       ioctl(fdtty, VT_WAITACTIVE, free_vt);
222       ioctl(fdtty, VT_LOCKSWITCH, 1);
223     }
224   }
225 #endif
226
227   // Test area ------------------------------------------------------------------------------------------------------
228
229   //shutdown(0);
230
231   // Run control ----------------------------------------------------------------------------------------------------
232
233   control = new Control();
234   if (!control)
235   {
236     loggerNT->crit(TAG, "Control module failed to create");
237     shutdown(1);
238   }
239
240   if (!control->init(crashed))
241   {
242     loggerNT->crit(TAG, "Control module failed to initialise");
243     delete control;
244     control = NULL;
245     shutdown(1);
246   }
247
248   control->run();
249   control->shutdown();
250
251   shutdown(0);
252 }
253
254 // -------------------------------------------------------------------------------------------------------------------
255
256 void threadSignalReceiverFunction()
257 {
258   int sig;
259   sigset_t set;
260   sigfillset(&set);
261   while(1)
262   {
263     if(sigwait(&set, &sig))
264     {
265       loggerNT->crit(TAG, "Sigwait returned fail - signal handler exiting");
266       return;
267     }
268
269     loggerNT->info(TAG, "Signal received: {}", sig);
270
271     if ((sig == SIGINT) || (sig == SIGTERM)) control->stop();
272   }
273 }
274
275 #endif
276
277 // -------------------------------------------------------------------------------------------------------------------
278
279 [[ noreturn ]] void shutdown(int code)
280 {
281   // FIXME, send a del all to boxstack first, then get rid of it after control?
282   if (control) // shut down control here in case views have posted messages
283   {
284     delete control;
285     control = NULL;
286     loggerNT->info(TAG, "Control module shut down");
287   }
288
289 #ifdef HANDLE_VT_SWITCHING
290   ioctl(fdtty, VT_UNLOCKSWITCH, 1);
291   close(fdtty);
292 #endif
293
294   if (logger)
295   {
296     loggerNT->info(TAG, "Log module shutting down... bye!\n\n");
297     logger->shutdown();
298     delete logger;
299   }
300
301   if (config)
302   {
303     delete config;
304   }
305
306   exit(code);
307 }
308
309 // -------------------------------------------------------------------------------------------------------------------
310
311 long long getTimeMS()
312 {
313   struct timespec ts;
314   clock_gettime(VOMP_LINUX_CLOCK, &ts);
315   return ts.tv_sec * 1000 + ts.tv_nsec / 1000000LL;
316 }
317
318 int getClockRealTime(struct timespec *tp) // FIXME - del if all goes chrono
319 {
320   return clock_gettime(CLOCK_REALTIME, tp);
321 }
322