version 0.1.2 v0.1.2
authorMats Johannesson <devel@bredband.net>
Thu, 26 Jun 2008 17:49:18 +0000 (13:49 -0400)
committerAristeu Rozanski <arozansk@redhat.com>
Thu, 26 Jun 2008 17:49:18 +0000 (13:49 -0400)
* Signal handling in place. Not much in itself, but:

* Re-reads the configuration file upon receipt of the signal SIGUSR1.
Do a "kill -USR1 <pid-of-ekeys>" after a config file edit. That's USR
and the digit 1. I've also modified USR2 to do the same thing, for
now at least.

Included is a shell script called ekeys-reread.sh which does it for you
if ekeys is running in daemon mode. Also included is ekeys-terminate.sh
which replaces the former ekeys-kill.sh (a bit smarter).

* The program will now refuse to start if it detects another instance
running. Only works if there is a pid-file to examine of course.
A pid-file left by a crash (will never happen...) and not connected
with any process by that number is ignored, and the program continues.

* A properly terminated program deletes the pid-file upon exit. Proper
means a normal "kill <pid>", "killall ekeys", "kill -TERM <pid>" etc.
Doing a brutal "kill -9 <pid>" or if the program crashes (cough, cough)
will leave the pid-file undeleted.

* Any error, encountered by the code, which terminates the program is
written to the file "error.log" as well as to the screen. A restart
truncates the file (it becomes size 0). This means that there always
will be an error.log present, but empty in normal cases.

12 files changed:
ChangeLog
USAGE
ekeys-kill.sh [deleted file]
ekeys-reread.sh [new file with mode: 0755]
ekeys-terminate.sh [new file with mode: 0755]
src-server/config_all.c
src-server/globals.c
src-server/globals.h
src-server/main_setup.c
src-server/makefile
src-server/reg_events.c
src-server/signal_all.c [new file with mode: 0644]

index 3bf8fe2..e6d076a 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,8 +1,37 @@
 
+_Version 0.1.2 20 April 2005_
+
+* Signal handling in place. Not much in itself, but:
+
+* Re-reads the configuration file upon receipt of the signal SIGUSR1.
+Do a "kill -USR1 <pid-of-ekeys>" after a config file edit. That's USR
+and the digit 1. I've also modified USR2 to do the same thing, for
+now at least.
+
+Included is a shell script called ekeys-reread.sh which does it for you
+if ekeys is running in daemon mode. Also included is ekeys-terminate.sh
+which replaces the former ekeys-kill.sh (a bit smarter).
+
+* The program will now refuse to start if it detects another instance
+running. Only works if there is a pid-file to examine of course.
+A pid-file left by a crash (will never happen...) and not connected
+with any process by that number is ignored, and the program continues.
+
+* A properly terminated program deletes the pid-file upon exit. Proper
+means a normal "kill <pid>", "killall ekeys", "kill -TERM <pid>" etc.
+Doing a brutal "kill -9 <pid>" or if the program crashes (cough, cough)
+will leave the pid-file undeleted.
+
+* Any error, encountered by the code, which terminates the program is
+written to the file "error.log" as well as to the screen. A restart
+truncates the file (it becomes size 0). This means that there always
+will be an error.log present, but empty in normal cases.
+
+
 _Version 0.1.1 17 April 2005_
 
 * Now reads an external configuration file at program launch. It
-searches in the user home directory under the hidden "./expresskeys"
+searches in the user home directory under the hidden "/.expresskeys"
 directory. File is called "expresskeys.conf". If none is found, or
 the directory doesn't exist yet, it makes the dir, then creates and
 populates a minimal file from an internal list. The original "default",
@@ -54,7 +83,7 @@ process identification (PID) is a unique number, separating the
 program from all the other stuff you have running. The number can
 be used, for example, to do an easy kill.
 
