libgeda
|
00001 /* gEDA - GPL Electronic Design Automation 00002 * libgeda - gEDA's library 00003 * Copyright (C) 1998-2010 Ales Hvezda 00004 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details) 00005 * 00006 * This program is free software; you can redistribute it and/or modify 00007 * it under the terms of the GNU General Public License as published by 00008 * the Free Software Foundation; either version 2 of the License, or 00009 * (at your option) any later version. 00010 * 00011 * This program is distributed in the hope that it will be useful, 00012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 00013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU General Public License for more details. 00015 * 00016 * You should have received a copy of the GNU General Public License 00017 * along with this program; if not, write to the Free Software 00018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 00019 */ 00020 #include <config.h> 00021 00022 #include <stdio.h> 00023 #include <sys/stat.h> 00024 #ifdef HAVE_STDLIB_H 00025 #include <stdlib.h> 00026 #endif 00027 #ifdef HAVE_UNISTD_H 00028 #include <unistd.h> 00029 #endif 00030 #ifdef HAVE_FCNTL_H 00031 #include <fcntl.h> 00032 #endif 00033 #ifdef HAVE_ERRNO_H 00034 #include <errno.h> 00035 #endif 00036 #ifdef HAVE_STRING_H 00037 #include <string.h> 00038 #endif 00039 00040 #include "libgeda_priv.h" 00041 00042 #include <time.h> 00043 00044 #ifdef HAVE_LIBDMALLOC 00045 #include <dmalloc.h> 00046 #endif 00047 00049 void (*x_log_update_func)() = NULL; 00050 00052 int do_logging = TRUE; 00053 00054 #define CATCH_LOG_LEVELS (G_LOG_LEVEL_MASK ^ \ 00055 (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO)) 00056 #define PRINT_LOG_LEVELS (CATCH_LOG_LEVELS ^ \ 00057 (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE)) 00058 00059 #define LOG_OPEN_ATTEMPTS 5 00060 00061 static void s_log_handler (const gchar *log_domain, 00062 GLogLevelFlags log_level, 00063 const gchar *message, 00064 gpointer user_data); 00065 00066 static int logfile_fd = -1; 00067 00068 static guint log_handler_id; 00069 00077 void s_log_init (const gchar *prefix) 00078 { 00079 /* FIXME we assume that the prefix is in the filesystem encoding. */ 00080 00081 time_t nowt; 00082 struct tm *nowtm; 00083 gchar *full_prefix = NULL; 00084 size_t full_prefix_len = 0; 00085 gchar *dir_path = NULL; 00086 gchar *filename = NULL; 00087 int s, i; 00088 int last_exist_logn = 0; 00089 GDir *logdir = NULL; 00090 00091 if (logfile_fd != -1) { 00092 g_critical ("s_log_init: Log already initialised.\n"); 00093 return; 00094 } 00095 if (do_logging == FALSE) { 00096 return; 00097 } 00098 00099 time (&nowt); 00100 nowtm = gmtime (&nowt); 00101 00102 /* create "real" prefix -- this has the form "<prefix>-<date>-" */ 00103 full_prefix = g_strdup_printf ("%s-%04i%02i%02i-", prefix, 00104 nowtm->tm_year + 1900, nowtm->tm_mon + 1, 00105 nowtm->tm_mday); 00106 full_prefix_len = strlen (full_prefix); 00107 00108 /* Find/create the directory where we're going to put the logs. 00109 * FIXME should this be configured somehow? 00110 * 00111 * Then run through it finding the "biggest" existing filename with 00112 * a matching prefix & date. */ 00113 dir_path = g_build_filename (s_path_user_config (), "logs", NULL); 00114 /* Try to create the directory. */ 00115 s = g_mkdir_with_parents (dir_path, 0777/*octal*/); 00116 if (s != 0) { 00117 /* It's okay to use the logging functions from here, because 00118 * there's already a default handler. */ 00119 g_warning ("Could not create log directory %s: %s\n", 00120 dir_path, strerror (errno)); 00121 g_free (dir_path); 00122 g_free (full_prefix); 00123 return; 00124 } 00125 00126 logdir = g_dir_open (dir_path, 0, NULL); 00127 while (TRUE) { 00128 const gchar *file = g_dir_read_name (logdir); 00129 int n; 00130 if (file == NULL) break; 00131 if (strncmp (full_prefix, file, full_prefix_len)) continue; 00132 00133 s = sscanf (file + full_prefix_len, "%i", &n); 00134 if (s != 1) continue; 00135 00136 if (n > last_exist_logn) last_exist_logn = n; 00137 } 00138 00139 /* Now try and create a new file. When we fail, increment the number. */ 00140 i = 0; 00141 while (logfile_fd == -1 && (LOG_OPEN_ATTEMPTS > i++)) { 00142 filename = g_strdup_printf ("%s%s%s%i.log", dir_path, 00143 G_DIR_SEPARATOR_S, full_prefix, 00144 ++last_exist_logn); 00145 logfile_fd = open (filename, O_RDWR|O_CREAT|O_EXCL, 0600); 00146 00147 if (logfile_fd == -1 && (errno != EEXIST)) break; 00148 } 00149 00150 if (logfile_fd != -1) { 00151 00152 /* install the log handler */ 00153 log_handler_id = g_log_set_handler (NULL, 00154 CATCH_LOG_LEVELS, 00155 s_log_handler, 00156 NULL); 00157 00158 } else { 00159 /* It's okay to use the logging functions from here, because 00160 * there's already a default handler. */ 00161 if (errno == EEXIST) { 00162 g_warning ("Could not create unique log filename in %s\n", 00163 dir_path); 00164 } else { 00165 g_warning ("Could not create log file in %s: %s\n", 00166 dir_path, strerror (errno)); 00167 } 00168 } 00169 00170 g_free (filename); 00171 g_free (dir_path); 00172 g_free (full_prefix); 00173 } 00174 00180 void s_log_close (void) 00181 { 00182 do_logging = FALSE; /* subsequent messages are lost after the close */ 00183 00184 if (logfile_fd == -1) 00185 { 00186 return; 00187 } 00188 00189 /* remove the handler */ 00190 g_log_remove_handler (NULL, log_handler_id); 00191 00192 /* close the file */ 00193 if (logfile_fd != -1) { 00194 close (logfile_fd); 00195 logfile_fd = -1; 00196 } 00197 00198 } 00199 00207 gchar *s_log_read (void) 00208 { 00209 gboolean tmp; 00210 #define BUFSIZE 200 00211 gchar buf[BUFSIZE]; 00212 GString *contents; 00213 gint len; 00214 00215 if (logfile_fd == -1) { 00216 return NULL; 00217 } 00218 00219 tmp = do_logging; 00220 do_logging = FALSE; 00221 00222 /* rewind the file */ 00223 lseek(logfile_fd, 0, SEEK_SET); 00224 00225 /* read its contents and build a string */ 00226 contents = g_string_new (""); 00227 while ((len = read (logfile_fd, &buf, BUFSIZE)) != 0) { 00228 contents = g_string_append_len (contents, buf, len); 00229 } 00230 00231 do_logging = tmp; 00232 00233 return g_string_free (contents, FALSE); 00234 } 00235 00251 static void s_log_handler (const gchar *log_domain, 00252 GLogLevelFlags log_level, 00253 const gchar *message, 00254 gpointer user_data) 00255 { 00256 int status; 00257 00258 if (do_logging == FALSE) { 00259 return; 00260 } 00261 g_return_if_fail (logfile_fd != -1); 00262 00263 status = write (logfile_fd, message, strlen (message)); 00264 if (status == -1) { 00265 fprintf(stderr, "Could not write message to log file\n"); 00266 } 00267 if ((status == -1) || (log_level & PRINT_LOG_LEVELS)) { 00268 /* If messages are serious or writing to file failed, call the 00269 * default handler to write to the console. */ 00270 g_log_default_handler (log_domain, log_level, message, NULL); 00271 } 00272 00273 if (x_log_update_func) { 00274 (*x_log_update_func) (log_domain, log_level, message); 00275 } 00276 00277 }