-
Notifications
You must be signed in to change notification settings - Fork 0
/
signal_handle.c
421 lines (386 loc) · 11.9 KB
/
signal_handle.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
/*
* signal_handle.c
* This is to manipulate signals.
* Created on: Aug 5, 2015
* Author: tientham
*/
/*
Author note: 1. update pid condition in wait_child_termination()
*/
#include "serial_ip.h"
int signo_child = 0; /* Global child signal, 0 by default. */
/*
Location: signal_handle.c
This is a generic signal handler. Log which signal occurred, tidy up a bit, then we terminate.
does not return.
*/
void child_sighandler(int signal)
{
extern int gsockfd; /* global copy of sockfd */
syslog(LOG_ERR,"signal_handle.c: child_sighandler: received signal %d (%s)", signal, signame(signal));
if (gsockfd >= 0)
disconnect(gsockfd);
_exit(128 + signal);
}
/*
Location: signal_handle.c
this function is called from handle_pending_signal() upon receipt of a SIGINT
*/
void telnet_sigint(void)
{
extern int break_signaled;
extern unsigned char linestate;
break_signaled = 1;
linestate |= CPC_LINESTATE_BREAK_DETECT;
}
/*
Location: signal_handle.c
This is to handle a pending signal.
*/
void child_pending_signal_handle(void)
{
extern int signo_child; /* what signal did we receive? */
switch (signo_child) {
case 0: /* none */
break;
case SIGINT: /* serial/modem break condition */
telnet_sigint();
break;
case SIGUSR1:
action_sigusr1(signo_child); /* increment debug level */
break;
case SIGUSR2:
action_sigusr2(signo_child); /* decrement debug level */
break;
default:
child_sighandler(signo_child); /* does not return */
break;
}
signo_child = 0; /* clear pending signal; very important! */
}
/*
Location: signal_handle.c
this is our generic signal handling function for the child process. it gets called for any signal we care to handle and simply sets the
global signo_child variable to the signal number.
it's then up to code elsewhere in the system to check signo_child and act accordingly.
*/
void child_signal_received(int signal)
{
extern int signo_child; /* Global variable for child signal. */
signo_child = signal;
}
/*
Location: signal_handle.c
This is to reset the signal handlers that a child inherited from
its parent, except for SIGCHLD.
No return value.
*/
void reset_signals(void)
{
extern int signo_child; /* what signal did we receive? */
struct sigaction act; /* for signals */
act.sa_handler = &child_signal_received; /* function to handle signals */
sigemptyset(&act.sa_mask); /* required before sigaction() */
act.sa_flags = 0; /* no SA_RESTART */
sigaction(SIGTERM,&act,NULL); /* same handler for all 5 signals */
sigaction(SIGINT,&act,NULL);
sigaction(SIGQUIT,&act,NULL);
sigaction(SIGHUP,&act,NULL);
sigaction(SIGUSR1,&act,NULL);
sigaction(SIGUSR2,&act,NULL);
sigaction(SIGPIPE,&act,NULL);
signo_child = 0; /* default. */
}
/*
Location: signal_handle.c
This function is to use waitpid().
With the flag WNOHANG and pid = -1;
Return value:
-1 on error/unsuccessful.
0 if no child status information available which means child does not terminated yet.
>0 if sucessful, and the return value is the PID of child terminated.
On sucessful, the status of child terminated will be point to the pointer "status".
*/
pid_t wait_child_termination(pid_t pid, int *child_status)
{
extern int errno;
pid_t ret;
int *status;
int wstatus;
/*We need a new status variable for storing child process information.
* if child_status is available, create a new status pointer.
* Otherwise, use it.*/
if (child_status != (int *) NULL)
{
status = child_status; /* Use given child_status cose it has no information. */
} else {
status = &wstatus; /* Using new status for storing child process terminated information. */
}
/*
waitpid with flag WNOHANG will put the calling being non-blocked during the systemcall waitpid().
*/
ret = waitpid(pid,status,WNOHANG);
if ((ret == (pid_t) 0) && (pid == (pid_t) -1)) /*Author note: update pid condition!!!!*/
{
/*
Status not yet available for specified pid.
we'll wait a second and try again
*/
syslog(LOG_DEBUG,"signal_handle.c: wait_child_termination() returned 0; will try again");
sleep(1);
ret = waitpid(pid,status,WNOHANG);
}
if (ret == (pid_t) -1)
{
if (errno == ECHILD)
{
; /* syslog(LOG_DEBUG,"signal_handle.c: wait_child_termination(): no more child processes"); */
} else {
system_errorlog("signal_handle.c: wait_child_termination() error");
}
} else {
if (ret > 0) /* On successful.*/
{
log_termination_status(ret, *status);
}
}
return(ret);
}
/*
Location: signal_handle.c
interpret a child's exit status and send the
result to the syslog
*/
void log_termination_status(pid_t pid, int status)
{
char *str;
str = "child PID";
if (WIFEXITED(status))
{
syslog(LOG_ERR, "signal_handle.c: log_termination_status(): %s %d terminated normally by calling exit(%d)",
str, pid, WEXITSTATUS(status));
} else if (WIFSIGNALED(status))
{
syslog(LOG_ERR,"signal_handle.c: log_termination_status(): %s %d terminated by unhandled %s signal (number %d)",
str, pid, signame(WTERMSIG(status)), WTERMSIG(status));
} else
{
syslog(LOG_ERR,"signal_handle.c: log_termination_status(): %s %d unknown termination status, value: %d",
str, pid, status);
}
}
/*
Location: signal_handle.c
This function is to define a propriate action for SIGTERM, SIGINT, SIGQUIT.
returns nothing.
*/
void action_sigterm(int signal)
{
struct sigaction sa;
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"signal_handle.c: action_sigterm() received signal %d (%s)",signal,signame(signal));
program_clean_up(); /* close everything */
sa.sa_handler = SIG_DFL; /* set default handler for signal*/
sigemptyset(&sa.sa_mask); /* required before sigaction() */
sa.sa_flags = 0; /* signal is fatal, so no SA_RESTART */
sigaction(SIGTERM,&sa,NULL);
/* kill parent process.*/
kill(0,SIGTERM); /* kill(int pid, int signum) */
}
/*
Location: signal_handle.c
This function is to define a propriate action for SIGHUP.
SIGHUP is to re-initialize our program.
returns nothing.
*/
void action_sighup(int signal)
{
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"received signal %d (%s)",signal,signame(signal));
program_clean_up(); /* close everything */
serial_ip_init(); /* initialization program. */
}
/*
Location: signal_handle.c
This function is to handle the SIGCLD signal.
We collect the child process's termination status and log it.
This is important to keep track of zoombie processes.
returns nothing.
*/
void action_sigchild(int signal)
{
pid_t pid; /* pid of child */
int status; /* child's termination status */
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"received signal %d (%s)",signal,signame(signal));
while (1) {
pid = wait_child_termination((pid_t) -1, &status); /* get pid and child's status (note: status now is not available yet).
-1 for the calling process wait for any child process terminate. */
if (pid == -1) {
if (errno == EINTR) { /* wait() interrupted by a signal */
continue; /* wait() again */
} else { /* errno == ECHILD, no more children */
break;
}
} else if (pid == (pid_t) 0) { /* no status available */
break;
} else { /* got pid and status */
; /* nothing to do */
}
}
}
/*
Location: signal_handle.c
This function is to handle the SIGPIPE signal.
This is signal comming from kernel, we just need to get a system log for debugging.
returns nothing.
*/
void action_sigpipe(int signal)
{
/* log this at the ERR level to be sure it reaches the log */
syslog(LOG_ERR,"signal_handle.c: action_sigpipe() received signal %d (%s)",signal,signame(signal));
}
/*
Location: signal_handle.c
sigusr1() and sigusr2() provide a means for us to change
the debug level on the fly.
*/
/*
Location: signal_handle.c
This is to handle SIGUSR1.
Action: Increment the debug level.
*/
void action_sigusr1(int signal)
{
int level;
/*
increment the debug level
*/
level = get_debug_level();
if (level < DBG_LV9) {
++level;
set_debug_level(level);
}
/* log this at the LOG_ERR level to be sure it reaches the log */
syslog(LOG_ERR,"Received %s signal. Debug level now %d.",signame(signal),level);
}
/*
Location: signal_handle.c
This is to handle SIGUSR2.
Action: Decrement the debug level.
*/
void action_sigusr2(int signal)
{
int level;
/*
decrement the debug level
*/
level = get_debug_level();
if (level > DBG_LV0) {
--level;
set_debug_level(level);
}
/* log this at the LOG_ERR level to be sure it reaches the log */
syslog(LOG_ERR,"Received %s signal. Debug level now %d.",signame(signal),level);
}
/*
Location: signal_handler.c
This is to handle signal received inside parent process.
Receive the signal and return nothing.
*/
void parent_signal_received(int signal)
{
extern int signo; /* signo is global variable for signal we get */
switch (signal)
{
case SIGTERM:
case SIGINT:
case SIGQUIT:
action_sigterm(signal); /* does not return */
break;
case SIGHUP:
action_sighup(signal); /* re-read config file */
break;
case SIGCLD:
action_sigchild(signal); /* child process died */
break;
case SIGPIPE:
action_sigpipe(signal);
break;
case SIGUSR1:
action_sigusr1(signal); /* increment debug level */
break;
case SIGUSR2:
action_sigusr2(signal); /* decrement debug level */
break;
}
signo = signal; /* save signal number in global var */
}
/*
Location: signal_handle.c
This function is to install signal handlers for SIGTERM, SIGINT, SIGQUIT, SIGHUP, SIGCLD
SIGUSR1, SIGUSR2, and SIGPIPE.
a sigaction(SIGTERM,&sa,NULL) means we define signal handler for SIGTERM which will perform "sa" function.
Procedure here is:
1. Define a signal struct "sa" which is a function action for a specific signal.
2. Initialization by allocating "sa" structure with block of '0'.
3. Direct sa_handler field of "sa" to our defined function action which we want a specific signal do.
4. Calling function "sigaction(SIGNAL, &sa, NULL).
5. ...Our code...
*/
void install_signal_handlers(void)
{
struct sigaction sa;
//memset(sa, 0, sizeof(sa));
sa.sa_handler = &parent_signal_received; /* function to handle all signals */
/* we NEED signals to interrupt system calls, so don't specify SA_RESTART */
sigemptyset(&sa.sa_mask); /* Initialize signal set, it exclude all predefined signal, required before sigaction() */
sa.sa_flags = 0; /* no SA_RESTART */
sigaction(SIGTERM, &sa, NULL);
sigaction(SIGINT, &sa, NULL);
sigaction(SIGQUIT, &sa, NULL);
sigaction(SIGHUP, &sa, NULL);
sigaction(SIGCLD, &sa, NULL);
sigaction(SIGUSR1, &sa, NULL);
sigaction(SIGUSR2, &sa, NULL);
sigaction(SIGPIPE, &sa, NULL);
syslog(LOG_INFO,"signal_handle.c: installed signal handlers");
}
/*
Location: signal_handle.c
This is to return a pointer to a name of a supplied signal.
*/
char *signame(int signal)
{
register char *p = NULL;
switch (signal) {
case SIGHUP: p = "SIGHUP"; break;
case SIGINT: p = "SIGINT"; break;
case SIGQUIT: p = "SIGQUIT"; break;
case SIGILL: p = "SIGILL"; break;
case SIGTRAP: p = "SIGTRAP"; break;
case SIGABRT: p = "SIGABRT"; break;
case SIGFPE: p = "SIGFPE"; break;
case SIGKILL: p = "SIGKILL"; break;
case SIGBUS: p = "SIGBUS"; break;
case SIGSEGV: p = "SIGSEGV"; break;
case SIGPIPE: p = "SIGPIPE"; break;
case SIGALRM: p = "SIGALRM"; break;
case SIGTERM: p = "SIGTERM"; break;
case SIGUSR1: p = "SIGUSR1"; break;
case SIGUSR2: p = "SIGUSR2"; break;
case SIGCLD: p = "SIGCLD"; break;
case SIGPWR: p = "SIGPWR"; break;
case SIGWINCH: p = "SIGWINCH"; break;
case SIGPOLL: p = "SIGPOLL"; break;
case SIGSTOP: p = "SIGSTOP"; break;
case SIGTSTP: p = "SIGTSTP"; break;
case SIGCONT: p = "SIGCONT"; break;
case SIGTTIN: p = "SIGTTIN"; break;
case SIGTTOU: p = "SIGTTOU"; break;
case SIGVTALRM: p = "SIGVTALRM"; break;
case SIGPROF: p = "SIGPROF"; break;
default: p = "unexpected"; break;
}
return(p);
}