version 0.3.1
[expresskeys.git] / src-expresskeys / on_signal.c
1 /*
2  on_signal.c -- Support ExpressKeys & Touch Strips on a Wacom Intuos3 tablet.
3
4  Copyright (C) 2005-2006 - Mats Johannesson
5
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10
11  This program is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15
16  You should have received a copy of the GNU General Public License
17  along with this program; if not, write to the Free Software
18  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307, USA.
19 */
20
21 #include "globals.h"
22
23 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
24  Function acts as a signal handler replacement for SIGUSR1
25  On this signal we read a possibly changed configuration file again
26  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
27
28 void re_read_file_config(int signum)
29 {
30
31         struct program *p;
32
33         FILE *fp;
34         FILE *errorfp;
35
36 /* Open (and truncate) an error log for future reference */
37
38         if ((errorfp = fopen(total_error_file, "w")) == NULL) {
39                 exit_on_error(errorfp, "%s ERROR: Reread - Can not open %s in write mode\n", our_prog_name, total_error_file);
40         }
41
42 /* Read in an existing configuration file */
43
44         p = external_list;
45         if ((fp = fopen(total_config_file, "r")) == NULL) {
46                 exit_on_error(errorfp, "%s ERROR: Reread - Can not open %s in read mode\n", our_prog_name, total_config_file);
47         } else {
48                 switch (read_file_config((void *)&p, fp)){
49
50                         case 0: /* No errors */
51                         fclose(fp);
52                         break; /* OBS An identical list of error code returns exist in the
53                                         main_setup.c file. So change both when altering. */
54
55                         case 1:
56                         fclose(fp);
57                         exit_on_error(errorfp, "%s ERROR: Reread - No complete record found in %s\n", our_prog_name, total_config_file);
58
59                         case 2:
60                         fclose(fp);
61                         exit_on_error(errorfp, "%s ERROR: Reread - Memory allocation error while parsing %s\n", our_prog_name, total_config_file);
62
63                         case 3:
64                         fclose(fp);
65                         exit_on_error(errorfp, "%s ERROR: Reread - Config File Version 3 or higher not found\n", our_prog_name, "");
66
67                         case 4:
68                         fclose(fp);
69                         exit_on_error(errorfp, "%s ERROR: Reread - A line was too long to handle in the Config File %s\n", our_prog_name, total_config_file);
70
71                         case 5:
72                         fclose(fp);
73                         exit_on_error(errorfp, "%s ERROR: Reread - A program record named \"default\" must exist in %s\n", our_prog_name, total_config_file);
74
75                         default:
76                         fclose(fp);
77                         exit_on_error(errorfp, "%s ERROR: Reread - Unknown error while parsing %s\n", our_prog_name, total_config_file);
78                 }
79         }
80         go_daemon = 0;
81         status_report(0); /* Update our information file */
82         go_daemon = 1;
83         fclose(errorfp);
84 }
85
86 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
87  Function acts as a signal handler replacement for SIGUSR2. On this
88  signal we print some choise information to a file and to the screen.
89  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
90
91 void status_report(int signum)
92 {
93
94         FILE *errorfp = NULL;
95         FILE *statusfp = NULL;
96         
97         struct program *p;
98         p = external_list;
99         int i;
100
101         errorfp = fopen(total_error_file, "w");
102
103 /* Open (and truncate) a status log and fill it with information */
104
105         if ((statusfp = fopen(total_status_file, "w")) == NULL) {
106                 exit_on_error(errorfp, "%s ERROR: Can not open %s in write mode\n", our_prog_name, total_status_file);
107         } else {
108                 fclose(errorfp);
109                 fprintf(statusfp, "PGR VERSION = %s\n", our_prog_version);
110                 fprintf(statusfp, "USR HOMEDIR = %s\n", getenv("HOME"));
111                 fprintf(statusfp, "OUR CNF-DIR = %s\n", total_config_dir);
112                 fprintf(statusfp, "OUR CNFFILE = %s\n", total_config_file);
113                 fprintf(statusfp, "OUR PIDFILE = %s\n", total_pid_file);
114                 fprintf(statusfp, "OUR INFFILE = %s\n", total_status_file);
115                 fprintf(statusfp, "OUR ERRFILE = %s\n", total_error_file);
116                 if (pad1_name) {
117                         fprintf(statusfp, "OUR PD1NAME = %s\n", pad1_name);
118                 }
119                 if (stylus1_name) {
120                         fprintf(statusfp, "OUR ST1NAME = %s\n", stylus1_name);
121                 }
122                 fprintf(statusfp, "%s-user = %d\n", configstring, userconfigversion);
123                 fprintf(statusfp, "%s-ours = %s\n", configstring, configversion);
124                 fprintf(statusfp, "ConfigHeaderFields = %d\n", configheaderfields);
125                 for (i = 0; i < num_list; i++, p++) {
126                         fprintf(statusfp, "PGR RECNAME = %s\n", p->class_name);
127                         fprintf(statusfp, "ST1 PRCURVE = \"%s\"\n", p->stylus1_presscurve);
128                 }
129                 fprintf(statusfp, "PGR RECORDS = %d\n", num_list);
130                 if (go_daemon) {
131                         fprintf(statusfp, "OUR RUN-PID = %d\n", getpid());
132                 }
133                 fclose(statusfp);
134         }
135
136 /* Also print the info to sceen (only if we have been daemonised and act on a -s signal) */
137
138         if (go_daemon) {
139                 p = external_list;
140                 fprintf(stderr, "PGR VERSION = %s\n", our_prog_version);
141                 fprintf(stderr, "USR HOMEDIR = %s\n", getenv("HOME"));
142                 fprintf(stderr, "OUR CNF-DIR = %s\n", total_config_dir);
143                 fprintf(stderr, "OUR CNFFILE = %s\n", total_config_file);
144                 fprintf(stderr, "OUR PIDFILE = %s\n", total_pid_file);
145                 fprintf(stderr, "OUR INFFILE = %s\n", total_status_file);
146                 fprintf(stderr, "OUR ERRFILE = %s\n", total_error_file);
147                 if (pad1_name) {
148                         fprintf(stderr, "OUR PD1NAME = %s\n", pad1_name);
149                 }
150                 if (stylus1_name) {
151                         fprintf(stderr, "OUR ST1NAME = %s\n", stylus1_name);
152                 }
153                 fprintf(stderr, "%s-user = %d\n", configstring, userconfigversion);
154                 fprintf(stderr, "%s-ours = %s\n", configstring, configversion);
155                 fprintf(stderr, "ConfigHeaderFields = %d\n", configheaderfields);
156                 for (i = 0; i < num_list; i++, p++) {
157                         fprintf(stderr, "PGR RECNAME = %s\n", p->class_name);
158                         fprintf(stderr, "ST1 PRCURVE = \"%s\"\n", p->stylus1_presscurve);
159                 }
160                 fprintf(stderr, "PGR RECORDS = %d\n", num_list);
161                 fprintf(stderr, "OUR RUN-PID = %d\n", getpid());
162         }
163 }
164
165 /*+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
166  Function acts as a signal handler replacement for SIGINT, SIGHUP and
167  SIGTERM. All are normal exit signals. We want to trap them in order to
168  perform some house keeping pre-exit. Delete a PID file and free memory
169  Since it takes care of several signals, it could get invoked recursively
170  if some other signal comes in. We use this "volatile" variable to track
171  the case. At the end we restore the default signal handler and raise it
172  +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
173
174 volatile sig_atomic_t clean_up_exit_in_progress = 0;
175 void clean_up_exit(int signum)
176 {
177         int i;
178         struct program *p;
179         p = external_list;
180
181         if (clean_up_exit_in_progress) {
182                 raise(signum);
183         }
184         clean_up_exit_in_progress = 1;
185
186         if (go_daemon) {
187                 unlink(total_pid_file);
188                 unlink(total_status_file);
189         }
190
191         if (total_config_dir) {
192                 free(total_config_dir);
193         }
194
195         if (total_config_file) {
196                 free(total_config_file);
197         }
198
199         if (total_pid_file) {
200                 free(total_pid_file);
201         }
202
203         if (total_error_file) {
204                 free(total_error_file);
205         }
206
207         if (total_status_file) {
208                 free(total_status_file);
209         }
210
211         if (num_list) {
212                 for (i = 0; i < num_list; i++, p++) {
213                         free(p->stylus1_presscurve);
214                         free(p->class_name);
215                 }
216         }
217
218         if (pad1_info_block) {
219                 XFreeDeviceList(pad1_info_block);
220         }
221
222         if (stylus1_info_block) {
223                 XFreeDeviceList(stylus1_info_block);
224         }
225
226 /* pad1_device and stylus1_device should not be explicitly closed by a
227    call to XCloseDevice. It leaves a message from X (in the terminal
228    where X is started from) saying: "ProcXCloseDevice to close or not ?"
229    Instead we just free the XDevice structures created by XOpenDevice */
230
231         if (pad1_device) {
232                 XFree(pad1_device);
233         }
234
235         if (stylus1_device) {
236                 XFree(stylus1_device);
237         }
238
239         if (display) {
240                 XCloseDisplay(display);
241         }
242
243         signal(signum, SIG_DFL);
244         raise(signum);
245 }
246
247 /* End Code */
248