-I've included a simple shell script (kalled ekeys-kill.sh) which reads the
+I've included a simple shell script (called ekeys-kill.sh) which reads the
 expresskeys.pid and tries to kill whatever process that has the pid,
 so do a "ps aux | grep ekeys" beforehand to be sure it's running
 (and don't confuse your "grep ekeys" with an actual "ekeys" instance).
diff --git a/USAGE b/USAGE
index 1bce69c..a1e9008 100644 (file)
--- a/USAGE
+++ b/USAGE
@@ -55,6 +55,12 @@ recreated whenever a configuration file is missing on program start.
 
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 
+* The configuration file is re-read upon receipt of the signal SIGUSR1.
+Do a "kill -USR1 <pid-of-ekeys>" after a config file edit (or -USR2).
+The included shell script "ekeys-reread.sh" will do it for you.
+
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
+
 * Use the X program "xev" to find keycodes when changing the configuration.
 
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
diff --git a/ekeys-kill.sh b/ekeys-kill.sh
deleted file mode 100755 (executable)
index a05ed29..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-#!/bin/sh
-
-# Kill ekeys by its PID number.
-if [ -f ~/.expresskeys/expresskeys.pid ]; then
-  echo "Will try to kill ekeys."
-  /bin/kill -15 `/bin/cat ~/.expresskeys/expresskeys.pid | /bin/head -n 1`
-fi
-
diff --git a/ekeys-reread.sh b/ekeys-reread.sh
new file mode 100755 (executable)
index 0000000..9c72f4e
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/sh
+
+# Reread ekeys config file.
+
+if [ -f ~/.expresskeys/expresskeys.pid ]; then
+
+   echo "Rereading ekeys config file."
+
+   /bin/kill -USR1 `/bin/cat ~/.expresskeys/expresskeys.pid | /bin/head -n 1`
+
+else
+
+   echo "ekeys doesn't seem to be running..."
+
+fi
+
diff --git a/ekeys-terminate.sh b/ekeys-terminate.sh
new file mode 100755 (executable)
index 0000000..0754d29
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/sh
+
+# Terminate ekeys by its PID number.
+
+if [ -f ~/.expresskeys/expresskeys.pid ]; then
+
+   echo "Will try to terminate ekeys."
+
+   /bin/kill -TERM `/bin/cat ~/.expresskeys/expresskeys.pid | /bin/head -n 1`
+
+   /bin/sleep 1
+
+   if ! [ -f ~/.expresskeys/expresskeys.pid ]; then
+      echo "Success!"
+   else
+      echo "Failure!"
+   fi
+
+else
+
+   echo "ekeys doesn't seem to be running..."
+
+fi
+
index d939d36..e20db9a 100644 (file)
@@ -42,17 +42,22 @@ int read_file_config(int *ip, FILE *fp)
        int num_field = 0;
 
        char buffer [MAXBUFFER];
-       char *prog_name [MAXRECORDS];
-       char *prog_field [MAXFIELDS];
        char *heap_protect;
 
+/* Put a dummy heap protection in place... */
+
+       if ((heap_protect = (char *)malloc(1024)) == NULL) {
+               return 2; 
+       }
+
 /* Previously allocated memory for the program names must be released */
 /* on subsequent reads of the config file. At program start the flag is 0 */
 
        if (reread_config) {
-               for (i = 0; i < num_list; i++) {
-                       free(prog_name [i]);
+               for (i = 0; i < num_list; i++, p++) {
+                       free(p->class_name);
                }
+               p = (void *)*ip;
        }
        reread_config = 1;
 
@@ -76,21 +81,10 @@ int read_file_config(int *ip, FILE *fp)
                                buffer [j] = '\0';
                                i = 0;
                                j = 0;
-                               if ((heap_protect = (char *)malloc(1024)) == NULL) {
-                                       for (i = 0; i < num_record; i++) {
-                                               free(prog_name [i]);
-                                       }
-                                       return 2; 
-                               }
-                               if ((prog_name [num_record] = (char *)malloc(strlen(buffer)+1)) == NULL) {
-                                       for (i = 0; i < num_record; i++) {
-                                               free(prog_name [i]);
-                                       }
-                                       free(heap_protect);
+                               if ((p->class_name = (char *)malloc(strlen(buffer)+1)) == NULL) {
                                        return 2;
                                }
-                               free(heap_protect);
-                               memcpy(prog_name [num_record], buffer, (strlen(buffer)+1));
+                               sprintf(p->class_name, "%s", buffer);
                                while ((c = fgetc(fp)) != EOF && (c != '}')) {
                                        if (num_field < MAXFIELDS) {
                                                if ((c != ',') && (isdigit(c))) {
@@ -102,67 +96,95 @@ int read_file_config(int *ip, FILE *fp)
                                                if (c == ',') {
                                                        buffer [i] = '\0';
                                                        i=0;
-                                                       if ((heap_protect = (char *)malloc(1024)) == NULL) {
-                                                               for (i = 0; i < num_field; i++) {
-                                                                       free(prog_field [i]);
-                                                               }
-                                                               for (i = 0; i <= num_record; i++) {
-                                                                       free(prog_name [i]);
-                                                               }
-                                                               return 2; 
-                                                       }
-                                                       if ((prog_field [num_field] = (char *)malloc(strlen(buffer)+1)) == NULL) {
-                                                               for (i = 0; i < num_field; i++) {
-                                                                       free(prog_field [i]);
-                                                               }
-                                                               for (i = 0; i <= num_record; i++) {
-                                                                       free(prog_name [i]);
-                                                               }
-                                                               free(heap_protect);
-                                                               return 2;
+
+                                                       switch (num_field) {
+                                                               case 0:
+                                                               p->handle_touch = atoi(buffer);
+                                                               break;
+                                                               case 1:
+                                                               p->l_touch_up = atoi(buffer);
+                                                               break;
+                                                               case 2:
+                                                               p->l_touch_up_plus = atoi(buffer);
+                                                               break;
+                                                               case 3:
+                                                               p->l_touch_down = atoi(buffer);
+                                                               break;
+                                                               case 4:
+                                                               p->l_touch_down_plus = atoi(buffer);
+                                                               break;
+                                                               case 5:
+                                                               p->r_touch_up = atoi(buffer);
+                                                               break;
+                                                               case 6:
+                                                               p->r_touch_up_plus = atoi(buffer);
+                                                               break;
+                                                               case 7:
+                                                               p->r_touch_down = atoi(buffer);
+                                                               break;
+                                                               case 8:
+                                                               p->r_touch_down_plus = atoi(buffer);
+                                                               break;
+                                                               case 9:
+                                                               p->key_9 = atoi(buffer);
+                                                               break;
+                                                               case 10:
+                                                               p->key_9_plus = atoi(buffer);
+                                                               break;
+                                                               case 11:
+                                                               p->key_10 = atoi(buffer);
+                                                               break;
+                                                               case 12:
+                                                               p->key_10_plus = atoi(buffer);
+                                                               break;
+                                                               case 13:
+                                                               p->key_11 = atoi(buffer);
+                                                               break;
+                                                               case 14:
+                                                               p->key_11_plus = atoi(buffer);
+                                                               break;
+                                                               case 15:
+                                                               p->key_12 = atoi(buffer);
+                                                               break;
+                                                               case 16:
+                                                               p->key_12_plus = atoi(buffer);
+                                                               break;
+                                                               case 17:
+                                                               p->key_13 = atoi(buffer);
+                                                               break;
+                                                               case 18:
+                                                               p->key_13_plus = atoi(buffer);
+                                                               break;
+                                                               case 19:
+                                                               p->key_14 = atoi(buffer);
+                                                               break;
+                                                               case 20:
+                                                               p->key_14_plus = atoi(buffer);
+                                                               break;
+                                                               case 21:
+                                                               p->key_15 = atoi(buffer);
+                                                               break;
+                                                               case 22:
+                                                               p->key_15_plus = atoi(buffer);
+                                                               break;
+                                                               case 23:
+                                                               p->key_16 = atoi(buffer);
+                                                               break;
+                                                               case 24:
+                                                               p->key_16_plus = atoi(buffer);
+                                                               break;
+                                                               default:
+                                                               break;
                                                        }
-                                                       free(heap_protect);
-                                                       memcpy(prog_field [num_field], buffer, (strlen(buffer)+1));
                                                        num_field++;
                                                }
                                        }
                                }
                                if (num_field == MAXFIELDS) {
-
-                                       p->class_name = prog_name [num_record];
-                                       p->handle_touch = (atoi(prog_field [0]));
-                                       p->l_touch_up = (atoi(prog_field [1]));
-                                       p->l_touch_up_plus = (atoi(prog_field [2]));
-                                       p->l_touch_down = (atoi(prog_field [3]));
-                                       p->l_touch_down_plus = (atoi(prog_field [4]));
-                                       p->r_touch_up = (atoi(prog_field [5]));
-                                       p->r_touch_up_plus = (atoi(prog_field [6]));
-                                       p->r_touch_down = (atoi(prog_field [7]));
-                                       p->r_touch_down_plus = (atoi(prog_field [8]));
-                                       p->key_9 = (atoi(prog_field [9]));
-                                       p->key_9_plus = (atoi(prog_field [10]));
-                                       p->key_10 = (atoi(prog_field [11]));
-                                       p->key_10_plus = (atoi(prog_field [12]));
-                                       p->key_11 = (atoi(prog_field [13]));
-                                       p->key_11_plus = (atoi(prog_field [14]));
-                                       p->key_12 = (atoi(prog_field [15]));
-                                       p->key_12_plus = (atoi(prog_field [16]));
-                                       p->key_13 = (atoi(prog_field [17]));
-                                       p->key_13_plus = (atoi(prog_field [18]));
-                                       p->key_14 = (atoi(prog_field [19]));
-                                       p->key_14_plus = (atoi(prog_field [20]));
-                                       p->key_15 = (atoi(prog_field [21]));
-                                       p->key_15_plus = (atoi(prog_field [22]));
-                                       p->key_16 = (atoi(prog_field [23]));
-                                       p->key_16_plus = (atoi(prog_field [24]));
-
                                        num_record++;
                                        p++;
                                } else {
-                                               free(prog_name [num_record]);
-                               }
-                               for (i = 0; i < num_field; i++) {
-                                       free(prog_field [i]);
+                                       free(p->class_name);
                                }
                                num_field = 0;
                        }
@@ -171,6 +193,7 @@ int read_file_config(int *ip, FILE *fp)
        if (!num_record) {
                return 1;
        }
+       free(heap_protect);
        num_list = num_record;
        return 0;
 }
index 508c16f..72510d8 100644 (file)
@@ -31,6 +31,9 @@ XDevice *pen_device;
 char *our_prog_name;
 char *pen_name;
 char *total_config_dir;
+char *total_config_file;
+char *total_pid_file;
+char *total_error_file;
 char *config_dir = "/.expresskeys";    /* This is where in the user home */
 char *config_file = "/expresskeys.conf";/* directory we'd like to reside, */
 char *pid_file = "/expresskeys.pid";   /* and what our different status */
index 543c414..4fe97cc 100644 (file)
 #include <stdlib.h>
 #include <ctype.h>
 #include <string.h>
-/* For the daemon and getpid calls */
+/* For the daemon, getpid and unlink calls */
 #include <unistd.h>
-/* For the mkdir and getpid calls */
+/* For the mkdir call */
 #include <sys/stat.h>
+/* For the mkdir, getpid and kill calls */
 #include <sys/types.h>
+/* For the signal and kill calls */
+#include <signal.h>
 
 /* Standard X includes */
 #include <X11/Xlib.h>
 /* Our global variables */
 extern char *our_prog_name;    /* This program's file name */
 extern char *pen_name;         /* Identifier as set in the X config file */
-extern char *total_config_dir; /* The "~/" of the user, plus our config_dir */
+extern char *total_config_dir; /* The "~/" of the user, plus our config_dir */
+extern char *total_config_file;        /* total_config_dir plus config_file */
+extern char *total_pid_file;   /* total_config_dir plus pid_file */
+extern char *total_error_file; /* total_config_dir plus error_file */
 extern char *config_dir;       /* Set to a dot directory: .expresskeys */
 extern char *config_file;      /* Set to expresskeys.conf */
 extern char *pid_file;         /* Set to expresskeys.pid */
@@ -90,6 +96,9 @@ extern int register_events(Display *display, XDeviceInfo *pad_info, char *name);
 extern int toggle_pen_mode(Display *display, char *name);
 /* In event_loop.c */
 extern int use_events(Display *display);
+/* In signal_all.c */
+extern void re_read_file_config(int signum);
+extern void clean_up_exit(int signum);
 
 /* Our global structures */
 /* The internal_list is initialized in globals.c */
index f20f0d5..506ae72 100644 (file)
@@ -32,6 +32,7 @@ int main (int argc, char *argv[])
        int len;
 
        FILE *fp;
+       FILE *errorfp;
 
 /* Prelaunch sanity checks: See if X is OK */
 
@@ -41,6 +42,124 @@ int main (int argc, char *argv[])
        }
        screen = DefaultScreen(display);
 
+/* Locate the home directory of the user running this program */
+
+       char *user_homedir;
+       if ((user_homedir = getenv("HOME")) == NULL) {
+               fprintf(stderr, "%s ERROR: Can not find your HOME directory!\n", our_prog_name);
+               XCloseDisplay(display);
+               return EXIT_KO;
+       }
+
+/* This is silly, but in order to keep the heap from being stomped on */
+/* by malloc and even automatic allocations we first need to allocate */
+/* a slight bit of memory. Here I use 1024 bytes, which seems enough. */
+/* Not doing this results in random errors when changing the code. */
+/* The "heap_protect" memory is freed before we leave the function */
+/* Another solution is to allocate a fair bit of memory in the actual */
+/* malloc that stomps on the heap. But it seems even sillier to use */
+/* a 1024 byte string when only needing 41, than this workaround is*/
+
+       char *heap_protect;
+       if ((heap_protect = (char *)malloc(1024)) == NULL) {
+               fprintf(stderr, "%s ERROR: Memory allocation trouble at stage 1!\n", our_prog_name);
+               return EXIT_KO; 
+       }
+
+/* Concatenate the home directory string with the string of our preferred*/
+/* configuration file directory. The address to the whole string is then */
+/* copied to a global pointer, so we won't have to perform this part again */
+
+       char *total_config_dir_block;
+       len = strlen(user_homedir) + strlen(config_dir) + 1;
+       if ((total_config_dir_block = (char *)malloc(len)) == NULL) {
+               fprintf(stderr, "%s ERROR: Memory allocation trouble at stage 2!\n", our_prog_name);
+               XCloseDisplay(display);
+               return EXIT_KO; 
+       }
+       sprintf(total_config_dir_block, "%s%s", user_homedir, config_dir);
+       total_config_dir = total_config_dir_block;
+
+/* Concatenate the full path with the config file name. Store address */
+
+       char *total_config_file_block;
+       len = strlen(total_config_dir) + strlen(config_file) + 1;
+       if ((total_config_file_block = (char *)malloc(len)) == NULL) {
+               fprintf(stderr, "%s ERROR: Memory allocation trouble at stage 3!\n", our_prog_name);
+               XCloseDisplay(display);
+               return EXIT_KO; 
+       }
+       sprintf(total_config_file_block, "%s%s", total_config_dir, config_file);
+       total_config_file = total_config_file_block;
+
+/* Concatenate the full path with the pid file name. Store address */
+
+       char *total_pid_file_block;
+       len = strlen(total_config_dir) + strlen(pid_file) + 1;
+       if ((total_pid_file_block = (char *)malloc(len)) == NULL) {
+               fprintf(stderr, "%s ERROR: Memory allocation trouble at stage 4!\n", our_prog_name);
+               XCloseDisplay(display);
+               return EXIT_KO; 
+       }
+       sprintf(total_pid_file_block, "%s%s", total_config_dir, pid_file);
+       total_pid_file = total_pid_file_block;
+
+/* Concatenate the full path with the error file name. Store address */
+
+       char *total_error_file_block;
+       len = strlen(total_config_dir) + strlen(error_file) + 1;
+       if ((total_error_file_block = (char *)malloc(len)) == NULL) {
+               fprintf(stderr, "%s ERROR: Memory allocation trouble at stage 5!\n", our_prog_name);
+               XCloseDisplay(display);
+               return EXIT_KO; 
+       }
+       sprintf(total_error_file_block, "%s%s", total_config_dir, error_file);
+       total_error_file = total_error_file_block;
+
+/* Prepare a scratch buffer for reading in an eventual PID */
+
+       char pid_buffer [MAXBUFFER];
+
+/* Try to open the the configuration directory for */
+/* reading, just as a test to see if it exists. A failure */
+/* here can mean many things, but we then try to create */
+/* it as a means to rule out a true lack of existence */
+
+       if ((fp = fopen(total_config_dir, "r")) == NULL) {
+               if ((mkdir(total_config_dir, 0777)) == NON_VALID) {
+                       fprintf(stderr, "%s ERROR: Can not read or create %s\n", our_prog_name, total_config_dir);
+                       XCloseDisplay(display);
+                       return EXIT_KO;
+               }
+       } else {
+               fclose(fp);
+       }
+
+/* If a pid file exists it is a sign of either A) program already runs, or */
+/* B) a crash/brutal kill not handled by our exit routine has occured */
+/* previously. We therefore read in such a PID and perform a "fake" kill */
+/* with it (signal number 0). If -1 (error) is returned we just carry on. */
+/* Otherwise our kill test detected a process with that PID and we exit, */
+/* based on the assumption that another instance is running */
+
+       if ((fp = fopen(total_pid_file, "r")) != NULL) {
+               fgets(pid_buffer, MAXBUFFER, fp);
+               fclose(fp);
+               if ((kill(atoi(pid_buffer), 0)) != NON_VALID) {
+                       fprintf(stderr, "%s ERROR: Another instance of %s seems to be running!\n", our_prog_name, our_prog_name);
+                       XCloseDisplay(display);
+                       return EXIT_KO;
+               }
+       }
+
+/* Open (and truncate) an error log for future reference */
+
+       if ((errorfp = fopen(total_error_file, "w")) == NULL) {
+               fprintf(stderr, "%s ERROR: Can not open %s in write mode\n", our_prog_name, total_error_file);
+               XCloseDisplay(display);
+               return EXIT_KO;
+       }
+       
 /* Can we use XTest to send fake key presses */
 
        int event_base, error_base;
@@ -48,6 +167,7 @@ int main (int argc, char *argv[])
        if (!XTestQueryExtension(display, &event_base, &error_base,
                &major_version, &minor_version)) {
                fprintf(stderr, "%s ERROR: XTest extension not present on your X server\n", our_prog_name);
+               fprintf(errorfp, "%s ERROR: XTest extension not present on your X server\n", our_prog_name);
                XCloseDisplay(display);
                return EXIT_KO;
        }
@@ -60,6 +180,7 @@ int main (int argc, char *argv[])
                XFree(xinputext);
        } else {
                fprintf(stderr, "%s ERROR: XInput extension not present on your X server\n", our_prog_name);
+               fprintf(errorfp, "%s ERROR: XInput extension not present on your X server\n", our_prog_name);
                XCloseDisplay(display);
                return EXIT_KO;
        }
@@ -86,6 +207,7 @@ int main (int argc, char *argv[])
        XFreeDeviceList(info);
        if (!pad_info) {
                fprintf(stderr, "%s ERROR: Can not find pad device: %s\n", our_prog_name, argv[1]);
+               fprintf(errorfp, "%s ERROR: Can not find pad device: %s\n", our_prog_name, argv[1]);
                XCloseDisplay(display);
                return EXIT_KO;
        }
@@ -108,6 +230,7 @@ int main (int argc, char *argv[])
                                XFreeDeviceList(info);
                                if (!pen_info) {
                                        fprintf(stderr, "%s ERROR: Can not find pen device: %s\n", our_prog_name, pen_name);
+                                       fprintf(errorfp, "%s ERROR: Can not find pen device: %s\n", our_prog_name, pen_name);
                                        XCloseDisplay(display);
                                        return EXIT_KO;
                                }
@@ -122,80 +245,18 @@ int main (int argc, char *argv[])
                pen_mode = Relative;
                if (toggle_pen_mode(display, pen_name)) {
                        fprintf(stderr, "%s ERROR: Can not open pen device: %s\n", our_prog_name, pen_name);
+                       fprintf(errorfp, "%s ERROR: Can not open pen device: %s\n", our_prog_name, pen_name);
                        XCloseDisplay(display);
                        return EXIT_KO;
                }
        }
 
-/* Locate the home directory of the user running this program */
-
-       char *user_homedir;
-       if ((user_homedir = getenv("HOME")) == NULL) {
-               fprintf(stderr, "%s ERROR: Can not find your HOME directory!\n", our_prog_name);
-               XCloseDisplay(display);
-               return EXIT_KO;
-       }
-
-/* This is silly, but in order to keep the heap from being stomped on */
-/* by malloc and even automatic allocations we first need to allocate */
-/* a slight bit of memory. Here I use 1024 bytes, which seems enough. */
-/* Not doing this results in random errors when changing the code. */
-/* The "heap_protect" memory is freed right after the next malloc */
-/* Another solution is to allocate a fair bit of memory in the actual */
-/* malloc that stomps on the heap. But it seems even sillier to use */
-/* a 1024 byte string when only needing 41, than this workaround is*/
-
-       char *heap_protect;
-       if ((heap_protect = (char *)malloc(1024)) == NULL) {
-               fprintf(stderr, "%s ERROR: Memory allocation trouble at stage 1!\n", our_prog_name);
-               return EXIT_KO; 
-       }
-
-/* Concatenate the home directory string with the string of our preferred*/
-/* configuration file directory. The address to the whole string is then */
-/* copied to a global pointer, so we won't have to perform this part again */
-
-       char *total_config_dir_block;
-       len = strlen(user_homedir) + strlen(config_dir) + 1;
-       if ((total_config_dir_block = (char *)malloc(len)) == NULL) {
-               fprintf(stderr, "%s ERROR: Memory allocation trouble at stage 2!\n", our_prog_name);
-               XCloseDisplay(display);
-               return EXIT_KO; 
-       }
-       sprintf(total_config_dir_block, "%s%s", user_homedir, config_dir);
-       total_config_dir = total_config_dir_block;
-
-/* And here's the heap_protect freeing... */
-
-       free(heap_protect);
-
-/* Try to open the the configuration directory for */
-/* reading, just as a test to see if it exists. A failure */
-/* here can mean many things, but we then try to create */
-/* it as a means to rule out a true lack of existence */
-
-       if ((fp = fopen(total_config_dir, "r")) == NULL) {
-               if ((mkdir(total_config_dir, 0777)) == NON_VALID) {
-                       fprintf(stderr, "%s ERROR: Can not read or create %s\n", our_prog_name, total_config_dir);
-                       XCloseDisplay(display);
-                       return EXIT_KO;
-               }
-       } else {
-               fclose(fp);
-       }
-
-/* Concatenate the full directory path string with */
-/* the string of our preferred configuration file name */
-
-       len = strlen(total_config_dir) + strlen(config_file) + 1;
-       char file_path [len];
-       sprintf(file_path, "%s%s", total_config_dir, config_file);
-       
 /* If no configuration file exists, write out a */
 /* short one from an internal memory structure */
 
