- Modified forking. Child will now signal parent when it has started up OK. Only after that (or error) parent dies.

- Modified startup order of LCDd parts.
- Moved code for starting up the socket from main.c to sock.c
- Variable daemon_mode renamed to foreground_mode, consistent with command line.
- Variable lcd_port renamed to bind_port.
- Modified the constant stay_in_foreground for drivers hd44780 and sed1330. They don't need to stay in foreground anymore.
This commit is contained in:
robijn
2003-07-30 19:57:13 +00:00
parent b5f750f4f3
commit 75cd8a1112
6 changed files with 227 additions and 131 deletions
+1 -1
View File
@@ -111,7 +111,7 @@ static int parse_span_list (int *spanListArray[], int *spLsize, int *dispOffsets
// Vars for the server core
MODULE_EXPORT char * api_version = API_VERSION;
MODULE_EXPORT int stay_in_foreground = 1; // because of port access problems
MODULE_EXPORT int stay_in_foreground = 0;
MODULE_EXPORT int supports_multiple = 1; // yes, we have no global variables (except for constants)
MODULE_EXPORT char *symbol_prefix = "HD44780_";
+1 -1
View File
@@ -294,7 +294,7 @@ static char *defaultKeyMapMatrix[KEYPAD_MAXY][KEYPAD_MAXX] = {
// Vars for the server core
MODULE_EXPORT char * api_version = API_VERSION;
MODULE_EXPORT int stay_in_foreground = 1;
MODULE_EXPORT int stay_in_foreground = 0;
MODULE_EXPORT int supports_multiple = 1; // yes, we have no global variables (except for constants)
MODULE_EXPORT char *symbol_prefix = "sed1330_";
+143 -75
View File
@@ -37,6 +37,8 @@
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/wait.h>
#ifdef HAVE_SYS_TIME_H
# include <sys/time.h>
@@ -69,7 +71,7 @@ extern int optind, optopt, opterr;
#define DEFAULT_DRIVER "curses"
#define DEFAULT_DRIVER_PATH
#define MAX_DRIVERS 8
#define DEFAULT_DAEMON_MODE 1
#define DEFAULT_FOREGROUND_MODE 0
#define DEFAULT_ROTATE_SERVER_SCREEN 1
#define DEFAULT_REPORTTOSYSLOG 0
#define DEFAULT_REPORTLEVEL RPT_WARNING
@@ -97,21 +99,19 @@ char *build_date = __DATE__;
/* Some variables are settable on the command line. This are variables that
* change the mode of operation. This includes settings that you can use to
* enable debugging: driver selection, report settings, bind address etc.
* These variables should be in main.h and main.c (below).
*
* All other settings do not need to be settable from the command line. They
* also do not necesarily need to be read in main.c but can better be read in
* in the file concerned.
*/
/* All variables are set to 'unset' values*/
#define UNSET_INT -1
#define UNSET_STR "\01"
int lcd_port = UNSET_INT;
unsigned int bind_port = UNSET_INT;
char bind_addr[64]; /* Do not preinit these strings as they will occupy */
char configfile[256]; /* a lot of space in the executable. */
char user[64]; /* The values will be overwritten anyway... */
int daemon_mode = UNSET_INT;
int foreground_mode = UNSET_INT;
static int report_level = UNSET_INT;
static int report_to_syslog = UNSET_INT;
@@ -119,10 +119,15 @@ static int report_to_syslog = UNSET_INT;
/* The drivers and their driver parameters */
char *drivernames[MAX_DRIVERS];
int num_drivers = 0;
/* End of configuration variables */
/* Local variables */
int stored_argc;
char **stored_argv;
short got_reload_signal = 0;
/* Local exported variables */
long int timer = 0;
/**** Local functions ****/
@@ -130,8 +135,10 @@ void clear_settings();
int process_command_line (int argc, char **argv);
int process_configfile (char *cfgfile);
void set_default_settings();
int daemonize();
int init_sockets();
void install_signal_handlers (int allow_reload);
void child_ok_func (int signal);
pid_t daemonize();
int wave_to_parent (pid_t parent_pid);
int init_drivers();
int drop_privs(char *user);
int init_screens();
@@ -150,17 +157,11 @@ int
main (int argc, char **argv)
{
int e = 0;
pid_t parent_pid = 0;
stored_argc = argc;
stored_argv = argv;
signal (SIGINT, exit_program); /* Ctrl-C will cause a clean exit...*/
signal (SIGTERM, exit_program); /* and "kill"...*/
signal (SIGKILL, exit_program); /* and just in case, "kill -KILL" (which cannot be trapped; but oh well)*/
signal (SIGHUP, catch_reload_signal); /* On SIGHUP reread config and restart the drivers ! */
/* Let's see if we can actually get this to work ;) */
/*
* Settings in order of preference:
*
@@ -205,27 +206,35 @@ main (int argc, char **argv)
report( RPT_INFO, "Set report level to %d, output to %s", report_level, (report_to_syslog?"syslog":"stderr") );
CHAIN_END( e, "Critical error while processing settings, abort." );
/* Startup the server*/
CHAIN( e, screenlist_init() );
CHAIN( e, init_drivers() );
CHAIN( e, init_sockets() );
CHAIN( e, input_init() );
CHAIN( e, menuscreens_init() );
CHAIN( e, server_screen_init() );
CHAIN( e, drop_privs(user) );
CHAIN_END( e, "Critical error while initializing, abort." );
/* Now, go into daemon mode...*/
/* TODO: do this earlier and let parent process wait until
* child has fully started or reported its errors. */
if (daemon_mode) {
/* Now, go into daemon mode (if we should)...
* We wait for the child to report it is running OK. This mechanism
* is used because forking after starting the drivers causes the
* child to loose the (LPT) port access. */
if (!foreground_mode) {
report(RPT_INFO, "Server forking to background");
CHAIN( e, daemonize() );
CHAIN( e, parent_pid = daemonize() );
} else {
output_GPL_notice();
report(RPT_INFO, "Server running in foreground");
}
install_signal_handlers (!foreground_mode);
/* Only catch SIGHUP if not in foreground mode */
/* Startup the subparts of the server */
CHAIN( e, sock_init() );
CHAIN( e, screenlist_init() );
CHAIN( e, init_drivers() );
CHAIN( e, clients_init() );
CHAIN( e, input_init() );
CHAIN( e, menuscreens_init() );
CHAIN( e, server_screen_init() );
CHAIN_END( e, "Critical error while initializing, abort." );
if (!foreground_mode) {
/* Tell to parent that startup went OK. */
wave_to_parent (parent_pid);
}
drop_privs(user); /* This can't be done before, because sending a
signal to a process of a different user will fail */
do_mainloop();
/* This loop never stops; we'll get out only with a signal...*/
@@ -241,11 +250,11 @@ clear_settings ()
debug( RPT_DEBUG, "%s()", __FUNCTION__ );
lcd_port = UNSET_INT;
bind_port = UNSET_INT;
strncpy( bind_addr, UNSET_STR, sizeof(bind_addr) );
strncpy( configfile, UNSET_STR, sizeof(configfile) );
strncpy( user, UNSET_STR, sizeof(user) );
daemon_mode = UNSET_INT;
foreground_mode = UNSET_INT;
rotate_server_screen = UNSET_INT;
backlight = UNSET_INT;
@@ -303,7 +312,7 @@ process_command_line (int argc, char **argv)
report( RPT_ERR, "Not a boolean value: '%s'", optarg );
e = -1;
} else {
daemon_mode = !b;
foreground_mode = b;
}
break;
case 'a':
@@ -311,7 +320,7 @@ process_command_line (int argc, char **argv)
bind_addr[sizeof(bind_addr)-1] = 0; /* Terminate string */
break;
case 'p':
lcd_port = atoi(optarg);
bind_port = atoi(optarg);
break;
case 'u':
strncpy(user, optarg, sizeof(user));
@@ -385,8 +394,8 @@ process_configfile ( char *configfile )
report( RPT_WARNING, "Could not read config file: %s", configfile );
}
if( lcd_port == UNSET_INT )
lcd_port = config_get_int( "server", "port", 0, UNSET_INT );
if( bind_port == UNSET_INT )
bind_port = config_get_int( "server", "port", 0, UNSET_INT );
if( strcmp( bind_addr, UNSET_STR ) == 0 )
strncpy( bind_addr, config_get_string( "server", "bind", 0, UNSET_STR ), sizeof(bind_addr));
@@ -404,11 +413,11 @@ process_configfile ( char *configfile )
}
}
if( daemon_mode == UNSET_INT ) {
if( foreground_mode == UNSET_INT ) {
int fg;
fg = config_get_bool( "server", "foreground", 0, UNSET_INT );
if( fg != UNSET_INT )
daemon_mode = !fg;
foreground_mode = fg;
}
if( rotate_server_screen == UNSET_INT ) {
@@ -470,15 +479,15 @@ set_default_settings()
/* Set defaults into unfilled variables....*/
if (lcd_port == UNSET_INT)
lcd_port = DEFAULT_BIND_PORT;
if (bind_port == UNSET_INT)
bind_port = DEFAULT_BIND_PORT;
if (strcmp( bind_addr, UNSET_STR ) == 0)
strncpy (bind_addr, DEFAULT_BIND_ADDR, sizeof(bind_addr));
if (strcmp( user, UNSET_STR ) == 0)
strncpy(user, DEFAULT_USER, sizeof(user));
if (daemon_mode == UNSET_INT)
daemon_mode = DEFAULT_DAEMON_MODE;
if (foreground_mode == UNSET_INT)
foreground_mode = DEFAULT_FOREGROUND_MODE;
if (rotate_server_screen == UNSET_INT)
rotate_server_screen = DEFAULT_ROTATE_SERVER_SCREEN;
@@ -502,52 +511,112 @@ set_default_settings()
}
int
void
install_signal_handlers (int allow_reload)
{
/* Installs signal handlers so that the program does clean exit and
* can also receive a reload signal.
* sigaction() is favoured over signal() */
struct sigaction sa;
debug( RPT_DEBUG, "%s( allow_reload=%d )", __FUNCTION__, allow_reload );
sa.sa_handler = exit_program;
sigemptyset ( &(sa.sa_mask) );
sa.sa_flags = SA_RESTART;
sigaction (SIGINT, &sa, NULL); /* Ctrl-C will cause a clean exit...*/
sigaction (SIGTERM, &sa, NULL); /* and "kill"...*/
if (allow_reload) {
sa.sa_handler = catch_reload_signal;
/* On SIGHUP reread config and restart the drivers ! */
}
else {
/* Treat this signal just like INT and TERM */
}
sigaction (SIGHUP, &sa, NULL);
}
void
child_ok_func (int signal) {
/* We only catch this signal to be sure the child runs OK. */
debug( RPT_INFO, "%s( signal=%d )", __FUNCTION__, signal );
/* Exit now ! because of bug? in wait() */
_exit( 0 ); /* Parent exits normally. */
}
pid_t
daemonize()
{
int child;
pid_t child;
pid_t parent;
int child_status;
struct sigaction sa;
debug( RPT_DEBUG, "%s()", __FUNCTION__ );
parent = getpid();
debug( RPT_INFO, "parent = %d", parent );
/* Install handler at parent for child's signal */
/* sigaction should be more portable than signal, but it does not
* work for some reason. */
sa.sa_handler = child_ok_func;
sigemptyset ( &(sa.sa_mask) );
sa.sa_flags = SA_RESTART;
sigaction (SIGUSR1, &sa, NULL);
/* Do the fork */
switch ((child = fork ()) ) {
case -1:
report(RPT_ERR, "Could not fork");
report( RPT_ERR, "Could not fork" );
return -1;
case 0: /* We are the child*/
case 0: /* We are the child */
break;
default: /* We are the parent*/
usleep (1500000); /* Wait for child to initialize*/
exit (0); /* PARENT EXITS */
default: /* We are the parent */
debug( RPT_INFO, "child = %d", child );
wait( &child_status );
/* BUG? According to the man page wait() should also return
* when a signal comes in that is caught. Instead it
* continues to wait. */
if( WIFEXITED(child_status) ) {
/* Child exited normally, probably because of some
* error. */
debug( RPT_INFO, "Child has terminated!" );
exit( WEXITSTATUS(child_status) );
/* Parent exits with same status as child did... */
}
/* Child is still running and has signalled it's OK.
* This means the parent can now rest in peace. */
debug( RPT_INFO, "Got OK signal from child." );
exit( 0 ); /* Parent exits normally. */
}
/* This line removed because it eats error messages...
* setsid();*/ /* RELEASE TTY */
/*
* After this point, as a daemon, no error messages should
* go to the console unless drastic; rather, they should go to syslog
*
* However, option processing is not yet done, nor is any initialization (!)
* So we must wait until the main loop.
*/
return 0;
/* At this point we are always the child. */
/* Reset signal handler */
sa.sa_handler = SIG_DFL;
sigaction (SIGUSR1, &sa, NULL);
setsid(); /* Create a new session because otherwise we'll
* catch a SIGHUP when the shell is closed. */
return parent;
}
int
init_sockets ()
wave_to_parent (pid_t parent_pid)
{
debug( RPT_DEBUG, "%s()", __FUNCTION__ );
debug( RPT_DEBUG, "%s( parent_pid=%d )", __FUNCTION__, parent_pid );
if (sock_create_server (&bind_addr, lcd_port) <= 0) {
report(RPT_ERR, "Error opening socket");
return -1;
}
kill( parent_pid, SIGUSR1 );
/* Now init a bunch of required stuff...*/
if (clients_init () < 0) {
report(RPT_ERR, "Error initializing client list");
return -1;
}
return 0;
}
@@ -574,9 +643,7 @@ init_drivers()
output_loaded = 1;
break;
case 2: /* Driver does output in foreground (don't daemonize) */
if ( !output_loaded ) {
daemon_mode = 0;
}
foreground_mode = 1;
output_loaded = 1;
break;
}
@@ -782,6 +849,7 @@ exit_program (int val)
screenlist_shutdown (); /* shutdown screens (must come after client_shutdown) */
input_shutdown (); /* shutdown key input part */
report( RPT_INFO, "Exiting." );
_exit (0);
}
+25
View File
@@ -42,4 +42,29 @@ extern long int timer;
* If you get an overflow, please mail us and we will fix this personally
* for you ! */
/**** Configuration variables ****/
/* Only configuration items that are settable from the command line should
* be mentioned here. See main.c.
*/
extern unsigned int bind_port;
extern char bind_addr[]; /* Do not preinit these strings as they will occupy */
extern char configfile[]; /* a lot of space in the executable. */
extern char user[]; /* The values will be overwritten anyway... */
extern int foreground_mode;
extern int report_level;
extern int report_to_syslog;
/* The drivers and their driver parameters */
extern char *drivernames[];
extern int num_drivers;
/* End of configuration variables */
/* Defines for having 'unset' values*/
#define UNSET_INT -1
#define UNSET_STR "\01"
#endif
+52 -49
View File
@@ -32,6 +32,7 @@
#include <string.h>
#include "shared/sockets.h"
#include "main.h"
#include "sock.h"
#include "client.h"
#include "clients.h"
@@ -39,19 +40,57 @@
#include "shared/report.h"
#include "screenlist.h"
extern char bind_addr[64];
extern int lcd_port;
fd_set active_fd_set, read_fd_set;
int orig_sock;
int listening_fd;
/* Length of longest transmission allowed at once...*/
#define MAXMSG 8192
int read_from_client (int filedes);
int sock_read_from_client (int filedes);
/* Creates a socket in internet space*/
int
sock_init ()
{
debug (RPT_DEBUG, "%s( bind_addr=\"%s\", port=%d )", __FUNCTION__, bind_addr, bind_port);
/* Create the socket and set it up to accept connections. */
listening_fd = sock_create_inet_socket (bind_addr, bind_port);
if (listening_fd < 0) {
report (RPT_ERR, "%s: Error creating socket", __FUNCTION__);
return -1;
}
return 0;
}
/*
This code gets the send and receive buffer sizes.
{
int val, len, sock;
sock = new;
len = sizeof(int);
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, &len);
debug(RPT_DEBUG, "SEND buffer: %i bytes", val);
len = sizeof(int);
getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, &len);
debug(RPT_DEBUG, "RECV buffer: %i bytes", val);
}
*/
int
sock_shutdown ()
{
debug( RPT_DEBUG, "%s()", __FUNCTION__ );
close( listening_fd );
}
/* Creates a socket in internet space */
int
sock_create_inet_socket (char * addr, unsigned int port)
{
@@ -61,7 +100,6 @@ sock_create_inet_socket (char * addr, unsigned int port)
debug (RPT_DEBUG, "%s( addr=\"%s\", port=%i )", __FUNCTION__, addr, port);
/* Create the socket. */
/*debug(RPT_DEBUG, "Creating Inet Socket");*/
sock = socket (PF_INET, SOCK_STREAM, 0);
if (sock < 0) {
report(RPT_ERR, "%s: Could not create socket", __FUNCTION__);
@@ -86,25 +124,6 @@ sock_create_inet_socket (char * addr, unsigned int port)
report(RPT_NOTICE, "Listening for queries on %s:%d", addr, port);
}
return sock;
}
/*int StartSocketServer()*/
int
sock_create_server (char *bind_addr, int lcd_port)
{
int sock;
debug (RPT_DEBUG, "%s( bind_addr=\"%s\", port=%d )", __FUNCTION__, bind_addr, lcd_port);
/* Create the socket and set it up to accept connections. */
sock = sock_create_inet_socket (bind_addr, lcd_port);
if (sock < 0) {
report (RPT_ERR, "%s: Error creating socket", __FUNCTION__);
return -1;
}
if (listen (sock, 1) < 0) {
report(RPT_ERR, "%s: error in attempting to listen to port", __FUNCTION__);
return -1;
@@ -114,28 +133,11 @@ sock_create_server (char *bind_addr, int lcd_port)
FD_ZERO (&active_fd_set);
FD_SET (sock, &active_fd_set);
orig_sock = sock;
/*
{
int val, len, sock;
sock = new;
len = sizeof(int);
getsockopt(sock, SOL_SOCKET, SO_SNDBUF, &val, &len);
debug(RPT_DEBUG, "SEND buffer: %i bytes", val);
len = sizeof(int);
getsockopt(sock, SOL_SOCKET, SO_RCVBUF, &val, &len);
debug(RPT_DEBUG, "RECV buffer: %i bytes", val);
}
*/
return sock;
}
/* Service all clients with input pending...*/
/* Service all clients with input pending...*/
int
sock_poll_clients ()
{
@@ -162,11 +164,11 @@ sock_poll_clients ()
/* Service all the sockets with input pending. */
for (i = 0; i < FD_SETSIZE; ++i) {
if (FD_ISSET (i, &read_fd_set)) {
if (i == orig_sock) {
if (i == listening_fd) {
/* Connection request on original socket. */
int new_sock;
size = sizeof (clientname);
new_sock = accept (orig_sock, (struct sockaddr *) &clientname, &size);
new_sock = accept (listening_fd, (struct sockaddr *) &clientname, &size);
if (new_sock < 0) {
report (RPT_ERR, "%s: Accept error", __FUNCTION__);
return -1;
@@ -191,7 +193,7 @@ sock_poll_clients ()
err = 0;
do {
debug (RPT_DEBUG, "%s: reading...", __FUNCTION__);
err = read_from_client (i);
err = sock_read_from_client (i);
debug (RPT_DEBUG, "%s: ...done", __FUNCTION__);
if (err < 0) {
/* Client disconnected, destroy client data */
@@ -203,8 +205,9 @@ sock_poll_clients ()
clients_remove_client (c);
close (i);
FD_CLR (i, &active_fd_set);
} else
} else {
report (RPT_ERR, "%s: Can't find client of socket %i", __FUNCTION__, i);
}
}
} while (err > 0);
}
@@ -214,7 +217,7 @@ sock_poll_clients ()
}
int
read_from_client (int filedes)
sock_read_from_client (int filedes)
{
char buffer[MAXMSG];
int nbytes, i;
+5 -5
View File
@@ -9,17 +9,17 @@
*
*/
#ifndef SOCKETS_H
#define SOCKETS_H
#ifndef SOCK_H
#define SOCK_H
#include "shared/sockets.h"
typedef struct sockaddr_in sockaddr_in;
/* Server functions...*/
int sock_create_server ();
int sock_create_inet_socket (unsigned short int port);
int sock_init ();
int sock_shutdown ();
int sock_create_inet_socket (char * addr, unsigned int port);
int sock_poll_clients ();
int read_from_client (int filedes);
#endif