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
40 #include "libgeda_priv.h"
44 #ifdef HAVE_LIBDMALLOC
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
,
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. */
83 gchar
*full_prefix
= NULL
;
84 size_t full_prefix_len
= 0;
85 gchar
*dir_path
= NULL
;
86 gchar
*filename
= NULL
;
88 int last_exist_logn
= 0;
91 if (logfile_fd
!= -1) {
92 g_critical ("s_log_init: Log already initialised.\n");
95 if (do_logging
== FALSE
) {
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,
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*/);
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
));
122 g_free (full_prefix
);
126 logdir
= g_dir_open (dir_path
, 0, NULL
);
128 const gchar
*file
= g_dir_read_name (logdir
);
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. */
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
,
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
,
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",
165 g_warning ("Could not create log file in %s: %s\n",
166 dir_path
, strerror (errno
));
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
180 void s_log_close (void)
182 do_logging
= FALSE
; /* subsequent messages are lost after the close */
184 if (logfile_fd
== -1)
189 /* remove the handler */
190 g_log_remove_handler (NULL
, log_handler_id
);
193 if (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)
215 if (logfile_fd
== -1) {
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
);
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>
244 * \param [in] log_domain (unused).
245 * \param [in] log_level (unused).
246 * \param [in] message Character string containing message to
248 * \param [in] user_data (unused).
251 static void s_log_handler (const gchar
*log_domain
,
252 GLogLevelFlags log_level
,
253 const gchar
*message
,
258 if (do_logging
== FALSE
) {
261 g_return_if_fail (logfile_fd
!= -1);
263 status
= write (logfile_fd
, message
, strlen (message
));
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
);