-       if ((fp = fopen(file_path, "a+")) == NULL) {
-               fprintf(stderr, "%s ERROR: Can not open %s in read/write mode\n", our_prog_name, file_path);
+       if ((fp = fopen(total_config_file, "a+")) == NULL) {
+               fprintf(stderr, "%s ERROR: Can not open %s in read/write mode\n", our_prog_name, total_config_file);
+               fprintf(errorfp, "%s ERROR: Can not open %s in read/write mode\n", our_prog_name, total_config_file);
                XCloseDisplay(display);
                return EXIT_KO;
        } else {
@@ -204,7 +265,8 @@ int main (int argc, char *argv[])
                        for (p = internal_list; p < internal_list + num_list; p++) {
                                write_file_config((void *)&p, fp);
                                if (ferror(fp)) {
-                                       fprintf(stderr, "%s ERROR: Write error in %s\n", our_prog_name, file_path);
+                                       fprintf(stderr, "%s ERROR: Write error in %s\n", our_prog_name, total_config_file);
+                                       fprintf(errorfp, "%s ERROR: Write error in %s\n", our_prog_name, total_config_file);
                                        XCloseDisplay(display);
                                        return EXIT_KO;
                                }
@@ -216,8 +278,9 @@ int main (int argc, char *argv[])
 /* Read in an existing configuration file */
 
        p = external_list;
-       if ((fp = fopen(file_path, "r")) == NULL) {
-               fprintf(stderr, "%s ERROR: Can not open %s in read mode\n", our_prog_name, file_path);
+       if ((fp = fopen(total_config_file, "r")) == NULL) {
+               fprintf(stderr, "%s ERROR: Can not open %s in read mode\n", our_prog_name, total_config_file);
+               fprintf(errorfp, "%s ERROR: Can not open %s in read mode\n", our_prog_name, total_config_file);
                XCloseDisplay(display);
                return EXIT_KO;
        } else {
@@ -228,47 +291,65 @@ int main (int argc, char *argv[])
                        break;
 
                        case 1:
-                       fprintf(stderr, "%s ERROR: No complete record found in %s\n", our_prog_name, file_path);
+                       fprintf(stderr, "%s ERROR: No complete record found in %s\n", our_prog_name, total_config_file);
+                       fprintf(errorfp, "%s ERROR: No complete record found in %s\n", our_prog_name, total_config_file);
                        XCloseDisplay(display);
                        return EXIT_KO;
                        
                        case 2:
-                       fprintf(stderr, "%s ERROR: Memory allocation error while parsing %s\n", our_prog_name, file_path);
+                       fprintf(stderr, "%s ERROR: Memory allocation error while parsing %s\n", our_prog_name, total_config_file);
+                       fprintf(errorfp, "%s ERROR: Memory allocation error while parsing %s\n", our_prog_name, total_config_file);
                        XCloseDisplay(display);
                        return EXIT_KO;
                        
                        default:
-                       fprintf(stderr, "%s ERROR: Unknown error while parsing %s\n", our_prog_name, file_path);
+                       fprintf(stderr, "%s ERROR: Unknown error while parsing %s\n", our_prog_name, total_config_file);
+                       fprintf(errorfp, "%s ERROR: Unknown error while parsing %s\n", our_prog_name, total_config_file);
                        XCloseDisplay(display);
                        return EXIT_KO;
                }
        }
 
+/* Replace some of the normal signal handlers with our own functions. We */
+/* want SIGUSR1 and SIGUSR2 to read in the config file after a modification, */
+/* and all the normal program exits should first clean up a bit. The exit */
+/* could have been handled by a call to "atexit" but this was more fun :-) */
+
+       if ((signal(SIGUSR1, re_read_file_config) == SIG_ERR)
+               || (signal(SIGUSR2, re_read_file_config) == SIG_ERR)
+               || (signal(SIGINT, clean_up_exit) == SIG_ERR)
+               || (signal(SIGHUP, clean_up_exit) == SIG_ERR)
+               || (signal(SIGTERM, clean_up_exit) == SIG_ERR)) {
+               fprintf(stderr, "%s ERROR: Failed to modify signal handling!\n", our_prog_name);
+               fprintf(errorfp, "%s ERROR: Failed to modify signal handling!\n", our_prog_name);
+               XCloseDisplay(display);
+               return EXIT_KO;
+       }
+
 /* Ready to launch in the foreground or as a daemon after one last check. */
 /* In daemon mode we also take care of storing our PID in the config dir */
+/* Observe that with a (0, 0) standard input/output/error goes to /dev/null */
+/* I've found it better to use (0, 1) and see errors while writing the code */
 
        if (register_events(display, pad_info, argv[1])) {
                if (go_daemon) {
                        if ((daemon(0, 1)) == NON_VALID) {
                                fprintf(stderr, "%s ERROR: Failed to fork into daemon mode! EXITING!\n", our_prog_name);
+                               fprintf(errorfp, "%s ERROR: Failed to fork into daemon mode! EXITING!\n", our_prog_name);
                                XCloseDisplay(display);
-                               exit(EXIT_KO);
+                               return EXIT_KO;
                        } else {
-                               char pid_buffer [MAXBUFFER];
-                               sprintf(pid_buffer, "%d\n", getpid());
-
-                               len = strlen(total_config_dir) + strlen(pid_file) + 1;
-                               char pid_path [len];
-                               sprintf(pid_path, "%s%s", total_config_dir, pid_file);
-
-                               if ((fp = fopen(pid_path, "w")) == NULL) {
-                                       fprintf(stderr, "%s ERROR: Can not open %s in write mode\n", our_prog_name, pid_path);
+                               sprintf(pid_buffer, "%d", getpid());
+                               if ((fp = fopen(total_pid_file, "w")) == NULL) {
+                                       fprintf(stderr, "%s ERROR: Can not open %s in write mode\n", our_prog_name, total_pid_file);
+                                       fprintf(errorfp, "%s ERROR: Can not open %s in write mode\n", our_prog_name, total_pid_file);
                                        XCloseDisplay(display);
                                        exit(EXIT_KO);
                                } else {
                                        fprintf(fp, "%s", pid_buffer);
                                        if (ferror(fp)) {
-                                               fprintf(stderr, "%s ERROR: Write error in %s\n", our_prog_name, pid_path);
+                                               fprintf(stderr, "%s ERROR: Write error in %s\n", our_prog_name, total_pid_file);
+                                               fprintf(errorfp, "%s ERROR: Write error in %s\n", our_prog_name, total_pid_file);
                                                XCloseDisplay(display);
                                                exit(EXIT_KO);
                                        } else {
@@ -277,9 +358,12 @@ int main (int argc, char *argv[])
                                }
                        }
                }
+               fclose(errorfp); /* Close error log */
+               free(heap_protect); /* free the dummy heap protect */
                use_events(display); /* <-- Our true launch! The event loop */
        } else {
                fprintf(stderr, "%s ERROR: Could not register any events!\n", our_prog_name);
+               fprintf(errorfp, "%s ERROR: Could not register any events!\n", our_prog_name);
                XCloseDisplay(display);
                return EXIT_KO;
        }
index b946e9e..1149617 100644 (file)
@@ -8,8 +8,8 @@ LIBS = -lX11 -lXext -lXi -lXtst
 
 TARGET = ekeys
 
-SRCS = globals.c config_all.c get_device.c reg_events.c \
-       pen_mode.c event_loop.c main_setup.c
+SRCS = globals.c config_all.c signal_all.c pen_mode.c \
+       get_device.c reg_events.c event_loop.c main_setup.c
 
 OBJS = $(SRCS:.c=.o)
 ALL =  $(SRCS)
index 2f09554..ad5c4a4 100644 (file)
@@ -43,7 +43,6 @@ int register_events(Display *display, XDeviceInfo *pad_info, char *name)
 
        pad_device = XOpenDevice(display, pad_info->id);
        if (!pad_device) {
-               fprintf(stderr, "%s ERROR: Can not open device %s\n", our_prog_name, name);
                return 0;
        }
 
@@ -69,7 +68,6 @@ int register_events(Display *display, XDeviceInfo *pad_info, char *name)
                }
 
        if (XSelectExtensionEvent(display, root_win, event_list, count)) {
-               fprintf(stderr, "%s ERROR: Could not select extended events!\n", our_prog_name);
                return 0;
                }
        }
diff --git a/src-server/signal_all.c b/src-server/signal_all.c
new file mode 100644 (file)
index 0000000..05eaa92
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * signal_all.c -- Support ExpressKeys & Touch Strips on a Wacom Intuos3 tablet.
+ *
+ * Copyright (C) 2005 - Mats Johannesson
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include "globals.h"
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* Function acts as a signal handler replacement for SIGUSR1 and SIGUSR2 */
+/* On these signals we read a possibly changed configuration file again */
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+void re_read_file_config(int signum)
+{
+
+       struct program *p;
+
+       FILE *fp;
+       FILE *errorfp;
+
+/* Open (and truncate) an error log for future reference */
+       
+       if ((errorfp = fopen(total_error_file, "w")) == NULL) {
+               fprintf(stderr, "%s ERROR: Reread - Can not open %s in write mode\n", our_prog_name, total_error_file);
+               XCloseDisplay(display);
+               exit(EXIT_KO);
+       }
+
+/* Read in an existing configuration file */
+
+       p = external_list;
+       if ((fp = fopen(total_config_file, "r")) == NULL) {
+               fprintf(stderr, "%s ERROR: Reread - Can not open %s in read mode\n", our_prog_name, total_config_file);
+               fprintf(errorfp, "%s ERROR: Reread - Can not open %s in read mode\n", our_prog_name, total_config_file);
+               XCloseDisplay(display);
+               exit(EXIT_KO);
+       } else {
+               switch (read_file_config((void *)&p, fp)){
+                       
+                       case 0:
+                       fclose(fp);
+                       break;
+
+                       case 1:
+                       fprintf(stderr, "%s ERROR: Reread - No complete record found in %s\n", our_prog_name, total_config_file);
+                       fprintf(errorfp, "%s ERROR: Reread - No complete record found in %s\n", our_prog_name, total_config_file);
+                       XCloseDisplay(display);
+                       exit(EXIT_KO);
+                       
+                       case 2:
+                       fprintf(stderr, "%s ERROR: Reread - Memory allocation error while parsing %s\n", our_prog_name, total_config_file);
+                       fprintf(errorfp, "%s ERROR: Reread - Memory allocation error while parsing %s\n", our_prog_name, total_config_file);
+                       XCloseDisplay(display);
+                       exit(EXIT_KO);
+                       
+                       default:
+                       fprintf(stderr, "%s ERROR: Reread - Unknown error while parsing %s\n", our_prog_name, total_config_file);
+                       fprintf(errorfp, "%s ERROR: Reread - Unknown error while parsing %s\n", our_prog_name, total_config_file);
+                       XCloseDisplay(display);
+                       exit(EXIT_KO);
+               }
+       }
+       
+       fclose(errorfp);
+}
+
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+/* Function acts as a signal handler replacement for SIGINT, SIGHUP and */
+/* SIGTERM. All are normal exit signals. We want to trap them in order to */
+/* perform some house keeping pre-exit. Here it deletes a possible PID file */
+/* Since it takes care of several signals, it could get invoked recursively */
+/* if some other signal comes in. We use this "volatile" variable to track */
+/* the case. At the end we restore the default signal handler and raise it */
+/*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
+
+volatile sig_atomic_t clean_up_exit_in_progress = 0;
+void clean_up_exit(int signum)
+{
+       if (clean_up_exit_in_progress) {
+               raise(signum);
+       }
+       clean_up_exit_in_progress = 1;
+       
+       if (go_daemon) {
+               unlink(total_pid_file);
+       }
+       
+       signal(signum, SIG_DFL);
+       raise(signum);
+}
+