Implemented new API function burn_set_signal_handling(), libburner uses it
This commit is contained in:
191
trunk/libburn/cleanup.c
Normal file
191
trunk/libburn/cleanup.c
Normal file
@ -0,0 +1,191 @@
|
||||
/*
|
||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
A signal handler which cleans up an application and exits.
|
||||
|
||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
||||
*/
|
||||
|
||||
/*
|
||||
cc -g -o cleanup -DCleanup_standalonE cleanup.c
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <signal.h>
|
||||
typedef void (*sighandler_t)(int);
|
||||
|
||||
|
||||
#include "cleanup.h"
|
||||
|
||||
/* Signals to be caught */
|
||||
static int signal_list[]= {
|
||||
SIGHUP, SIGINT, SIGQUIT, SIGILL, SIGABRT,
|
||||
SIGFPE, SIGSEGV, SIGPIPE, SIGALRM, SIGTERM,
|
||||
SIGUSR1, SIGUSR2, SIGXCPU, SIGTSTP, SIGTTIN,
|
||||
SIGTTOU,
|
||||
SIGBUS, SIGPOLL, SIGPROF, SIGSYS, SIGTRAP,
|
||||
SIGVTALRM, SIGXCPU, SIGXFSZ, -1
|
||||
};
|
||||
static char *signal_name_list[]= {
|
||||
"SIGHUP", "SIGINT", "SIGQUIT", "SIGILL", "SIGABRT",
|
||||
"SIGFPE", "SIGSEGV", "SIGPIPE", "SIGALRM", "SIGTERM",
|
||||
"SIGUSR1", "SIGUSR2", "SIGXCPU", "SIGTSTP", "SIGTTIN",
|
||||
"SIGTTOU",
|
||||
"SIGBUS", "SIGPOLL", "SIGPROF", "SIGSYS", "SIGTRAP",
|
||||
"SIGVTALRM", "SIGXCPU", "SIGXFSZ", "@"
|
||||
};
|
||||
static int signal_list_count= 24;
|
||||
|
||||
/* Signals not to be caught */
|
||||
static int non_signal_list[]= {
|
||||
SIGKILL, SIGCHLD, SIGSTOP, SIGURG, -1
|
||||
};
|
||||
static int non_signal_list_count= 4;
|
||||
|
||||
|
||||
/* run time dynamic part */
|
||||
static char cleanup_msg[4096]= {""};
|
||||
static int cleanup_exiting= 0;
|
||||
|
||||
static void *cleanup_app_handle= NULL;
|
||||
static Cleanup_app_handler_T cleanup_app_handler= NULL;
|
||||
static int cleanup_perform_app_handler_first= 0;
|
||||
|
||||
|
||||
static int Cleanup_handler_exit(int exit_value, int signum, int flag)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if(cleanup_perform_app_handler_first)
|
||||
if(cleanup_app_handler!=NULL) {
|
||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
||||
if(ret==2 || ret==-2)
|
||||
return(2);
|
||||
}
|
||||
if(cleanup_exiting) {
|
||||
if(cleanup_msg[0]!=0)
|
||||
fprintf(stderr,"%s\n",cleanup_msg);
|
||||
fprintf(stderr,"cleanup: ABORT : repeat by pid=%d, signum=%d\n",
|
||||
getpid(),signum);
|
||||
return(0);
|
||||
}
|
||||
cleanup_exiting= 1;
|
||||
if(cleanup_msg[0]!=0)
|
||||
fprintf(stderr,"\n%s\n",cleanup_msg);
|
||||
alarm(0);
|
||||
if(!cleanup_perform_app_handler_first)
|
||||
if(cleanup_app_handler!=NULL) {
|
||||
ret= (*cleanup_app_handler)(cleanup_app_handle,signum,0);
|
||||
if(ret==2 || ret==-2)
|
||||
return(2);
|
||||
}
|
||||
exit(exit_value);
|
||||
}
|
||||
|
||||
|
||||
static void Cleanup_handler_generic(int signum)
|
||||
{
|
||||
int i;
|
||||
|
||||
sprintf(cleanup_msg,"UNIX-SIGNAL caught: %d errno= %d",signum,errno);
|
||||
for(i= 0; i<signal_list_count; i++)
|
||||
if(signum==signal_list[i]) {
|
||||
sprintf(cleanup_msg,"UNIX-SIGNAL: %s errno= %d",
|
||||
signal_name_list[i],errno);
|
||||
break;
|
||||
}
|
||||
Cleanup_handler_exit(1,signum,0);
|
||||
}
|
||||
|
||||
|
||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler, int flag)
|
||||
/*
|
||||
bit0= set to default handlers
|
||||
bit1= set to ignore
|
||||
bit2= set cleanup_perform_app_handler_first
|
||||
bit3= set SIGABRT to handler (makes sense with bits 0 or 1)
|
||||
*/
|
||||
{
|
||||
int i,j,max_sig= -1,min_sig= 0x7fffffff;
|
||||
sighandler_t sig_handler;
|
||||
|
||||
cleanup_msg[0]= 0;
|
||||
cleanup_app_handle= handle;
|
||||
cleanup_app_handler= handler;
|
||||
|
||||
/* <<< make cleanup_exiting thread safe to get rid of this */
|
||||
if(flag&4)
|
||||
cleanup_perform_app_handler_first= 1;
|
||||
|
||||
|
||||
if(flag&1)
|
||||
sig_handler= SIG_DFL;
|
||||
else if(flag&2)
|
||||
sig_handler= SIG_IGN;
|
||||
else
|
||||
sig_handler= Cleanup_handler_generic;
|
||||
/* set all signal numbers between the lowest and highest in the list
|
||||
except those in the non-signal list */
|
||||
for(i= 0; i<signal_list_count; i++) {
|
||||
if(signal_list[i]>max_sig)
|
||||
max_sig= signal_list[i];
|
||||
if(signal_list[i]<min_sig)
|
||||
min_sig= signal_list[i];
|
||||
}
|
||||
for(i= min_sig; i<=max_sig; i++) {
|
||||
for(j= 0; j<non_signal_list_count; j++)
|
||||
if(i==non_signal_list[j])
|
||||
break;
|
||||
if(j>=non_signal_list_count) {
|
||||
if(i==SIGABRT && (flag&8))
|
||||
signal(i,Cleanup_handler_generic);
|
||||
else
|
||||
signal(i,sig_handler);
|
||||
}
|
||||
}
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
#ifdef Cleanup_standalonE
|
||||
|
||||
struct Demo_apP {
|
||||
char *msg;
|
||||
};
|
||||
|
||||
|
||||
int Demo_app_handler(struct Demo_apP *demoapp, int signum, int flag)
|
||||
{
|
||||
printf("Handling exit of demo application on signal %d. msg=\"%s\"\n",
|
||||
signum,demoapp->msg);
|
||||
return(1);
|
||||
}
|
||||
|
||||
|
||||
main()
|
||||
{
|
||||
struct Demo_apP demoapp;
|
||||
|
||||
demoapp.msg= "Good Bye";
|
||||
Cleanup_set_handlers(&demoapp,(Cleanup_app_handler_T) Demo_app_handler,0);
|
||||
|
||||
if(1) { /* change to 0 in order to wait for external signals */
|
||||
char *cpt= NULL,c;
|
||||
printf("Intentionally provoking SIGSEGV ...\n");
|
||||
c= *cpt;
|
||||
} else {
|
||||
printf("killme: %d\n",getpid());
|
||||
sleep(3600);
|
||||
}
|
||||
|
||||
Cleanup_set_handlers(NULL,NULL,1);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
#endif /* Cleanup_standalonE */
|
34
trunk/libburn/cleanup.h
Normal file
34
trunk/libburn/cleanup.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
cleanup.c , Copyright 2006 Thomas Schmitt <scdbackup@gmx.net>
|
||||
|
||||
A signal handler which cleans up an application and exits.
|
||||
|
||||
Provided under GPL license within GPL projects, BSD license elsewise.
|
||||
*/
|
||||
|
||||
#ifndef Cleanup_includeD
|
||||
#define Cleanup_includeD 1
|
||||
|
||||
|
||||
/** Layout of an application provided cleanup function using an application
|
||||
provided handle as first argument and the signal number as second
|
||||
argument. The third argument is a flag bit field with no defined bits yet.
|
||||
If the handler returns 2 or -2 then it has delegated exit() to some other
|
||||
instance and the Cleanup handler shall return rather than exit.
|
||||
*/
|
||||
typedef int (*Cleanup_app_handler_T)(void *, int, int);
|
||||
|
||||
|
||||
/** Establish exiting signal handlers on (hopefully) all signals that are
|
||||
not ignored by default or non-catchable.
|
||||
@param handle Opaque object which knows how to cleanup application
|
||||
@param handler Function which uses handle to perform application cleanup
|
||||
@param flag Control Bitfield
|
||||
bit0= reset to default signal handling
|
||||
*/
|
||||
int Cleanup_set_handlers(void *handle, Cleanup_app_handler_T handler,
|
||||
int flag);
|
||||
|
||||
|
||||
#endif /* ! Cleanup_includeD */
|
||||
|
@ -38,6 +38,15 @@ int burn_sg_open_o_nonblock = 1;
|
||||
int burn_sg_open_abort_busy = 0;
|
||||
|
||||
|
||||
/* ts A61002 */
|
||||
|
||||
#include "cleanup.h"
|
||||
|
||||
/* Parameters for builtin abort handler */
|
||||
static char abort_message_prefix[81] = {"libburn : "};
|
||||
static pid_t abort_control_pid= 0;
|
||||
|
||||
|
||||
/* ts A60925 : ticket 74 */
|
||||
/** Create the messenger object for libburn. */
|
||||
int burn_msgs_initialize(void)
|
||||
@ -197,3 +206,40 @@ ex:
|
||||
return ret;
|
||||
}
|
||||
|
||||
int burn_builtin_abort_handler(void *handle, int signum, int flag)
|
||||
{
|
||||
if(getpid() != abort_control_pid)
|
||||
return -2;
|
||||
Cleanup_set_handlers(NULL, NULL, 2);
|
||||
fprintf(stderr,"%sABORT : Trying to shut down drive and library\n",
|
||||
abort_message_prefix);
|
||||
fprintf(stderr,
|
||||
"%sABORT : Wait the normal burning time before any kill -9\n",
|
||||
abort_message_prefix);
|
||||
close(0); /* somehow stdin as input blocks abort until EOF */
|
||||
burn_abort(4440, burn_abort_pacifier, abort_message_prefix);
|
||||
fprintf(stderr,
|
||||
"\n%sABORT : Program done. Even if you do not see a shell prompt.\n\n",
|
||||
abort_message_prefix);
|
||||
return(1);
|
||||
}
|
||||
|
||||
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
||||
int mode)
|
||||
{
|
||||
if(handler == NULL && mode == 0) {
|
||||
handler = burn_builtin_abort_handler;
|
||||
/*
|
||||
fprintf(stderr, "libburn_experimental: activated burn_builtin_abort_handler() with handle '%s'\n",(handle==NULL ? "libburn : " : (char *) handle));
|
||||
*/
|
||||
|
||||
}
|
||||
strcpy(abort_message_prefix, "libburn : ");
|
||||
if(handle != NULL)
|
||||
strncpy(abort_message_prefix, (char *) handle,
|
||||
sizeof(abort_message_prefix)-1);
|
||||
abort_message_prefix[sizeof(abort_message_prefix)-1] = 0;
|
||||
abort_control_pid= getpid();
|
||||
Cleanup_set_handlers(handle, (Cleanup_app_handler_T) handler, mode|4);
|
||||
}
|
||||
|
||||
|
@ -392,7 +392,14 @@ int burn_initialize(void);
|
||||
void burn_finish(void);
|
||||
|
||||
|
||||
/* ts A61002 */
|
||||
/** Abort any running drive operation and finally call burn_finish().
|
||||
You MUST calm down the busy drive if an aborting event occurs during a
|
||||
burn run. For that you may call this function either from your own signal
|
||||
handling code or indirectly by activating the builtin signal handling:
|
||||
burn_set_signal_handling("my_app_name : ", NULL, 0);
|
||||
Else you may eventually call burn_drive_cancel() on the active drive and
|
||||
wait for it to assume state BURN_DRIVE_IDLE.
|
||||
@param patience Maximum number of seconds to wait for drives to finish
|
||||
@param pacifier_func If not NULL: a function to produce appeasing messages.
|
||||
See burn_abort_pacifier() for an example.
|
||||
@ -406,6 +413,8 @@ int burn_abort(int patience,
|
||||
|
||||
/** A pacifier function suitable for burn_abort.
|
||||
@param handle If not NULL, a pointer to a text suitable for printf("%s")
|
||||
@param patience Maximum number of seconds to wait
|
||||
@param elapsed Elapsed number of seconds
|
||||
*/
|
||||
int burn_abort_pacifier(void *handle, int patience, int elapsed);
|
||||
|
||||
@ -1071,6 +1080,29 @@ int burn_msgs_obtain(char *minimum_severity,
|
||||
char severity[]);
|
||||
|
||||
|
||||
/* ts A61002 */
|
||||
/* The prototype of a handler function suitable for burn_set_abort_handling().
|
||||
Such a function has to return -2 if it does not want the process to
|
||||
exit with value 1.
|
||||
*/
|
||||
typedef int (*burn_abort_handler_t)(void *handle, int signum, int flag);
|
||||
|
||||
/** Control builtin signal handling. See also burn_abort().
|
||||
@param handle Opaque handle eventually pointing to an application
|
||||
provided memory object
|
||||
@param handler A function to be called on signals. It will get handle as
|
||||
argument. It should finally call burn_abort(). See there.
|
||||
@param mode : 0 call handler(handle, signum, 0) on nearly all signals
|
||||
1 enable system default reaction on all signals
|
||||
2 try to ignore nearly all signals
|
||||
10 like mode 2 but handle SIGABRT like with mode 0
|
||||
Arguments (text, NULL, 0) activate the builtin abort handler. It will
|
||||
eventually call burn_abort() and then perform exit(1). If text is not NULL
|
||||
then it is used as prefix for pacifier messages of burn_abort_pacifier().
|
||||
*/
|
||||
void burn_set_signal_handling(void *handle, burn_abort_handler_t handler,
|
||||
int mode);
|
||||
|
||||
#ifndef DOXYGEN
|
||||
|
||||
BURN_END_DECLS
|
||||
|
Reference in New Issue
Block a user