From 2322eb0625ebab972fbbd78cbccfca7ff0afaab5 Mon Sep 17 00:00:00 2001 From: Sebastien Helleu Date: Sat, 20 May 2006 13:42:08 +0000 Subject: [PATCH] Automatically rename log file when crashing, added backtrace to log file --- ChangeLog | 2 +- src/common/backtrace.c | 55 +++++++++++---- src/common/log.c | 119 +++++++++++++++++++++++++++------ src/common/log.h | 3 +- src/common/weechat.c | 9 ++- weechat/ChangeLog | 2 +- weechat/src/common/backtrace.c | 55 +++++++++++---- weechat/src/common/log.c | 119 +++++++++++++++++++++++++++------ weechat/src/common/log.h | 3 +- weechat/src/common/weechat.c | 9 ++- 10 files changed, 294 insertions(+), 82 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5cc9b310a..8a5f3fa0b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -4,7 +4,7 @@ WeeChat - Wee Enhanced Environment for Chat ChangeLog - 2006-05-20 Version 0.1.9 (under dev!): - * added backtrace when WeeChat crashes + * added backtrace when WeeChat crashes, log file automatically renamed * added lock for log file (~/.weechat/weechat.log), only one WeeChat process can use this file (bug #16382) * fixed crash with malformed UTF-8 strings diff --git a/src/common/backtrace.c b/src/common/backtrace.c index d94de3432..98235f5e4 100644 --- a/src/common/backtrace.c +++ b/src/common/backtrace.c @@ -27,6 +27,7 @@ #include #include #include +#include #define __USE_GNU #include @@ -36,8 +37,27 @@ #include "weechat.h" #include "backtrace.h" +#include "log.h" +/* + * weechat_backtrace_printf: display a backtrage line (on stderr and in WeeChat log) + */ + +void +weechat_backtrace_printf (char *message, ...) +{ + static char buffer[4096]; + va_list argptr; + + va_start (argptr, message); + vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); + va_end (argptr); + + fprintf (stderr, "%s", buffer); + weechat_log_printf ("%s", buffer); +} + /* * weechat_backtrace_addr2line: display function name and line with a backtrace address */ @@ -57,7 +77,7 @@ weechat_backtrace_addr2line (int number, void *address, char *symbol) rc = dladdr (address, &info); if ((rc == 0) || !info.dli_fname || !info.dli_fname[0]) { - fprintf (stderr, "%03d %s\n", number, symbol); + weechat_backtrace_printf ("%03d %s\n", number, symbol); return; } @@ -71,7 +91,7 @@ weechat_backtrace_addr2line (int number, void *address, char *symbol) output = popen (cmd_line, "r"); if (!output) { - fprintf (stderr, "%03d %s\n", number, symbol); + weechat_backtrace_printf ("%03d %s\n", number, symbol); return; } function_name[0] = '\0'; @@ -87,25 +107,27 @@ weechat_backtrace_addr2line (int number, void *address, char *symbol) if (strchr (ptr_line, ':')) { file_line = 1; - fprintf (stderr, "%03d %s%s%s%s\n", - number, - ptr_line, - (function_name[0]) ? " [function " : "", - function_name, - (function_name[0]) ? "]" : ""); + weechat_backtrace_printf ("%03d %s%s%s%s\n", + number, + ptr_line, + (function_name[0]) ? " [function " : "", + function_name, + (function_name[0]) ? "]" : ""); function_name[0] = '\0'; } else { if (function_name[0]) - fprintf (stderr, "%03d %s", number, function_name); + weechat_backtrace_printf ("%03d %s", + number, function_name); snprintf (function_name, sizeof (function_name), "%s", ptr_line); } } } if (function_name[0]) - fprintf (stderr, "%03d %s\n", number, function_name); + weechat_backtrace_printf ("%03d %s\n", + number, function_name); pclose (output); } @@ -120,7 +142,11 @@ weechat_backtrace () void *trace[BACKTRACE_MAX]; int trace_size, i; char **symbols; - +#endif + + weechat_backtrace_printf ("======= WeeChat backtrace =======\n"); + +#ifdef HAVE_BACKTRACE trace_size = backtrace (trace, BACKTRACE_MAX); symbols = backtrace_symbols (trace, trace_size); @@ -129,8 +155,9 @@ weechat_backtrace () weechat_backtrace_addr2line (i + 1, trace[i], symbols[i]); } #else - fprintf (stderr, - " No backtrace info (no debug info available or no backtrace possible " - "on your system).\n"); + weechat_backtrace_printf (" No backtrace info (no debug info available " + "or no backtrace possible on your system).\n"); #endif + + weechat_backtrace_printf ("======= End of backtrace =======\n"); } diff --git a/src/common/log.c b/src/common/log.c index 3403c7d87..85adea885 100644 --- a/src/common/log.c +++ b/src/common/log.c @@ -25,17 +25,63 @@ #endif #include +#include #include #include #include +#include #include "weechat.h" #include "log.h" -FILE *weechat_log_file = NULL; /* WeeChat log file (~/.weechat/weechat.log) */ +char *weechat_log_filename = NULL; /* log name (~/.weechat/weechat.log) */ +FILE *weechat_log_file = NULL; /* WeeChat log file */ +/* + * weechat_log_open: initialize log file + */ + +int +weechat_log_open (char *filename, char *mode) +{ + int filename_length; + + /* exit if log already opened */ + if (weechat_log_file) + return 0; + + if (filename) + weechat_log_filename = strdup (filename); + else + { + filename_length = strlen (weechat_home) + 64; + weechat_log_filename = + (char *) malloc (filename_length * sizeof (char)); + snprintf (weechat_log_filename, filename_length, + "%s/%s", weechat_home, WEECHAT_LOG_NAME); + } + + weechat_log_file = fopen (weechat_log_filename, mode); + if (!weechat_log_file) + { + free (weechat_log_filename); + weechat_log_filename = NULL; + return 0; + } + if ((flock (fileno (weechat_log_file), LOCK_EX | LOCK_NB) != 0)) + { + fclose (weechat_log_file); + weechat_log_file = NULL; + free (weechat_log_filename); + weechat_log_filename = NULL; + return 0; + } + + return 1; +} + /* * weechat_log_init: initialize log file */ @@ -43,26 +89,15 @@ FILE *weechat_log_file = NULL; /* WeeChat log file (~/.weechat/weechat.log) */ void weechat_log_init () { - int filename_length; - char *filename; - - filename_length = strlen (weechat_home) + 64; - filename = - (char *) malloc (filename_length * sizeof (char)); - snprintf (filename, filename_length, "%s/%s", weechat_home, WEECHAT_LOG_NAME); - - weechat_log_file = fopen (filename, "wt"); - if (!weechat_log_file - || (flock (fileno (weechat_log_file), LOCK_EX | LOCK_NB) != 0)) + if (!weechat_log_open (NULL, "w")) { fprintf (stderr, - _("%s unable to create/append to log file (%s/%s)\n" + _("%s unable to create/append to log file (%s)\n" "If another WeeChat process is using this file, try to run WeeChat\n" "with another home using \"--dir\" command line option.\n"), - WEECHAT_ERROR, weechat_home, WEECHAT_LOG_NAME); + WEECHAT_ERROR, weechat_log_filename); exit (1); } - free (filename); } /* @@ -115,10 +150,19 @@ weechat_log_printf (char *message, ...) void weechat_log_close () { + /* close log file */ if (weechat_log_file) { flock (fileno (weechat_log_file), LOCK_UN); fclose (weechat_log_file); + weechat_log_file = NULL; + } + + /* free filename */ + if (weechat_log_filename) + { + free (weechat_log_filename); + weechat_log_filename = NULL; } } @@ -126,14 +170,49 @@ weechat_log_close () * weechat_log_crash_rename: rename log file when crashing */ -void +int weechat_log_crash_rename () { - char *oldname, *newname; + char *old_name, *new_name; + int length; + time_t time_now; + struct tm *local_time; - oldname = (char *) malloc (strlen (weechat_home) + 64); - newname = (char *) malloc (strlen (weechat_home) + 64); - if (oldname && newname) + if (!weechat_log_filename) + return 0; + + old_name = strdup (weechat_log_filename); + if (!old_name) + return 0; + + weechat_log_close (); + + length = strlen (weechat_home) + 128; + new_name = (char *) malloc (length); + if (new_name) { + time_now = time (NULL); + local_time = localtime (&time_now); + snprintf (new_name, length, + "%s/weechat_crash_%04d%02d%02d_%d.log", + weechat_home, + local_time->tm_year + 1900, + local_time->tm_mon + 1, + local_time->tm_mday, + getpid()); + if (rename (old_name, new_name) == 0) + { + fprintf (stderr, "*** Full crash dump was saved to %s file.\n", + new_name); + weechat_log_open (new_name, "a"); + free (old_name); + free (new_name); + return 1; + } + free (new_name); } + + free (old_name); + weechat_log_open (NULL, "a"); + return 0; } diff --git a/src/common/log.h b/src/common/log.h index 53095dbfd..8fff3ef48 100644 --- a/src/common/log.h +++ b/src/common/log.h @@ -21,11 +21,12 @@ #ifndef __WEECHAT_LOG_H #define __WEECHAT_LOG_H 1 +extern char *weechat_log_filename; extern FILE *weechat_log_file; extern void weechat_log_init (); extern void weechat_log_close (); extern void weechat_log_printf (char *, ...); -extern void weechat_log_crash_rename (); +extern int weechat_log_crash_rename (); #endif /* log.h */ diff --git a/src/common/weechat.c b/src/common/weechat.c index 9cedef9d1..933d4ef04 100644 --- a/src/common/weechat.c +++ b/src/common/weechat.c @@ -1003,20 +1003,19 @@ weechat_sigsegv () fprintf (stderr, "*** Very bad! WeeChat is crashing (SIGSEGV received)\n"); fprintf (stderr, "*** (%s, compiled on %s %s)\n", PACKAGE_STRING, __DATE__, __TIME__); - fprintf (stderr, "*** Full crash dump was saved to %s/weechat.log file.\n", - weechat_home); + if (!weechat_log_crash_rename ()) + fprintf (stderr, "*** Full crash dump was saved to %s/weechat.log file.\n", + weechat_home); fprintf (stderr, "***\n"); fprintf (stderr, "*** Please help WeeChat developers to fix this bug:\n"); fprintf (stderr, "*** 1. If you have a core file, please run: gdb weechat-curses core\n"); fprintf (stderr, "*** then issue \"bt\" command and send result to developers\n"); fprintf (stderr, "*** To enable core files with bash shell: ulimit -c 10000\n"); - fprintf (stderr, "*** 2. Otherwise send backtrace displayed below and weechat.log\n"); + fprintf (stderr, "*** 2. Otherwise send backtrace (below) and weechat.log\n"); fprintf (stderr, "*** (be careful, private info may be in this file since\n"); fprintf (stderr, "*** part of chats are displayed, so remove lines if needed)\n\n"); - fprintf (stderr, "======= WeeChat backtrace =======\n"); weechat_backtrace (); - fprintf (stderr, "======= End of backtrace =======\n"); /* shutdown with error code */ weechat_shutdown (EXIT_FAILURE, 1); diff --git a/weechat/ChangeLog b/weechat/ChangeLog index 5cc9b310a..8a5f3fa0b 100644 --- a/weechat/ChangeLog +++ b/weechat/ChangeLog @@ -4,7 +4,7 @@ WeeChat - Wee Enhanced Environment for Chat ChangeLog - 2006-05-20 Version 0.1.9 (under dev!): - * added backtrace when WeeChat crashes + * added backtrace when WeeChat crashes, log file automatically renamed * added lock for log file (~/.weechat/weechat.log), only one WeeChat process can use this file (bug #16382) * fixed crash with malformed UTF-8 strings diff --git a/weechat/src/common/backtrace.c b/weechat/src/common/backtrace.c index d94de3432..98235f5e4 100644 --- a/weechat/src/common/backtrace.c +++ b/weechat/src/common/backtrace.c @@ -27,6 +27,7 @@ #include #include #include +#include #define __USE_GNU #include @@ -36,8 +37,27 @@ #include "weechat.h" #include "backtrace.h" +#include "log.h" +/* + * weechat_backtrace_printf: display a backtrage line (on stderr and in WeeChat log) + */ + +void +weechat_backtrace_printf (char *message, ...) +{ + static char buffer[4096]; + va_list argptr; + + va_start (argptr, message); + vsnprintf (buffer, sizeof (buffer) - 1, message, argptr); + va_end (argptr); + + fprintf (stderr, "%s", buffer); + weechat_log_printf ("%s", buffer); +} + /* * weechat_backtrace_addr2line: display function name and line with a backtrace address */ @@ -57,7 +77,7 @@ weechat_backtrace_addr2line (int number, void *address, char *symbol) rc = dladdr (address, &info); if ((rc == 0) || !info.dli_fname || !info.dli_fname[0]) { - fprintf (stderr, "%03d %s\n", number, symbol); + weechat_backtrace_printf ("%03d %s\n", number, symbol); return; } @@ -71,7 +91,7 @@ weechat_backtrace_addr2line (int number, void *address, char *symbol) output = popen (cmd_line, "r"); if (!output) { - fprintf (stderr, "%03d %s\n", number, symbol); + weechat_backtrace_printf ("%03d %s\n", number, symbol); return; } function_name[0] = '\0'; @@ -87,25 +107,27 @@ weechat_backtrace_addr2line (int number, void *address, char *symbol) if (strchr (ptr_line, ':')) { file_line = 1; - fprintf (stderr, "%03d %s%s%s%s\n", - number, - ptr_line, - (function_name[0]) ? " [function " : "", - function_name, - (function_name[0]) ? "]" : ""); + weechat_backtrace_printf ("%03d %s%s%s%s\n", + number, + ptr_line, + (function_name[0]) ? " [function " : "", + function_name, + (function_name[0]) ? "]" : ""); function_name[0] = '\0'; } else { if (function_name[0]) - fprintf (stderr, "%03d %s", number, function_name); + weechat_backtrace_printf ("%03d %s", + number, function_name); snprintf (function_name, sizeof (function_name), "%s", ptr_line); } } } if (function_name[0]) - fprintf (stderr, "%03d %s\n", number, function_name); + weechat_backtrace_printf ("%03d %s\n", + number, function_name); pclose (output); } @@ -120,7 +142,11 @@ weechat_backtrace () void *trace[BACKTRACE_MAX]; int trace_size, i; char **symbols; - +#endif + + weechat_backtrace_printf ("======= WeeChat backtrace =======\n"); + +#ifdef HAVE_BACKTRACE trace_size = backtrace (trace, BACKTRACE_MAX); symbols = backtrace_symbols (trace, trace_size); @@ -129,8 +155,9 @@ weechat_backtrace () weechat_backtrace_addr2line (i + 1, trace[i], symbols[i]); } #else - fprintf (stderr, - " No backtrace info (no debug info available or no backtrace possible " - "on your system).\n"); + weechat_backtrace_printf (" No backtrace info (no debug info available " + "or no backtrace possible on your system).\n"); #endif + + weechat_backtrace_printf ("======= End of backtrace =======\n"); } diff --git a/weechat/src/common/log.c b/weechat/src/common/log.c index 3403c7d87..85adea885 100644 --- a/weechat/src/common/log.c +++ b/weechat/src/common/log.c @@ -25,17 +25,63 @@ #endif #include +#include #include #include #include +#include #include "weechat.h" #include "log.h" -FILE *weechat_log_file = NULL; /* WeeChat log file (~/.weechat/weechat.log) */ +char *weechat_log_filename = NULL; /* log name (~/.weechat/weechat.log) */ +FILE *weechat_log_file = NULL; /* WeeChat log file */ +/* + * weechat_log_open: initialize log file + */ + +int +weechat_log_open (char *filename, char *mode) +{ + int filename_length; + + /* exit if log already opened */ + if (weechat_log_file) + return 0; + + if (filename) + weechat_log_filename = strdup (filename); + else + { + filename_length = strlen (weechat_home) + 64; + weechat_log_filename = + (char *) malloc (filename_length * sizeof (char)); + snprintf (weechat_log_filename, filename_length, + "%s/%s", weechat_home, WEECHAT_LOG_NAME); + } + + weechat_log_file = fopen (weechat_log_filename, mode); + if (!weechat_log_file) + { + free (weechat_log_filename); + weechat_log_filename = NULL; + return 0; + } + if ((flock (fileno (weechat_log_file), LOCK_EX | LOCK_NB) != 0)) + { + fclose (weechat_log_file); + weechat_log_file = NULL; + free (weechat_log_filename); + weechat_log_filename = NULL; + return 0; + } + + return 1; +} + /* * weechat_log_init: initialize log file */ @@ -43,26 +89,15 @@ FILE *weechat_log_file = NULL; /* WeeChat log file (~/.weechat/weechat.log) */ void weechat_log_init () { - int filename_length; - char *filename; - - filename_length = strlen (weechat_home) + 64; - filename = - (char *) malloc (filename_length * sizeof (char)); - snprintf (filename, filename_length, "%s/%s", weechat_home, WEECHAT_LOG_NAME); - - weechat_log_file = fopen (filename, "wt"); - if (!weechat_log_file - || (flock (fileno (weechat_log_file), LOCK_EX | LOCK_NB) != 0)) + if (!weechat_log_open (NULL, "w")) { fprintf (stderr, - _("%s unable to create/append to log file (%s/%s)\n" + _("%s unable to create/append to log file (%s)\n" "If another WeeChat process is using this file, try to run WeeChat\n" "with another home using \"--dir\" command line option.\n"), - WEECHAT_ERROR, weechat_home, WEECHAT_LOG_NAME); + WEECHAT_ERROR, weechat_log_filename); exit (1); } - free (filename); } /* @@ -115,10 +150,19 @@ weechat_log_printf (char *message, ...) void weechat_log_close () { + /* close log file */ if (weechat_log_file) { flock (fileno (weechat_log_file), LOCK_UN); fclose (weechat_log_file); + weechat_log_file = NULL; + } + + /* free filename */ + if (weechat_log_filename) + { + free (weechat_log_filename); + weechat_log_filename = NULL; } } @@ -126,14 +170,49 @@ weechat_log_close () * weechat_log_crash_rename: rename log file when crashing */ -void +int weechat_log_crash_rename () { - char *oldname, *newname; + char *old_name, *new_name; + int length; + time_t time_now; + struct tm *local_time; - oldname = (char *) malloc (strlen (weechat_home) + 64); - newname = (char *) malloc (strlen (weechat_home) + 64); - if (oldname && newname) + if (!weechat_log_filename) + return 0; + + old_name = strdup (weechat_log_filename); + if (!old_name) + return 0; + + weechat_log_close (); + + length = strlen (weechat_home) + 128; + new_name = (char *) malloc (length); + if (new_name) { + time_now = time (NULL); + local_time = localtime (&time_now); + snprintf (new_name, length, + "%s/weechat_crash_%04d%02d%02d_%d.log", + weechat_home, + local_time->tm_year + 1900, + local_time->tm_mon + 1, + local_time->tm_mday, + getpid()); + if (rename (old_name, new_name) == 0) + { + fprintf (stderr, "*** Full crash dump was saved to %s file.\n", + new_name); + weechat_log_open (new_name, "a"); + free (old_name); + free (new_name); + return 1; + } + free (new_name); } + + free (old_name); + weechat_log_open (NULL, "a"); + return 0; } diff --git a/weechat/src/common/log.h b/weechat/src/common/log.h index 53095dbfd..8fff3ef48 100644 --- a/weechat/src/common/log.h +++ b/weechat/src/common/log.h @@ -21,11 +21,12 @@ #ifndef __WEECHAT_LOG_H #define __WEECHAT_LOG_H 1 +extern char *weechat_log_filename; extern FILE *weechat_log_file; extern void weechat_log_init (); extern void weechat_log_close (); extern void weechat_log_printf (char *, ...); -extern void weechat_log_crash_rename (); +extern int weechat_log_crash_rename (); #endif /* log.h */ diff --git a/weechat/src/common/weechat.c b/weechat/src/common/weechat.c index 9cedef9d1..933d4ef04 100644 --- a/weechat/src/common/weechat.c +++ b/weechat/src/common/weechat.c @@ -1003,20 +1003,19 @@ weechat_sigsegv () fprintf (stderr, "*** Very bad! WeeChat is crashing (SIGSEGV received)\n"); fprintf (stderr, "*** (%s, compiled on %s %s)\n", PACKAGE_STRING, __DATE__, __TIME__); - fprintf (stderr, "*** Full crash dump was saved to %s/weechat.log file.\n", - weechat_home); + if (!weechat_log_crash_rename ()) + fprintf (stderr, "*** Full crash dump was saved to %s/weechat.log file.\n", + weechat_home); fprintf (stderr, "***\n"); fprintf (stderr, "*** Please help WeeChat developers to fix this bug:\n"); fprintf (stderr, "*** 1. If you have a core file, please run: gdb weechat-curses core\n"); fprintf (stderr, "*** then issue \"bt\" command and send result to developers\n"); fprintf (stderr, "*** To enable core files with bash shell: ulimit -c 10000\n"); - fprintf (stderr, "*** 2. Otherwise send backtrace displayed below and weechat.log\n"); + fprintf (stderr, "*** 2. Otherwise send backtrace (below) and weechat.log\n"); fprintf (stderr, "*** (be careful, private info may be in this file since\n"); fprintf (stderr, "*** part of chats are displayed, so remove lines if needed)\n\n"); - fprintf (stderr, "======= WeeChat backtrace =======\n"); weechat_backtrace (); - fprintf (stderr, "======= End of backtrace =======\n"); /* shutdown with error code */ weechat_shutdown (EXIT_FAILURE, 1);