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