Update README with new Automake requirement.
[geda-gaf.git] / libgeda / src / s_log.c
blob51eeb998697182252473bb0d07486dcdb63cde12
1 /* gEDA - GPL Electronic Design Automation
2 * libgeda - gEDA's library
3 * Copyright (C) 1998-2010 Ales Hvezda
4 * Copyright (C) 1998-2010 gEDA Contributors (see ChangeLog for details)
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 #include <config.h>
22 #include <stdio.h>
23 #include <sys/stat.h>
24 #ifdef HAVE_STDLIB_H
25 #include <stdlib.h>
26 #endif
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30 #ifdef HAVE_FCNTL_H
31 #include <fcntl.h>
32 #endif
33 #ifdef HAVE_ERRNO_H
34 #include <errno.h>
35 #endif
36 #ifdef HAVE_STRING_H
37 #include <string.h>
38 #endif
40 #include "libgeda_priv.h"
42 #include <time.h>
44 #ifdef HAVE_LIBDMALLOC
45 #include <dmalloc.h>
46 #endif
48 /*! Default setting for log update callback function. */
49 void (*x_log_update_func)() = NULL;
51 /*! Default setting for log enable. */
52 int do_logging = TRUE;
54 #define CATCH_LOG_LEVELS (G_LOG_LEVEL_MASK ^ \
55 (G_LOG_LEVEL_DEBUG | G_LOG_LEVEL_INFO))
56 #define PRINT_LOG_LEVELS (CATCH_LOG_LEVELS ^ \
57 (G_LOG_LEVEL_WARNING | G_LOG_LEVEL_MESSAGE))
59 #define LOG_OPEN_ATTEMPTS 5
61 static void s_log_handler (const gchar *log_domain,
62 GLogLevelFlags log_level,
63 const gchar *message,
64 gpointer user_data);
66 static int logfile_fd = -1;
68 static guint log_handler_id;
70 /*! \brief Initialize libgeda logging feature.
71 * \par Function Description
72 * This function opens the file <B>filename</B> to log to and registers the
73 * handler to redirect log message to this file.
75 * \param [in] prefix Character string with file name prefix to log to.
77 void s_log_init (const gchar *prefix)
79 /* FIXME we assume that the prefix is in the filesystem encoding. */
81 time_t nowt;
82 struct tm *nowtm;
83 gchar *full_prefix = NULL;
84 size_t full_prefix_len = 0;
85 gchar *dir_path = NULL;
86 gchar *filename = NULL;
87 int s, i;
88 int last_exist_logn = 0;
89 GDir *logdir = NULL;
91 if (logfile_fd != -1) {
92 g_critical ("s_log_init: Log already initialised.\n");
93 return;
95 if (do_logging == FALSE) {
96 return;
99 time (&nowt);
100 nowtm = gmtime (&nowt);
102 /* create "real" prefix -- this has the form "<prefix>-<date>-" */
103 full_prefix = g_strdup_printf ("%s-%04i%02i%02i-", prefix,
104 nowtm->tm_year + 1900, nowtm->tm_mon + 1,
105 nowtm->tm_mday);
106 full_prefix_len = strlen (full_prefix);
108 /* Find/create the directory where we're going to put the logs.
109 * FIXME should this be configured somehow?
111 * Then run through it finding the "biggest" existing filename with
112 * a matching prefix & date. */
113 dir_path = g_build_filename (s_path_user_config (), "logs", NULL);
114 /* Try to create the directory. */
115 s = g_mkdir_with_parents (dir_path, 0777/*octal*/);
116 if (s != 0) {
117 /* It's okay to use the logging functions from here, because
118 * there's already a default handler. */
119 g_warning ("Could not create log directory %s: %s\n",
120 dir_path, strerror (errno));
121 g_free (dir_path);
122 g_free (full_prefix);
123 return;
126 logdir = g_dir_open (dir_path, 0, NULL);
127 while (TRUE) {
128 const gchar *file = g_dir_read_name (logdir);
129 int n;
130 if (file == NULL) break;
131 if (strncmp (full_prefix, file, full_prefix_len)) continue;
133 s = sscanf (file + full_prefix_len, "%i", &n);
134 if (s != 1) continue;
136 if (n > last_exist_logn) last_exist_logn = n;
139 /* Now try and create a new file. When we fail, increment the number. */
140 i = 0;
141 while (logfile_fd == -1 && (LOG_OPEN_ATTEMPTS > i++)) {
142 filename = g_strdup_printf ("%s%s%s%i.log", dir_path,
143 G_DIR_SEPARATOR_S, full_prefix,
144 ++last_exist_logn);
145 logfile_fd = open (filename, O_RDWR|O_CREAT|O_EXCL, 0600);
147 if (logfile_fd == -1 && (errno != EEXIST)) break;
150 if (logfile_fd != -1) {
152 /* install the log handler */
153 log_handler_id = g_log_set_handler (NULL,
154 CATCH_LOG_LEVELS,
155 s_log_handler,
156 NULL);
158 } else {
159 /* It's okay to use the logging functions from here, because
160 * there's already a default handler. */
161 if (errno == EEXIST) {
162 g_warning ("Could not create unique log filename in %s\n",
163 dir_path);
164 } else {
165 g_warning ("Could not create log file in %s: %s\n",
166 dir_path, strerror (errno));
170 g_free (filename);
171 g_free (dir_path);
172 g_free (full_prefix);
175 /*! \brief Terminates the logging of messages.
176 * \par Function Description
177 * This function deregisters the handler for redirection to the log file
178 * and closes it.
180 void s_log_close (void)
182 do_logging = FALSE; /* subsequent messages are lost after the close */
184 if (logfile_fd == -1)
186 return;
189 /* remove the handler */
190 g_log_remove_handler (NULL, log_handler_id);
192 /* close the file */
193 if (logfile_fd != -1) {
194 close (logfile_fd);
195 logfile_fd = -1;
200 /*! \brief Reads the current log file and returns its contents.
201 * \par Function Description
202 * This function reads the current log file and returns its contents.
204 * \return Character string with current log's contents.
207 gchar *s_log_read (void)
209 gboolean tmp;
210 #define BUFSIZE 200
211 gchar buf[BUFSIZE];
212 GString *contents;
213 gint len;
215 if (logfile_fd == -1) {
216 return NULL;
219 tmp = do_logging;
220 do_logging = FALSE;
222 /* rewind the file */
223 lseek(logfile_fd, 0, SEEK_SET);
225 /* read its contents and build a string */
226 contents = g_string_new ("");
227 while ((len = read (logfile_fd, &buf, BUFSIZE)) != 0) {
228 contents = g_string_append_len (contents, buf, len);
231 do_logging = tmp;
233 return g_string_free (contents, FALSE);
236 /*! \brief Write a message to the current log file.
237 * \par Function Description
238 * Writes <B>message</B> to the current log file whose file descriptor
239 * is <B>logfile_fd</B>.
241 * It also sends <B>message</B> to the optional function <B>x_log_update</B>
242 * for further use.
244 * \param [in] log_domain (unused).
245 * \param [in] log_level (unused).
246 * \param [in] message Character string containing message to
247 * write to log.
248 * \param [in] user_data (unused).
251 static void s_log_handler (const gchar *log_domain,
252 GLogLevelFlags log_level,
253 const gchar *message,
254 gpointer user_data)
256 int status;
258 if (do_logging == FALSE) {
259 return;
261 g_return_if_fail (logfile_fd != -1);
263 status = write (logfile_fd, message, strlen (message));
264 if (status == -1) {
265 fprintf(stderr, "Could not write message to log file\n");
267 if ((status == -1) || (log_level & PRINT_LOG_LEVELS)) {
268 /* If messages are serious or writing to file failed, call the
269 * default handler to write to the console. */
270 g_log_default_handler (log_domain, log_level, message, NULL);
273 if (x_log_update_func) {
274 (*x_log_update_func) (log_domain, log_level, message);