3 * This file is part of LCDd, the lcdproc server.
5 * This file is released under the GNU General Public License. Refer to the
6 * COPYING file distributed with this package.
8 * Copyright (c) 1999, William Ferrell, Scott Scriven
12 * 2002, Guillaume Filion
13 * 2003, Benjamin Tse (Win32 support)
14 * 2005-2006, Peter Marschall (cleanup)
16 * Contains main(), plus signal callback functions and a help screen.
18 * Program init, command-line handling, and the main loop are
19 * implemented here. Also, minimal data about the program such as
20 * the revision number.
22 * Some of this stuff should probably be move elsewhere eventually,
23 * such as command-line handling and the main loop. main() is supposed
37 # include <sys/wait.h>
43 #include <sys/types.h>
45 #include <sys/types.h>
50 #ifdef HAVE_SYS_TIME_H
51 # include <sys/time.h>
53 /* TODO: fill in what to include otherwise */
55 #include "shared/report.h"
60 #include "screenlist.h"
64 #include "serverscreens.h"
65 #include "menuscreens.h"
67 #include "shared/configfile.h"
72 #if !defined(SYSCONFDIR)
73 # define SYSCONFDIR "/etc"
76 #define DEFAULT_BIND_ADDR "127.0.0.1"
77 #define DEFAULT_BIND_PORT LCDPORT
78 #define DEFAULT_CONFIGFILE SYSCONFDIR "/LCDd.conf"
79 #define DEFAULT_USER "nobody"
80 #define DEFAULT_DRIVER "curses"
81 #define DEFAULT_DRIVER_PATH "" /* not needed */
83 #define DEFAULT_FOREGROUND_MODE 0
84 #define DEFAULT_ROTATE_SERVER_SCREEN 1
85 #define DEFAULT_REPORTDEST RPT_DEST_STDERR
86 #define DEFAULT_REPORTLEVEL RPT_WARNING
88 #define DEFAULT_SCREEN_DURATION 32
89 #define DEFAULT_HEARTBEAT HEARTBEAT_ON
91 /* All variables are set to 'unset' values*/
93 #define UNSET_STR "\01"
95 /* Socket to bind to...
97 Using loopback is much more secure; it means that this port is
98 accessible only to programs running locally on the same host as LCDd.
100 Using variables for these means that (later) we can select which port
101 and which address to bind to at run time. */
104 /* Store some standard defines into vars... */
105 char *version
= VERSION
;
106 char *protocol_version
= PROTOCOL_VERSION
;
107 char *api_version
= API_VERSION
;
108 char *build_date
= __DATE__
;
111 /**** Configuration variables ****/
112 /* Some variables are settable on the command line. This are variables that
113 * change the mode of operation. This includes settings that you can use to
114 * enable debugging: driver selection, report settings, bind address etc.
115 * These variables should be in main.h and main.c (below).
117 * All other settings do not need to be settable from the command line. They
118 * also do not necesarily need to be read in main.c but can better be read in
119 * in the file concerned.
122 unsigned int bind_port
= UNSET_INT
;
123 char bind_addr
[64]; /* Do not preinit these strings as they will occupy */
124 char configfile
[256]; /* a lot of space in the executable. */
125 char user
[64]; /* The values will be overwritten anyway... */
127 /* The drivers and their driver parameters */
128 char *drivernames
[MAX_DRIVERS
];
131 /* End of configuration variables */
133 /* Local variables */
134 static int foreground_mode
= UNSET_INT
;
135 static int report_dest
= UNSET_INT
;
136 static int report_level
= UNSET_INT
;
138 static int stored_argc
;
139 static char **stored_argv
;
140 static volatile short got_reload_signal
= 0;
142 /* Local exported variables */
145 /**** Local functions ****/
146 static void clear_settings(void);
147 static int process_command_line(int argc
, char **argv
);
148 static int process_configfile(char *cfgfile
);
149 static void set_default_settings(void);
150 static void install_signal_handlers(int allow_reload
);
151 static void child_ok_func(int signal
);
152 static pid_t
daemonize(void);
153 static int wave_to_parent(pid_t parent_pid
);
154 static int init_drivers(void);
155 static int drop_privs(char *user
);
156 static int init_screens(void);
157 static void do_reload(void);
158 static void do_mainloop(void);
159 static void exit_program(int val
);
160 static void catch_reload_signal(int val
);
161 static int interpret_boolean_arg(char *s
);
162 static void output_help_screen(void);
163 static void output_GPL_notice(void);
165 #define CHAIN(e,f) { if (e>=0) { e=(f); }}
166 #define CHAIN_END(e,msg) { if (e<0) { report(RPT_CRIT,(msg)); exit(e); }}
170 main(int argc
, char **argv
)
173 pid_t parent_pid
= 0;
179 * Settings in order of preference:
181 * 1: Settings specified in command line options...
182 * 2: Settings specified in configuration file...
183 * 3: Default settings
185 * Because of this, and because one option (-c) specifies where
186 * the configuration file is, things are done in this order:
188 * 1. Read and set options.
189 * 2. Read configuration file; if option is read in configuration
190 * file and not already set, then set it.
191 * 3. Having read configuration file, if parameter is not set,
192 * set it to the default value.
194 * It is for this reason that the default values are **NOT** set
195 * in the variable declaration...
198 /* Report that server is starting (report will be delayed) */
199 report(RPT_NOTICE
, "LCDd version %s starting", version
);
200 report(RPT_INFO
, "Built on %s, protocol version %s, API version %s",
201 build_date
, protocol_version
, api_version
);
205 /* Read command line*/
206 CHAIN(e
, process_command_line(argc
, argv
));
209 * If config file was not given on command line use default */
210 if (strcmp(configfile
, UNSET_STR
) == 0)
211 strncpy(configfile
, DEFAULT_CONFIGFILE
, sizeof(configfile
));
212 CHAIN(e
, process_configfile(configfile
));
214 /* Set default values*/
215 set_default_settings();
217 /* Set reporting settings (will also flush delayed reports) */
218 set_reporting("LCDd", report_level
, report_dest
);
219 report(RPT_INFO
, "Set report level to %d, output to %s", report_level
,
220 ((report_dest
== RPT_DEST_SYSLOG
) ? "syslog" : "stderr"));
221 CHAIN_END(e
, "Critical error while processing settings, abort.");
223 /* Now, go into daemon mode (if we should)...
224 * We wait for the child to report it is running OK. This mechanism
225 * is used because forking after starting the drivers causes the
226 * child to loose the (LPT) port access. */
227 if (!foreground_mode
) {
228 report(RPT_INFO
, "Server forking to background");
229 CHAIN(e
, parent_pid
= daemonize());
232 report(RPT_INFO
, "Server running in foreground");
234 install_signal_handlers(!foreground_mode
);
235 /* Only catch SIGHUP if not in foreground mode */
237 /* Startup the subparts of the server */
238 CHAIN(e
, sock_init(bind_addr
, bind_port
));
239 CHAIN(e
, screenlist_init());
240 CHAIN(e
, init_drivers());
241 CHAIN(e
, clients_init());
242 CHAIN(e
, input_init());
243 CHAIN(e
, menuscreens_init());
244 CHAIN(e
, server_screen_init());
245 CHAIN_END(e
, "Critical error while initializing, abort.");
246 if (!foreground_mode
) {
247 /* Tell to parent that startup went OK. */
248 wave_to_parent(parent_pid
);
250 drop_privs(user
); /* This can't be done before, because sending a
251 signal to a process of a different user will fail */
254 /* This loop never stops; we'll get out only with a signal...*/
265 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
267 bind_port
= UNSET_INT
;
268 strncpy(bind_addr
, UNSET_STR
, sizeof(bind_addr
));
269 strncpy(configfile
, UNSET_STR
, sizeof(configfile
));
270 strncpy(user
, UNSET_STR
, sizeof(user
));
271 foreground_mode
= UNSET_INT
;
272 rotate_server_screen
= UNSET_INT
;
273 backlight
= UNSET_INT
;
275 default_duration
= UNSET_INT
;
276 report_dest
= UNSET_INT
;
277 report_level
= UNSET_INT
;
279 for (i
= 0; i
< num_drivers
; i
++) {
280 free(drivernames
[i
]);
281 drivernames
[i
] = NULL
;
287 /* parses arguments given on command line */
289 process_command_line(int argc
, char **argv
)
294 debug(RPT_DEBUG
, "%s(argc=%d, argv=...)", __FUNCTION__
, argc
);
297 opterr
= 0; /* Prevent some messages to stderr */
299 /* Analyze options here.. (please try to keep list of options the
300 * same everywhere) */
301 while ((c
= getopt(argc
, argv
, "hc:d:fa:p:u:w:s:r:i:")) > 0) {
304 help
= 1; /* Continue to process the other
308 strncpy(configfile
, optarg
, sizeof(configfile
));
309 configfile
[sizeof(configfile
)-1] = 0; /* Terminate string */
312 /* Add to a list of drivers to be initialized later...*/
313 if (num_drivers
< MAX_DRIVERS
) {
314 drivernames
[num_drivers
] = strdup(optarg
);
315 if (drivernames
[num_drivers
] != NULL
) {
319 report(RPT_ERR
, "alloc error storing driver name: %s", optarg
);
323 report(RPT_ERR
, "Too many drivers!");
331 strncpy(bind_addr
, optarg
, sizeof(bind_addr
));
332 bind_addr
[sizeof(bind_addr
)-1] = 0; /* Terminate string */
335 bind_port
= atoi(optarg
);
338 strncpy(user
, optarg
, sizeof(user
));
339 user
[sizeof(user
)-1] = 0; /* Terminate string */
342 default_duration
= (int) (atof(optarg
) * 1e6
/ TIME_UNIT
);
343 if (default_duration
* TIME_UNIT
< 2e6
) {
344 report(RPT_ERR
, "Waittime should be at least 2 (seconds), not %.8s", optarg
);
349 b
= interpret_boolean_arg(optarg
);
351 report(RPT_ERR
, "Not a boolean value: '%s'", optarg
);
354 report_dest
= (b
) ? RPT_DEST_SYSLOG
: RPT_DEST_STDERR
;
358 report_level
= atoi(optarg
);
361 b
= interpret_boolean_arg(optarg
);
363 report(RPT_ERR
, "Not a boolean value: '%s'", optarg
);
366 rotate_server_screen
= b
;
370 /* For some reason getopt also returns an '?'
371 * when an option argument is mission... */
372 report(RPT_ERR
, "Unknown option: '%c'", optopt
);
376 report(RPT_ERR
, "Missing option argument!");
383 report(RPT_ERR
, "Non-option arguments on the command line !");
387 output_help_screen();
394 /* reads and parses configuration file */
396 process_configfile(char *configfile
)
401 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
403 /* Read server settings*/
405 if (config_read_file(configfile
) != 0) {
406 report(RPT_CRIT
, "Could not read config file: %s", configfile
);
410 if (bind_port
== UNSET_INT
)
411 bind_port
= config_get_int("server", "port", 0, UNSET_INT
);
413 if (strcmp(bind_addr
, UNSET_STR
) == 0)
414 strncpy(bind_addr
, config_get_string("server", "bind", 0, UNSET_STR
), sizeof(bind_addr
));
416 if (strcmp(user
, UNSET_STR
) == 0)
417 strncpy(user
, config_get_string("server", "user", 0, UNSET_STR
), sizeof(user
));
419 if (default_duration
== UNSET_INT
) {
420 default_duration
= (config_get_float("server", "waittime", 0, 0) * 1e6
/ TIME_UNIT
);
421 if (default_duration
== 0)
422 default_duration
= UNSET_INT
;
423 else if (default_duration
* TIME_UNIT
< 2e6
) {
424 report(RPT_WARNING
, "Waittime should be at least 2 (seconds). Set to 2 seconds.");
425 default_duration
= 2e6
/ TIME_UNIT
;
429 if (foreground_mode
== UNSET_INT
) {
430 int fg
= config_get_bool("server", "foreground", 0, UNSET_INT
);
433 foreground_mode
= fg
;
436 if (rotate_server_screen
== UNSET_INT
) {
437 rotate_server_screen
= config_get_bool("server", "serverscreen", 0, UNSET_INT
);
440 if (backlight
== UNSET_INT
) {
441 s
= config_get_string("server", "backlight", 0, UNSET_STR
);
442 if (strcmp(s
, "on") == 0) {
443 backlight
= BACKLIGHT_ON
;
445 else if (strcmp(s
, "off") == 0) {
446 backlight
= BACKLIGHT_OFF
;
448 else if (strcmp(s
, "open") == 0) {
449 backlight
= BACKLIGHT_OPEN
;
451 else if (strcmp(s
, UNSET_STR
) != 0) {
452 report(RPT_WARNING
, "Backlight state should be on, off or open");
456 if (report_dest
== UNSET_INT
) {
457 int rs
= config_get_bool("server", "reportToSyslog", 0, UNSET_INT
);
460 report_dest
= (rs
) ? RPT_DEST_SYSLOG
: RPT_DEST_STDERR
;
462 if (report_level
== UNSET_INT
) {
463 report_level
= config_get_int("server", "reportLevel", 0, UNSET_INT
);
469 /* If drivers have been specified on the command line, then do not
470 * use the driver list from the config file.
472 if (num_drivers
== 0) {
473 /* read the drivernames*/
476 s
= config_get_string("server", "driver", num_drivers
, NULL
);
480 drivernames
[num_drivers
] = malloc(strlen(s
)+1);
481 strcpy(drivernames
[num_drivers
], s
);
492 set_default_settings(void)
494 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
496 /* Set defaults into unfilled variables....*/
498 if (bind_port
== UNSET_INT
)
499 bind_port
= DEFAULT_BIND_PORT
;
500 if (strcmp(bind_addr
, UNSET_STR
) == 0)
501 strncpy(bind_addr
, DEFAULT_BIND_ADDR
, sizeof(bind_addr
));
502 if (strcmp(user
, UNSET_STR
) == 0)
503 strncpy(user
, DEFAULT_USER
, sizeof(user
));
505 if (foreground_mode
== UNSET_INT
)
506 foreground_mode
= DEFAULT_FOREGROUND_MODE
;
507 if (rotate_server_screen
== UNSET_INT
)
508 rotate_server_screen
= DEFAULT_ROTATE_SERVER_SCREEN
;
510 if (default_duration
== UNSET_INT
)
511 default_duration
= DEFAULT_SCREEN_DURATION
;
512 if (backlight
== UNSET_INT
)
513 backlight
= BACKLIGHT_OPEN
;
515 if (report_dest
== UNSET_INT
)
516 report_dest
= DEFAULT_REPORTDEST
;
517 if (report_level
== UNSET_INT
)
518 report_level
= DEFAULT_REPORTLEVEL
;
521 /* Use default driver*/
522 if (num_drivers
== 0) {
523 drivernames
[0] = malloc(strlen(DEFAULT_DRIVER
)+1);
524 strcpy(drivernames
[0], DEFAULT_DRIVER
);
531 install_signal_handlers(int allow_reload
)
534 /* Installs signal handlers so that the program does clean exit and
535 * can also receive a reload signal.
536 * sigaction() is favoured over signal() */
540 debug(RPT_DEBUG
, "%s(allow_reload=%d)", __FUNCTION__
, allow_reload
);
542 sigemptyset(&(sa
.sa_mask
));
544 /* Clients can cause SIGPIPE if they quit unexpectedly, and the
545 * default action is to kill the server. Just ignore it. */
546 sa
.sa_handler
= SIG_IGN
;
547 sigaction(SIGPIPE
, &sa
, NULL
);
549 sa
.sa_handler
= exit_program
;
550 sa
.sa_flags
= SA_RESTART
;
552 sigaction(SIGINT
, &sa
, NULL
); /* Ctrl-C will cause a clean exit...*/
553 sigaction(SIGTERM
, &sa
, NULL
); /* and "kill"...*/
556 sa
.sa_handler
= catch_reload_signal
;
557 /* On SIGHUP reread config and restart the drivers ! */
560 /* Treat this signal just like INT and TERM */
562 sigaction(SIGHUP
, &sa
, NULL
);
564 /* Win32 does not support POSIX signals i.e. sigaction(). However, it does
565 * support ANSI signals in mingw. */
566 signal(SIGINT
, exit_program
); /* Ctrl-C will cause a clean exit...*/
567 signal(SIGTERM
, exit_program
); /* and "kill"...*/
568 signal(SIGPIPE
, SIG_IGN
);
570 /* REVISIT: implement SIGHUP on windows */
576 child_ok_func(int signal
)
578 /* We only catch this signal to be sure the child runs OK. */
580 debug(RPT_INFO
, "%s(signal=%d)", __FUNCTION__
, signal
);
582 /* Exit now ! because of bug? in wait() */
583 _exit(0); /* Parent exits normally. */
591 /* WIN32 does not support fork() - CreateProcess() does not even have
592 * similar functionality. Instead don't daemonize on WIN32.
602 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
605 debug(RPT_INFO
, "parent = %d", parent
);
607 /* Install handler at parent for child's signal */
608 /* sigaction should be more portable than signal, but it does not
609 * work for some reason. */
610 sa
.sa_handler
= child_ok_func
;
611 sigemptyset(&(sa
.sa_mask
));
612 sa
.sa_flags
= SA_RESTART
;
613 sigaction(SIGUSR1
, &sa
, NULL
);
616 switch ((child
= fork())) {
618 report(RPT_ERR
, "Could not fork");
620 case 0: /* We are the child */
622 default: /* We are the parent */
623 debug(RPT_INFO
, "child = %d", child
);
625 /* BUG? According to the man page wait() should also return
626 * when a signal comes in that is caught. Instead it
627 * continues to wait. */
629 if (WIFEXITED(child_status
)) {
630 /* Child exited normally, probably because of some
632 debug(RPT_INFO
, "Child has terminated!");
633 exit(WEXITSTATUS(child_status
));
634 /* Parent exits with same status as child did... */
636 /* Child is still running and has signalled it's OK.
637 * This means the parent can now rest in peace. */
638 debug(RPT_INFO
, "Got OK signal from child.");
639 exit(0); /* Parent exits normally. */
641 /* At this point we are always the child. */
642 /* Reset signal handler */
643 sa
.sa_handler
= SIG_DFL
;
644 sigaction(SIGUSR1
, &sa
, NULL
);
646 setsid(); /* Create a new session because otherwise we'll
647 * catch a SIGHUP when the shell is closed. */
655 wave_to_parent(pid_t parent_pid
)
658 debug(RPT_DEBUG
, "%s(parent_pid=%d)", __FUNCTION__
, parent_pid
);
660 kill(parent_pid
, SIGUSR1
);
672 int output_loaded
= 0;
674 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
676 for (i
= 0; i
< num_drivers
; i
++) {
678 res
= drivers_load_driver(drivernames
[i
]);
683 case 0: /* Driver does input only */
685 case 1: /* Driver does output */
688 case 2: /* Driver does output in foreground (don't daemonize) */
694 report(RPT_ERR
, "Could not load driver %.40s", drivernames
[i
]);
698 /* Do we have a running output driver ?*/
702 report(RPT_ERR
, "There is no output driver");
709 drop_privs(char *user
)
712 struct passwd
*pwent
;
714 debug(RPT_DEBUG
, "%s(user=\"%.40s\")", __FUNCTION__
, user
);
716 if (getuid() == 0 || geteuid() == 0) {
717 if ((pwent
= getpwnam(user
)) == NULL
) {
718 report(RPT_ERR
, "User %.40s not a valid user!", user
);
721 if (setuid(pwent
->pw_uid
) < 0) {
722 report(RPT_ERR
, "Unable to switch to user %.40s", user
);
728 /* Don't alter privileges in WIN32 */
738 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
740 if (screenlist_init() < 0) {
741 report(RPT_ERR
, "Error initializing screen list");
745 /* Add the server screen */
746 if (server_screen_init() < 0) {
747 report(RPT_ERR
, "Error initializing server screens");
750 if (!rotate_server_screen
) {
751 /* Display the server screen only when there are no other
753 /* server_screen->priority = PRI_BACKGROUND; */
764 drivers_unload_all(); /* Close all drivers */
769 /* Reread command line*/
770 CHAIN(e
, process_command_line(stored_argc
, stored_argv
));
772 /* Reread config file */
773 if (strcmp(configfile
, UNSET_STR
)==0)
774 strncpy(configfile
, DEFAULT_CONFIGFILE
, sizeof(configfile
));
775 CHAIN(e
, process_configfile(configfile
));
777 /* Set default values */
778 CHAIN(e
, (set_default_settings(), 0));
780 /* Set reporting values */
781 CHAIN(e
, set_reporting("LCDd", report_level
, report_dest
));
782 CHAIN(e
, (report(RPT_INFO
, "Set report level to %d, output to %s", report_level
,
783 ((report_dest
== RPT_DEST_SYSLOG
) ? "syslog" : "stderr")), 0));
785 /* And restart the drivers */
786 CHAIN(e
, init_drivers());
787 CHAIN_END(e
, "Critical error while reloading, abort.");
797 struct timeval last_t
;
800 LARGE_INTEGER last_t
;
801 LARGE_INTEGER perf_freq
; /* frequency of high perf counter (cycles per usec) */
804 long int process_lag
= 0;
805 long int render_lag
= 0;
808 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
811 gettimeofday(&t
, NULL
); /* Get initial time */
813 QueryPerformanceFrequency(&perf_freq
);
814 /* scale perf_freq to number of cycles per micro-sec */
815 /* REVISIT: this causes rounding errors below but is more efficient */
816 perf_freq
.QuadPart
/= 1e6
;
817 QueryPerformanceCounter(&t
);
821 /* Get current time */
824 gettimeofday(&t
, NULL
);
825 t_diff
= t
.tv_sec
- last_t
.tv_sec
;
826 if ((t_diff
+ 1) > (LONG_MAX
/ 1e6
)) {
827 /* We're going to overflow the calculation - probably been to sleep, fudge the values */
830 render_lag
= (1e6
/RENDER_FREQ
);
833 t_diff
+= t
.tv_usec
- last_t
.tv_usec
;
836 QueryPerformanceCounter(&t
);
837 /*t_diff.HighPart = t.HighPart - last_t.HighPart;
838 t_diff.LowPart = t.LowPart - last_t.LowPart;
840 t_diff
= t
.QuadPart
- last_t
.QuadPart
;
841 t_diff
/= perf_freq
.QuadPart
; /* scale to microseconds */
842 /* REVISIT: assumes fits into long */
844 process_lag
+= t_diff
;
845 if (process_lag
> 0) {
846 /* Time for a processing stroke */
847 sock_poll_clients(); /* poll clients for input*/
848 parse_all_client_messages(); /* analyze input from network clients*/
849 handle_input(); /* handle key input from devices*/
851 /* We've done the job... */
852 process_lag
= 0 - (1e6
/PROCESS_FREQ
);
853 /* Note : this does not make a fixed frequency */
856 render_lag
+= t_diff
;
857 if (render_lag
> 0) {
858 /* Time for a rendering stroke */
860 screenlist_process();
861 s
= screenlist_current();
863 /* TODO: Move this call to every client connection
864 * and every screen add...
866 if (s
== server_screen
) {
867 update_server_screen();
869 render_screen(s
, timer
);
871 /* We've done the job... */
872 if (render_lag
> (1e6
/RENDER_FREQ
) * MAX_RENDER_LAG_FRAMES
) {
873 /* Cause rendering slowdown because too much lag */
874 render_lag
= (1e6
/RENDER_FREQ
) * MAX_RENDER_LAG_FRAMES
;
876 render_lag
-= (1e6
/RENDER_FREQ
);
877 /* Note: this DOES make a fixed frequency (except with slowdown) */
880 /* Sleep just as long as needed */
881 sleeptime
= min(0-process_lag
, 0-render_lag
);
886 /* Sleep in Windows takes milliseconds argument */
887 Sleep(sleeptime
/ 1000);
891 /* Check if a SIGHUP has been caught */
892 if (got_reload_signal
) {
893 got_reload_signal
= 0;
904 exit_program(int val
)
908 debug(RPT_DEBUG
, "%s(val=%d)", __FUNCTION__
, val
);
910 /* TODO: These things shouldn't be so interdependent. The order
911 * things are shut down in shouldn't matter...
915 strncpy(buf
, "Server shutting down on ", sizeof(buf
));
917 case 1: strcat(buf
, "SIGHUP"); break;
918 case 2: strcat(buf
, "SIGINT"); break;
919 case 15: strcat(buf
, "SIGTERM"); break;
920 default: snprintf(buf
, sizeof(buf
), "Server shutting down on signal %d", val
); break;
921 /* Other values should not be seen, but just in case.. */
923 report(RPT_NOTICE
, buf
); /* report it */
926 /* Set emergency reporting and flush all messages if not done already. */
927 if (report_level
== UNSET_INT
)
928 report_level
= DEFAULT_REPORTLEVEL
;
929 if (report_dest
== UNSET_INT
)
930 report_dest
= DEFAULT_REPORTDEST
;
931 set_reporting("LCDd", report_level
, report_dest
);
933 goodbye_screen(); /* display goodbye screen on LCD display */
934 drivers_unload_all(); /* release driver memory and file descriptors */
936 /* Shutdown things if server start was complete */
937 clients_shutdown(); /* shutdown clients (must come first) */
938 menuscreens_shutdown();
939 screenlist_shutdown(); /* shutdown screens (must come after client_shutdown) */
940 input_shutdown(); /* shutdown key input part */
941 sock_shutdown(); /* shutdown the sockets server */
943 report(RPT_INFO
, "Exiting.");
949 catch_reload_signal(int val
)
951 debug(RPT_DEBUG
, "%s(val=%d)", __FUNCTION__
, val
);
953 got_reload_signal
= 1;
958 interpret_boolean_arg(char *s
)
960 /* keep these checks consistent with config_get_boolean() */
961 if (strcasecmp(s
, "0") == 0 || strcasecmp(s
, "false") == 0
962 || strcasecmp(s
, "n") == 0 || strcasecmp(s
, "no") == 0
963 || strcasecmp(s
, "off") == 0) {
966 if (strcasecmp(s
, "1") == 0 || strcasecmp(s
, "true") == 0
967 || strcasecmp(s
, "y") == 0 || strcasecmp(s
, "yes") == 0
968 || strcasecmp(s
, "on") == 0) {
971 /* no legal boolean string given */
977 output_GPL_notice(void)
979 /* This will only be invoked when running in foreground
980 * So, directly output to stderr
982 fprintf(stderr
, "LCDd %s, LCDproc Protocol %s\n", VERSION
, PROTOCOL_VERSION
);
983 fprintf(stderr
, "Part of the LCDproc suite\n");
984 fprintf(stderr
, "Copyright (C) 1998-2007 William Ferrell, Scott Scriven\n"
985 " and many other contributors\n\n");
987 fprintf(stderr
, "This program is free software; you can redistribute it and/or\n"
988 "modify it under the terms of the GNU General Public License\n"
989 "as published by the Free Software Foundation; either version 2\n"
990 "of the License, or (at your option) any later version.\n\n");
992 fprintf(stderr
, "This program is distributed in the hope that it will be useful,\n"
993 "but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
994 "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
995 "GNU General Public License for more details.\n\n");
997 fprintf(stderr
, "You should have received a copy of the GNU General Public License\n"
998 "along with this program; if not, write to the Free Software Foundation,\n"
999 "Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.\n\n");
1004 output_help_screen(void)
1006 /* Help screen is printed to stdout on purpose. No reason to have
1009 debug(RPT_DEBUG
, "%s()", __FUNCTION__
);
1011 fprintf(stdout
, "LCDd - LCDproc Server Daemon, %s\n\n", version
);
1012 fprintf(stdout
, "Copyright (c) 1999-2006 Scott Scriven, William Ferrell, and misc. contributors.\n");
1013 fprintf(stdout
, "This program is released under the terms of the GNU General Public License.\n\n");
1014 fprintf(stdout
, "Usage: LCDd [<options>]\n");
1015 fprintf(stdout
, " where <options> are:\n");
1016 fprintf(stdout
, " -h Display this help screen\n");
1017 fprintf(stdout
, " -c <config> Use a configuration file other than %s\n",
1018 DEFAULT_CONFIGFILE
);
1019 fprintf(stdout
, " -d <driver> Add a driver to use (overrides drivers in config file) [%s]\n",
1021 fprintf(stdout
, " -f Run in the foreground\n");
1022 fprintf(stdout
, " -a <addr> Network (IP) address to bind to [%s]\n",
1024 fprintf(stdout
, " -p <port> Network port to listen for connections on [%i]\n",
1026 fprintf(stdout
, " -u <user> User to run as [%s]\n",
1028 fprintf(stdout
, " -w <waittime> Time to pause at each screen (in seconds) [%d]\n",
1029 DEFAULT_SCREEN_DURATION
/RENDER_FREQ
);
1030 fprintf(stdout
, " -s <bool> If set, reporting will be done using syslog\n");
1031 fprintf(stdout
, " -r <level> Report level [%d]\n",
1032 DEFAULT_REPORTLEVEL
);
1033 fprintf(stdout
, " -i <bool> Whether to rotate the server info screen\n");
1035 /* Error messages will be flushed to the configured output after this