diff --git a/coredump.c b/coredump.c index f24d153..d4b3ba0 100644 --- a/coredump.c +++ b/coredump.c @@ -1,3 +1,4 @@ +// vim: set noet sw=2 ts=2 sts=2: #define _GNU_SOURCE #include #include @@ -11,8 +12,6 @@ #include typedef struct argv_t { - char *_self; - char *coredir; char *pid; // %p char *global_pid; // %P char *tid; // %i @@ -30,7 +29,8 @@ typedef struct argv_t { char *cpu; // %C } argv_t; -const char const expected_pattern[] = "|%s %%p %%P %%i %%I %%u %%g %%d %%s %%t %%h %%e %%f %%E %%c %%C"; +const char const expected_pattern[] = "|%s [-d DESTDIR] [-a EXEPATH] %%p %%P %%i %%I %%u %%g %%d %%s %%t %%h %%e %%f %%E %%c %%C"; +const unsigned int const expected_argc = 15; typedef char *path_t; @@ -52,6 +52,8 @@ typedef struct args_t { path_t exepath; size_t max_size; uint cpu; + path_t after; + char corefile[1024]; } args_t; // if max_size is 0 or bigger than MAX_SIZE, then MAX_SIZE (1GiB): #define MAX_SIZE 1073741824 @@ -82,7 +84,6 @@ int prsint( long unsigned int *dst, char *src) { int argv2args( argv_t *v, args_t *s) { long unsigned int b; - TOSTR( coredir); TOINT( pid); TOINT( global_pid); TOINT( tid); @@ -100,8 +101,8 @@ int argv2args( argv_t *v, args_t *s) { TOINT( cpu); } -int proc_filename( char *dest, size_t len, argv_t *argv, char* fn) { - size_t destl = snprintf( dest, len, "/proc/%s/%s", argv->pid, fn); +int proc_filename( char *dest, size_t len, args_t *args, char* fn) { + size_t destl = snprintf( dest, len, "/proc/%i/%s", args->pid, fn); if( destl < 0) { fprintf( stderr, "ERROR: gen path for %s: %s (%i)\n", fn, strerror( errno), errno); return 1; @@ -113,8 +114,8 @@ int proc_filename( char *dest, size_t len, argv_t *argv, char* fn) { return 0; } -int core_filename( char *dest, size_t len, argv_t *argv, char* ext) { - size_t destl = snprintf( dest, len, "%s/core%s.%s", argv->coredir, ext, argv->pid); +int core_filename( char *dest, size_t len, args_t *args, char* ext) { + size_t destl = snprintf( dest, len, "%s/core%s.%u", args->coredir, ext, args->pid); if( destl < 0) { fprintf( stderr, "ERROR: gen path for core%s: %s (%i)\n", ext, strerror( errno), errno); return 1; @@ -145,25 +146,23 @@ void show_opened_files() { } } -int dump_core( argv_t *argv, args_t *args) { +int dump_core( args_t *args) { // Concept: Once used, not necessary anymore, we cen reuse the space again. - char path[1024]; // For any paths. - int rfd; // read file handler. int wfd; // write file handler. struct stat stat; // Needed for determine size of file. // copy stdin -> core.pid - if( core_filename( path, sizeof path, argv, "")) + if( core_filename( args->corefile, sizeof args->corefile, args, "")) return 1; - if( -1 == (wfd = open( path, O_WRONLY | O_CREAT | O_TRUNC, 0600))) { - fprintf( stderr, "ERROR: Cannot open file %s: %s (%i)\n", path, strerror( errno), errno); + if( -1 == (wfd = open( args->corefile, O_WRONLY | O_CREAT | O_TRUNC, 0600))) { + fprintf( stderr, "ERROR: Cannot open file %s: %s (%i)\n", args->corefile, strerror( errno), errno); return 1; } if( -1 == splice( STDIN_FILENO, 0, wfd, 0, (args->max_size || MAX_SIZE < args->max_size) ? args->max_size : MAX_SIZE, 0)) { - fprintf( stderr, "ERROR: Cannot write core to file %s: %s (%i)\n", path, strerror( errno), errno); + fprintf( stderr, "ERROR: Cannot write core to file %s: %s (%i)\n", args->corefile, strerror( errno), errno); return 1; } close( wfd); @@ -185,7 +184,7 @@ int copy_fd_to_fd( int infd, int outfd) { } } -int dump_cmdline( argv_t *argv, args_t *args) { +int dump_cmdline( args_t *args) { // Concept: Once used, not necessary anymore, we cen reuse the space again. char path[1024]; // For any paths. int rfd; // read file handler. @@ -193,7 +192,7 @@ int dump_cmdline( argv_t *argv, args_t *args) { struct stat stat; // Needed for determine size of file. // copy /proc/pid/cmdline -> core-cmdline.pid - if( proc_filename( path, sizeof path, argv, "cmdline")) return 1; + if( proc_filename( path, sizeof path, args, "cmdline")) return 1; if( -1 == (rfd = open( path, O_RDONLY, 0644))) { fprintf( stderr, "ERROR: Cannot open file %s: %s (%i)\n", path, strerror( errno), errno); return 1; @@ -202,7 +201,7 @@ int dump_cmdline( argv_t *argv, args_t *args) { fprintf( stderr, "ERROR: Cannot stat of file %s: %s (%i)\n", path, strerror( errno), errno); return 1; } - if( core_filename( path, sizeof path, argv, "-cmdline")) return 1; + if( core_filename( path, sizeof path, args, "-cmdline")) return 1; if( -1 == (wfd = open( path, O_WRONLY | O_CREAT | O_TRUNC, 0644))) { fprintf( stderr, "ERROR: Cannot open file %s: %s (%i)\n", path, strerror( errno), errno); return 1; @@ -223,13 +222,13 @@ int dump_cmdline( argv_t *argv, args_t *args) { fprintf( stderr, "ERROR: Cannot write to file %s: %s (%i)\n", path, strerror( errno), errno); \ return 1; \ } -int dump_md( argv_t *argv) { +int dump_md( argv_t *argv, args_t *args) { // Concept: Once used, not necessary anymore, we cen reuse the space again. char path[1024]; // For any paths. FILE *wfh; // write argv -> core-md.pid - if( core_filename( path, sizeof path, argv, "-md")) return 1; + if( core_filename( path, sizeof path, args, "-md")) return 1; umask( 0133); if( NULL == (wfh = fopen( path, "w"))) { fprintf( stderr, "ERROR: Cannot open file %s: %s (%i)\n", path, strerror( errno), errno); @@ -255,31 +254,78 @@ int dump_md( argv_t *argv) { return 0; } -int main( size_t argc, argv_t *argv) { - args_t *args = malloc( sizeof (args_t)); - args->_self = realpath( argv->_self, NULL); +int usage( args_t *args) { + fprintf( stderr, "Usage in kernel.core_pattern=\""); + fprintf( stderr, expected_pattern, args->_self); + fprintf( stderr, "\"\n"); + if( '/' != args->_self[0]) + fprintf( stderr, "\tAttention: Absolut path instead of %s should be used!\n", args->_self); + fprintf( stderr, "\n -a EXEPATH\tExecutes EXEPATH after dumping core as child process, before itself exits.\n"); + fprintf( stderr, "\t\tAs arguments, the path to core-file will be provided.\n"); + fprintf( stderr, " -d DESTDIR\tDestination directory for core-files and additional files. (default: /var/cores)\n"); + exit(2); +} - if( (sizeof (argv_t))/(sizeof (char*)) > argc) { - fprintf( stderr, "ERROR: %li arguments expected. Exect value of kernel.core_pattern must be: `", (sizeof (argv_t))/(sizeof (char*))); - fprintf( stderr, expected_pattern, args->_self); - fprintf( stderr, "`. Given: %li\n", argc-1); - if( '/' != args->_self[0]) - fprintf( stderr, "\tAttention: Absolut path instead of %s should be used!\n", args->_self); - return 2; +void run_after( args_t *args) { + if( args->after) { + pid_t child = fork(); + switch( child) { + case -1: + fprintf( stderr, "ERROR: error while forking: %s (%i)\n", strerror( errno), errno); + break; + case 0: + execl( args->after, args->after, args->corefile, NULL); + fprintf( stderr, "ERROR: Executing after-program failed: %s (%i)\n", strerror( errno), errno); + exit( 2); + } + } +} + +void parse_args( size_t argc, char** _argv, argv_t **argv, args_t *args) { + args->after = NULL; + args->coredir = "/var/cores"; + args->_self = realpath( _argv[0], NULL); + + char opt; + while( -1 != (opt = getopt( argc, _argv, "hd:a:"))) { + switch( opt) { + case 'h': usage( args); break; + case 'a': args->after = optarg; break; + case 'd': args->coredir = optarg; break; + default: + fprintf( stderr, "ERROR: Unknown option: -%c\n", opt); + usage( args); + } } - argv2args( argv, args); + if( expected_argc > argc-optind+1) { + fprintf( stderr, "ERROR: %u arguments expected. Given: %li\n", expected_argc, argc-optind+1); + usage( args); + exit(2); + } + + *argv = (argv_t*) (_argv + optind); + argv2args( *argv, args); +} + +int main( size_t argc, char **_argv) { + argv_t *argv = malloc( sizeof (argv_t)); + args_t *args = malloc( sizeof (args_t)); + parse_args( argc, _argv, &argv, args); //fprintf( stderr, "dump core...\n"); - dump_core( argv, args); + dump_core( args); // That's all, core dump written. :) // But, hold on, now the funny things will follow, which are the differences to a simple core-dump. //fprintf( stderr, "dump cmdline...\n"); - dump_cmdline( argv, args); + dump_cmdline( args); //fprintf( stderr, "dump metadata...\n"); - dump_md( argv); - //fprintf( stderr, "exit...\n"); + dump_md( argv, args); + //fprintf( stderr, "run after program...\n"); + run_after( args); + + //fprintf( stderr, "exit...\n"); return 0; }