From c68e1aca72b263de9ffa81aed126ab5752f39345 Mon Sep 17 00:00:00 2001 From: marschap Date: Sun, 6 Jan 2008 17:03:51 +0000 Subject: [PATCH] add PID file handling to clients (including signal handling to remove the files) --- clients/lcdexec/Makefile.am | 2 +- clients/lcdexec/lcdexec.c | 65 ++++++++++++++++++++++++++++++------ clients/lcdexec/lcdexec.conf | 3 ++ clients/lcdproc/Makefile.am | 2 +- clients/lcdproc/lcdproc.conf | 3 ++ clients/lcdproc/main.c | 31 ++++++++++++++--- clients/lcdvc/Makefile.am | 2 +- clients/lcdvc/lcd_link.c | 10 +++++- clients/lcdvc/lcd_link.h | 3 +- clients/lcdvc/lcdvc.c | 65 +++++++++++++++++++++++++++++++----- clients/lcdvc/lcdvc.conf | 3 ++ configure.in | 24 +++++++++++++ 12 files changed, 185 insertions(+), 28 deletions(-) diff --git a/clients/lcdexec/Makefile.am b/clients/lcdexec/Makefile.am index a0d5c0e..09b24bd 100644 --- a/clients/lcdexec/Makefile.am +++ b/clients/lcdexec/Makefile.am @@ -8,7 +8,7 @@ lcdexec_SOURCES = lcdexec.c menu.c menu.h lcdexec_LDADD = ../../shared/libLCDstuff.a -AM_CPPFLAGS = -I$(top_srcdir) -DSYSCONFDIR=\"$(sysconfdir)\" +AM_CPPFLAGS = -I$(top_srcdir) -DSYSCONFDIR=\"$(sysconfdir)\" -DPIDFILEDIR=\"$(pidfiledir)\" EXTRA_DIST = $(sysconf_DATA) diff --git a/clients/lcdexec/lcdexec.c b/clients/lcdexec/lcdexec.c index c877bfb..dec0dd0 100644 --- a/clients/lcdexec/lcdexec.c +++ b/clients/lcdexec/lcdexec.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -32,8 +33,12 @@ #if !defined(SYSCONFDIR) # define SYSCONFDIR "/etc" #endif +#if !defined(PIDFILEDIR) +# define PIDFILEDIR "/var/run" +#endif #define DEFAULT_CONFIGFILE SYSCONFDIR "/lcdexec.conf" +#define DEFAULT_PIDFILE PIDFILEDIR "/lcdexec.pid" /** information about a process started by lcdexec */ @@ -52,7 +57,7 @@ typedef struct ProcInfo { char * help_text = "lcdexec - LCDproc client to execute commands from the LCDd menu\n" "\n" -"Copyright (c) 2002, Joris Robijn, 2006 Peter Marschall.\n" +"Copyright (c) 2002, Joris Robijn, 2006,7 Peter Marschall.\n" "This program is released under the terms of the GNU General Public License.\n" "\n" "Usage: lcdexec []\n" @@ -76,10 +81,11 @@ int port = UNSET_INT; int foreground = FALSE; static int report_level = UNSET_INT; static int report_dest = UNSET_INT; +char *pidfile = NULL; char *displayname = NULL; char *default_shell = NULL; -/* Other variables */ +/* Other global variables */ MenuEntry *main_menu = NULL; /**< pointer to the main menu */ ProcInfo *proc_queue = NULL; /**< pointer to the list of executed processes */ @@ -88,9 +94,12 @@ int lcd_hgt = 0; /**< LCD display height reported by the server */ int sock = -1; /**< socket to connect to server */ +int Quit = 0; /**< indicate end of main loop */ + /* Function prototypes */ -static void sigchld_handler(int); +static void exit_program(int val); +static void sigchld_handler(int signal); static int process_command_line(int argc, char **argv); static int process_configfile(char * configfile); static int connect_and_setup(void); @@ -128,8 +137,30 @@ int main(int argc, char **argv) if (daemon(1,1) != 0) { report(RPT_ERR, "Error: daemonize failed"); } + + if (pidfile != NULL) { + FILE *pidf = fopen(pidfile, "w"); + + if (pidf) { + fprintf(pidf, "%d\n", (int) getpid()); + fclose(pidf); + } else { + fprintf(stderr, "Error creating pidfile %s: %s\n", + pidfile, strerror(errno)); + return(EXIT_FAILURE); + } + } } + /* setup signal handlers for common signals */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = exit_program; + sigaction(SIGINT, &sa, NULL); // Ctrl-C + sigaction(SIGTERM, &sa, NULL); // "regular" kill + sigaction(SIGHUP, &sa, NULL); // kill -HUP + sigaction(SIGKILL, &sa, NULL); // kill -9 [cannot be trapped; but ...] + /* setup signal handler for children to avoid zombies */ sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; @@ -138,7 +169,18 @@ int main(int argc, char **argv) main_loop(); - return 0; + exit_program(EXIT_SUCCESS); +} + + +static void exit_program(int val) +{ + //printf("exit program\n"); + Quit = 1; + sock_close(sock); + if ((foreground != TRUE) && (pidfile != NULL)) + unlink(pidfile); + exit(val); } @@ -215,7 +257,7 @@ static int process_command_line(int argc, char **argv) break; case 'h': fprintf(stderr, "%s", help_text); - exit(0); + exit(EXIT_SUCCESS); case ':': report(RPT_ERR, "Missing option argument for %c", optopt); error = -1; @@ -259,6 +301,9 @@ static int process_configfile(char *configfile) if (foreground != TRUE) { foreground = config_get_bool(progname, "Foreground", 0, FALSE); } + if (pidfile == NULL) { + pidfile = strdup(config_get_string(progname, "PidFile", 0, DEFAULT_PIDFILE)); + } if ((tmp = config_get_string(progname, "DisplayName", 0, NULL)) != NULL) displayname = strdup(tmp); @@ -453,8 +498,7 @@ static int process_response(char *str) else if (strcmp(argv[0], "bye") == 0) { // TODO: make it better report(RPT_INFO, "Server said: \"%s\"", str); - sock_close(sock); - exit(EXIT_SUCCESS); + exit_program(EXIT_SUCCESS); } else if (strcmp(argv[0], "huh?") == 0) { /* Report errors */ @@ -535,7 +579,7 @@ static int exec_command(MenuEntry *cmd) case 0: /* We're the child: execute the command */ execve(argv[0], (char **) argv, envp); - exit(0); + exit(EXIT_SUCCESS); break; default: /* We're the parent: setup the ProcInfo structure */ @@ -644,7 +688,7 @@ static int main_loop(void) int status_delay = 0; /* Continuously check if we get a menu event... */ - while ((num_bytes = sock_recv_string(sock, buf, sizeof(buf)-1)) >= 0) { + while (!Quit && ((num_bytes = sock_recv_string(sock, buf, sizeof(buf)-1)) >= 0)) { if (num_bytes == 0) { ProcInfo *p; @@ -690,7 +734,8 @@ static int main_loop(void) } } - report(RPT_ERR, "Server disconnected (or connection error)"); + if (!Quit) + report(RPT_ERR, "Server disconnected (or connection error)"); return 0; } diff --git a/clients/lcdexec/lcdexec.conf b/clients/lcdexec/lcdexec.conf index 565b26e..9c1658b 100644 --- a/clients/lcdexec/lcdexec.conf +++ b/clients/lcdexec/lcdexec.conf @@ -17,6 +17,9 @@ ReportToSyslog=false # run in foreground [default: false; legal: true, false] Foreground=false +# PidFile location when running as daemon [default: /var/run/lcdexec.pid] +#PidFile=/var/run/lcdexec.pid + # shell to use for executing programsi # [default: $SHELL or /bin/sh; legal: any shell that understands: -c COMMAND] #Shell=/bin/sh diff --git a/clients/lcdproc/Makefile.am b/clients/lcdproc/Makefile.am index 8e4fc71..1bc324d 100644 --- a/clients/lcdproc/Makefile.am +++ b/clients/lcdproc/Makefile.am @@ -12,7 +12,7 @@ if DARWIN AM_LDFLAGS = -framework CoreFoundation -framework IOKit endif -AM_CPPFLAGS = -I$(top_srcdir) -DSYSCONFDIR=\"$(sysconfdir)\" +AM_CPPFLAGS = -I$(top_srcdir) -DSYSCONFDIR=\"$(sysconfdir)\" -DPIDFILEDIR=\"$(pidfiledir)\" EXTRA_DIST = $(sysconf_DATA) diff --git a/clients/lcdproc/lcdproc.conf b/clients/lcdproc/lcdproc.conf index c923752..fcf0b5b 100644 --- a/clients/lcdproc/lcdproc.conf +++ b/clients/lcdproc/lcdproc.conf @@ -17,6 +17,9 @@ ReportToSyslog=false # run in foreground [default: false; legal: true, false] #Foreground=true +# PidFile location when running as daemon [default: /var/run/lcdproc.pid] +#PidFile=/var/run/lcdproc.pid + # slow down initial announcement of modes (in 1/100s) #delay=2 diff --git a/clients/lcdproc/main.c b/clients/lcdproc/main.c index d7e2937..1f88dfe 100644 --- a/clients/lcdproc/main.c +++ b/clients/lcdproc/main.c @@ -70,11 +70,15 @@ static int process_configfile(char *cfgfile); #if !defined(SYSCONFDIR) # define SYSCONFDIR "/etc" #endif +#if !defined(PIDFILEDIR) +# define PIDFILEDIR "/var/run" +#endif #define UNSET_INT -1 #define UNSET_STR "\01" #define DEFAULT_SERVER "127.0.0.1" #define DEFAULT_CONFIGFILE SYSCONFDIR "/lcdproc.conf" +#define DEFAULT_PIDFILE PIDFILEDIR "/lcdproc.pid" #define DEFAULT_REPORTDEST RPT_DEST_STDERR #define DEFAULT_REPORTLEVEL RPT_WARNING @@ -111,6 +115,7 @@ int port = LCDPORT; int foreground = FALSE; static int report_level = UNSET_INT; static int report_dest = UNSET_INT; +char *pidfile = NULL; char *configfile = NULL; char *displayname = NULL; @@ -243,7 +248,7 @@ main(int argc, char **argv) /* Read config file*/ cfgresult = process_configfile(configfile); if (cfgresult < 0) { - fprintf(stderr, "Error reading config file"); + fprintf(stderr, "Error reading config file\n"); exit(EXIT_FAILURE); } @@ -303,9 +308,22 @@ main(int argc, char **argv) if (foreground != TRUE) { if (daemon(1,0) != 0) { - fprintf(stderr, "Error: daemonize failed"); + fprintf(stderr, "Error: daemonize failed\n"); return(EXIT_FAILURE); } + + if (pidfile != NULL) { + FILE *pidf = fopen(pidfile, "w"); + + if (pidf) { + fprintf(pidf, "%d\n", (int) getpid()); + fclose(pidf); + } else { + fprintf(stderr, "Error creating pidfile %s: %s\n", + pidfile, strerror(errno)); + return(EXIT_FAILURE); + } + } } // Init the status gatherers... @@ -314,10 +332,8 @@ main(int argc, char **argv) // And spew stuff! main_loop(); - // Clean up + // Clean up & exit exit_program(EXIT_SUCCESS); - - return(0); } @@ -372,6 +388,9 @@ process_configfile(char *configfile) if (foreground != TRUE) { foreground = config_get_bool(progname, "Foreground", 0, FALSE); } + if (pidfile == NULL) { + pidfile = strdup(config_get_string(progname, "PidFile", 0, DEFAULT_PIDFILE)); + } if (islow < 0) { islow = config_get_int(progname, "Delay", 0, -1); } @@ -455,6 +474,8 @@ exit_program(int val) Quit = 1; sock_close(sock); mode_close(); + if ((foreground != TRUE) && (pidfile != NULL)) + unlink(pidfile); exit(val); } diff --git a/clients/lcdvc/Makefile.am b/clients/lcdvc/Makefile.am index 0a3e775..467f5a2 100644 --- a/clients/lcdvc/Makefile.am +++ b/clients/lcdvc/Makefile.am @@ -12,7 +12,7 @@ if DARWIN AM_LDFLAGS = -framework CoreFoundation -framework IOKit endif -AM_CPPFLAGS = -I$(top_srcdir) -DSYSCONFDIR=\"$(sysconfdir)\" +AM_CPPFLAGS = -I$(top_srcdir) -DSYSCONFDIR=\"$(sysconfdir)\" -DPIDFILEDIR=\"$(pidfiledir)\" #AM_CFLAGS = -g -O0 #AM_LDFLAGS = -g diff --git a/clients/lcdvc/lcd_link.c b/clients/lcdvc/lcd_link.c index 0c18c36..20ef723 100644 --- a/clients/lcdvc/lcd_link.c +++ b/clients/lcdvc/lcd_link.c @@ -33,7 +33,7 @@ static int read_connect_string(void); static int split(char *str, char delim, char *parts[], int maxparts); -int connect_and_setup(void) +int setup_connection(void) { char buf[200]; int i; @@ -83,6 +83,14 @@ int connect_and_setup(void) } +int teardown_connection(void) +{ + sock_close(sock); + + return 0; +} + + static int read_connect_string(void) { char buf[8192]; diff --git a/clients/lcdvc/lcd_link.h b/clients/lcdvc/lcd_link.h index d80aad3..1467421 100644 --- a/clients/lcdvc/lcd_link.h +++ b/clients/lcdvc/lcd_link.h @@ -4,7 +4,8 @@ extern char *address; extern int port; -int connect_and_setup(void); +int setup_connection(void); +int teardown_connection(void); int read_response(char *str, int maxsize); int process_response(char *str); int update_display(void); diff --git a/clients/lcdvc/lcdvc.c b/clients/lcdvc/lcdvc.c index bd7ba58..13cf276 100644 --- a/clients/lcdvc/lcdvc.c +++ b/clients/lcdvc/lcdvc.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -30,8 +31,12 @@ #if !defined(SYSCONFDIR) # define SYSCONFDIR "/etc" #endif +#if !defined(PIDFILEDIR) +# define PIDFILEDIR "/var/run" +#endif #define DEFAULT_CONFIGFILE SYSCONFDIR "/lcdvc.conf" +#define DEFAULT_PIDFILE PIDFILEDIR "/lcdvc.pid" char *help_text = @@ -50,9 +55,6 @@ char *help_text = " -s <0|1> Report to syslog (1) or stderr (0, default)\n" " -h Show this help\n"; -char *progname = "lcdvc"; -char *configfile = UNSET_STR; - /* Variables set by config */ int foreground = FALSE; static int report_level = UNSET_INT; @@ -61,7 +63,15 @@ char *vcsa_device = UNSET_STR; char *vcs_device = UNSET_STR; char *keys[4]; +/* Other global variables */ +char *progname = "lcdvc"; +char *pidfile = NULL; +char *configfile = UNSET_STR; + +int Quit = 0; /**< indicate end of main loop */ + /* Function prototypes */ +static void exit_program(int val); static int process_command_line(int argc, char **argv); static int process_configfile(char *configfile); static int main_loop(void); @@ -70,6 +80,7 @@ static int main_loop(void); int main(int argc, char **argv) { int e = 0; + struct sigaction sa; CHAIN( e, process_command_line( argc, argv )); if (strcmp( configfile, UNSET_STR ) == 0) { @@ -83,18 +94,51 @@ int main(int argc, char **argv) set_reporting( progname, report_level, report_dest ); CHAIN( e, open_vcs() ); - CHAIN( e, connect_and_setup() ); + CHAIN( e, setup_connection() ); CHAIN_END( e ); if (foreground != TRUE) { if (daemon(1,1) != 0) { report(RPT_ERR, "Error: daemonize failed"); } + + if (pidfile != NULL) { + FILE *pidf = fopen(pidfile, "w"); + + if (pidf) { + fprintf(pidf, "%d\n", (int) getpid()); + fclose(pidf); + } else { + fprintf(stderr, "Error creating pidfile %s: %s\n", + pidfile, strerror(errno)); + return(EXIT_FAILURE); + } + } } + /* setup signal handlers for common signals */ + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sa.sa_handler = exit_program; + sigaction(SIGINT, &sa, NULL); // Ctrl-C + sigaction(SIGTERM, &sa, NULL); // "regular" kill + sigaction(SIGHUP, &sa, NULL); // kill -HUP + sigaction(SIGKILL, &sa, NULL); // kill -9 [cannot be trapped; but ...] + main_loop(); - return 0; + exit_program(EXIT_SUCCESS); +} + + +static void exit_program(int val) +{ + //printf("exit program\n"); + Quit = 1; + teardown_connection(); + if ((foreground != TRUE) && (pidfile != NULL)) + unlink(pidfile); + exit(val); } @@ -113,7 +157,7 @@ static int process_command_line(int argc, char **argv) switch (c) { case 'h': fprintf(stderr, "%s", help_text); - exit( 0 ); + exit(EXIT_SUCCESS); case 'c': configfile = strdup(optarg); break; @@ -194,6 +238,10 @@ static int process_configfile(char *configfile) if (foreground != TRUE) { foreground = config_get_bool(progname, "Foreground", 0, FALSE); } + if (pidfile == NULL) { + pidfile = strdup(config_get_string(progname, "PidFile", 0, DEFAULT_PIDFILE)); + } + vcs_device = strdup(config_get_string(progname, "vcsDevice", 0, "/dev/vcs")); vcsa_device = strdup(config_get_string(progname, "vcsaDevice", 0, "/dev/vcsa")); @@ -214,7 +262,7 @@ static int main_loop(void) /* Continuously check if we get a menu event... */ - while ((num_bytes = read_response(buf, sizeof(buf)-1)) >= 0) { + while (!Quit && ((num_bytes = read_response(buf, sizeof(buf)-1)) >= 0)) { if (num_bytes != 0) { process_response(buf); } @@ -233,7 +281,8 @@ static int main_loop(void) } } - report(RPT_WARNING, "Server disconnected %d", num_bytes); + if (!Quit) + report(RPT_WARNING, "Server disconnected %d", num_bytes); return 0; } diff --git a/clients/lcdvc/lcdvc.conf b/clients/lcdvc/lcdvc.conf index 791b4dc..e20c1e5 100644 --- a/clients/lcdvc/lcdvc.conf +++ b/clients/lcdvc/lcdvc.conf @@ -18,6 +18,9 @@ # run in foreground [default: false; legal: true, false] #Foreground=false +# PidFile location when running as daemon [default: /var/run/lcdvc.pid] +#PidFile=/var/run/lcdvc.pid + # Keys to move the visible area around the screen. #UpKey=Up #DownKey=Down diff --git a/configure.in b/configure.in index 9985c21..9909490 100644 --- a/configure.in +++ b/configure.in @@ -273,6 +273,30 @@ dnl Select drivers to build LCD_DRIVERS_SELECT +# directory for PID files +pidfiledir=/var/run +# make sure the directory exists +if test ! -d $pidfiledir ; then + pidfiledir=`eval echo ${sysconfdir}` + case $pidfiledir in + NONE/*) pidfiledir=`echo $pidfiledir | sed "s~NONE~$ac_default_prefix~"` ;; + esac +fi + +AC_ARG_WITH(pidfile-dir, + [AS_HELP_STRING([--with-pidfile-dir=PATH], [specify location of pid files [/var/run]])], + [ if test -n "$withval" && test "x$withval" != "xno" && \ + test "x${withval}" != "xyes"; then + pidfiledir=$withval + if test ! -d $pidfiledir ; then + AC_MSG_WARN([** no $pidfiledir directory on this system **]) + fi + fi ] +) + +AC_SUBST(pidfiledir) + + # Features applicable to the server AC_ARG_ENABLE(seamless-hbars, [AS_HELP_STRING([--enable-seamless-hbars], [no gaps in horizontal bar graphs (if HW supports it)])],