libgeda

s_log.c

Go to the documentation of this file.
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 }
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines