~xavi-garcia-mena/ubuntu/vivid/upower/percentages-power-off

« back to all changes in this revision

Viewing changes to tools/egg-debug.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2010-02-16 10:16:24 UTC
  • Revision ID: james.westby@ubuntu.com-20100216101624-2cmwqsr1ndftdd87
Tags: upstream-0.9.0+git20100216.72bb2
ImportĀ upstreamĀ versionĀ 0.9.0+git20100216.72bb2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
 
2
 *
 
3
 * Copyright (C) 2007-2009 Richard Hughes <richard@hughsie.com>
 
4
 *
 
5
 * Licensed under the GNU General Public License Version 2
 
6
 *
 
7
 * This program is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * This program is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 
20
 */
 
21
 
 
22
/**
 
23
 * SECTION:egg-debug
 
24
 * @short_description: Debugging functions
 
25
 *
 
26
 * This file contains functions that can be used for debugging.
 
27
 */
 
28
 
 
29
#include "config.h"
 
30
 
 
31
#include <glib.h>
 
32
#include <glib/gi18n.h>
 
33
#include <glib/gprintf.h>
 
34
#include <stdio.h>
 
35
#include <string.h>
 
36
#include <stdarg.h>
 
37
#include <stdlib.h>
 
38
#include <signal.h>
 
39
#include <unistd.h>
 
40
#include <sys/types.h>
 
41
#include <sys/stat.h>
 
42
#include <fcntl.h>
 
43
#include <time.h>
 
44
 
 
45
#ifdef HAVE_EXECINFO_H
 
46
#include <execinfo.h>
 
47
#endif
 
48
 
 
49
#include "egg-debug.h"
 
50
 
 
51
#define CONSOLE_RESET           0
 
52
#define CONSOLE_BLACK           30
 
53
#define CONSOLE_RED             31
 
54
#define CONSOLE_GREEN           32
 
55
#define CONSOLE_YELLOW          33
 
56
#define CONSOLE_BLUE            34
 
57
#define CONSOLE_MAGENTA         35
 
58
#define CONSOLE_CYAN            36
 
59
#define CONSOLE_WHITE           37
 
60
 
 
61
static gint _fd = -1;
 
62
static gboolean _verbose = FALSE;
 
63
static gboolean _console = FALSE;
 
64
static gchar *_log_filename = NULL;
 
65
static gboolean _initialized = FALSE;
 
66
static GPtrArray *_modules_array = NULL;
 
67
static GPtrArray *_functions_array = NULL;
 
68
static gchar **_modules = NULL;
 
69
static gchar **_functions = NULL;
 
70
 
 
71
/**
 
72
 * egg_debug_filter_module:
 
73
 **/
 
74
static gboolean
 
75
egg_debug_filter_module (const gchar *filename)
 
76
{
 
77
        gchar *module;
 
78
        const gchar *module_tmp;
 
79
        guint i;
 
80
        gboolean ret = FALSE;
 
81
 
 
82
        /* nothing filtering */
 
83
        if (_modules_array == NULL)
 
84
                return FALSE;
 
85
 
 
86
        /* are we in the filter list */
 
87
        module = g_strdup (filename);
 
88
        g_strdelimit (module, ".", '\0');
 
89
        for (i=0; i<_modules_array->len; i++) {
 
90
                module_tmp = g_ptr_array_index (_modules_array, i);
 
91
                if (g_strcmp0 (module_tmp, module) == 0) {
 
92
                        ret = TRUE;
 
93
                        break;
 
94
                }
 
95
        }
 
96
        return ret;
 
97
}
 
98
 
 
99
/**
 
100
 * egg_debug_filter_function:
 
101
 **/
 
102
static gboolean
 
103
egg_debug_filter_function (const gchar *function)
 
104
{
 
105
        guint i;
 
106
        const gchar *function_tmp;
 
107
        gboolean ret = FALSE;
 
108
 
 
109
        /* nothing filtering */
 
110
        if (_functions_array == NULL)
 
111
                return FALSE;
 
112
 
 
113
        /* are we in the filter list */
 
114
        for (i=0; i<_functions_array->len; i++) {
 
115
                function_tmp = g_ptr_array_index (_functions_array, i);
 
116
                if (g_str_has_prefix (function, function_tmp)) {
 
117
                        ret = TRUE;
 
118
                        break;
 
119
                }
 
120
        }
 
121
        return ret;
 
122
}
 
123
 
 
124
/**
 
125
 * egg_debug_set_console_mode:
 
126
 **/
 
127
static void
 
128
egg_debug_set_console_mode (guint console_code)
 
129
{
 
130
        gchar command[13];
 
131
 
 
132
        /* don't put extra commands into logs */
 
133
        if (!_console)
 
134
                return;
 
135
 
 
136
        /* Command is the control command to the terminal */
 
137
        g_snprintf (command, 13, "%c[%dm", 0x1B, console_code);
 
138
        printf ("%s", command);
 
139
}
 
140
 
 
141
/**
 
142
 * egg_debug_backtrace:
 
143
 **/
 
144
void
 
145
egg_debug_backtrace (void)
 
146
{
 
147
#ifdef HAVE_EXECINFO_H
 
148
        void *call_stack[512];
 
149
        int  call_stack_size;
 
150
        char **symbols;
 
151
        int i = 1;
 
152
 
 
153
        call_stack_size = backtrace (call_stack, G_N_ELEMENTS (call_stack));
 
154
        symbols = backtrace_symbols (call_stack, call_stack_size);
 
155
        if (symbols != NULL) {
 
156
                egg_debug_set_console_mode (CONSOLE_RED);
 
157
                g_print ("Traceback:\n");
 
158
                while (i < call_stack_size) {
 
159
                        g_print ("\t%s\n", symbols[i]);
 
160
                        i++;
 
161
                }
 
162
                egg_debug_set_console_mode (CONSOLE_RESET);
 
163
                free (symbols);
 
164
        }
 
165
#endif
 
166
}
 
167
 
 
168
/**
 
169
 * egg_debug_log_line:
 
170
 **/
 
171
static void
 
172
egg_debug_log_line (const gchar *buffer)
 
173
{
 
174
        ssize_t count;
 
175
 
 
176
        /* open a file */
 
177
        if (_fd == -1) {
 
178
                /* ITS4: ignore, /var/log/foo is owned by root, and this is just debug text */
 
179
                _fd = open (_log_filename, O_WRONLY|O_APPEND|O_CREAT, 0777);
 
180
                if (_fd == -1)
 
181
                        g_error ("could not open log: '%s'", _log_filename);
 
182
        }
 
183
 
 
184
        /* ITS4: ignore, debug text always NULL terminated */
 
185
        count = write (_fd, buffer, strlen (buffer));
 
186
        if (count == -1)
 
187
                g_warning ("could not write %s", buffer);
 
188
 
 
189
        /* newline */
 
190
        count = write (_fd, "\n", 1);
 
191
        if (count == -1)
 
192
                g_warning ("could not write newline");
 
193
}
 
194
 
 
195
/**
 
196
 * egg_debug_print_line:
 
197
 **/
 
198
static void
 
199
egg_debug_print_line (const gchar *func, const gchar *file, const int line, const gchar *buffer, guint color)
 
200
{
 
201
        gchar *str_time;
 
202
        gchar *header;
 
203
        time_t the_time;
 
204
 
 
205
        time (&the_time);
 
206
        str_time = g_new0 (gchar, 255);
 
207
        strftime (str_time, 254, "%H:%M:%S", localtime (&the_time));
 
208
 
 
209
        /* generate header text */
 
210
        header = g_strdup_printf ("TI:%s\tFI:%s\tFN:%s,%d", str_time, file, func, line);
 
211
        g_free (str_time);
 
212
 
 
213
        /* always in light green */
 
214
        egg_debug_set_console_mode (CONSOLE_GREEN);
 
215
        printf ("%s\n", header);
 
216
 
 
217
        /* different colors according to the severity */
 
218
        egg_debug_set_console_mode (color);
 
219
        printf (" - %s\n", buffer);
 
220
        egg_debug_set_console_mode (CONSOLE_RESET);
 
221
 
 
222
        /* log to a file */
 
223
        if (_log_filename != NULL) {
 
224
                egg_debug_log_line (header);
 
225
                egg_debug_log_line (buffer);
 
226
        }
 
227
 
 
228
        /* flush this output, as we need to debug */
 
229
        fflush (stdout);
 
230
 
 
231
        g_free (header);
 
232
}
 
233
 
 
234
/**
 
235
 * egg_debug_real:
 
236
 **/
 
237
void
 
238
egg_debug_real (const gchar *func, const gchar *file, const int line, const gchar *format, ...)
 
239
{
 
240
        va_list args;
 
241
        gchar *buffer = NULL;
 
242
 
 
243
        if (!_verbose && !egg_debug_filter_module (file) && !egg_debug_filter_function (func))
 
244
                return;
 
245
 
 
246
        va_start (args, format);
 
247
        g_vasprintf (&buffer, format, args);
 
248
        va_end (args);
 
249
 
 
250
        egg_debug_print_line (func, file, line, buffer, CONSOLE_BLUE);
 
251
 
 
252
        g_free (buffer);
 
253
}
 
254
 
 
255
/**
 
256
 * egg_warning_real:
 
257
 **/
 
258
void
 
259
egg_warning_real (const gchar *func, const gchar *file, const int line, const gchar *format, ...)
 
260
{
 
261
        va_list args;
 
262
        gchar *buffer = NULL;
 
263
 
 
264
        if (!_verbose && !egg_debug_filter_module (file) && !egg_debug_filter_function (func))
 
265
                return;
 
266
 
 
267
        va_start (args, format);
 
268
        g_vasprintf (&buffer, format, args);
 
269
        va_end (args);
 
270
 
 
271
        /* do extra stuff for a warning */
 
272
        if (!_console)
 
273
                printf ("*** WARNING ***\n");
 
274
        egg_debug_print_line (func, file, line, buffer, CONSOLE_RED);
 
275
 
 
276
        g_free (buffer);
 
277
}
 
278
 
 
279
/**
 
280
 * egg_error_real:
 
281
 **/
 
282
void
 
283
egg_error_real (const gchar *func, const gchar *file, const int line, const gchar *format, ...)
 
284
{
 
285
        va_list args;
 
286
        gchar *buffer = NULL;
 
287
 
 
288
        va_start (args, format);
 
289
        g_vasprintf (&buffer, format, args);
 
290
        va_end (args);
 
291
 
 
292
        /* do extra stuff for a warning */
 
293
        if (!_console)
 
294
                printf ("*** ERROR ***\n");
 
295
        egg_debug_print_line (func, file, line, buffer, CONSOLE_RED);
 
296
        g_free (buffer);
 
297
 
 
298
        /* we want to fix this! */
 
299
        egg_debug_backtrace ();
 
300
 
 
301
        exit (1);
 
302
}
 
303
 
 
304
/**
 
305
 * egg_debug_is_verbose:
 
306
 *
 
307
 * Returns: TRUE if we have debugging enabled
 
308
 **/
 
309
gboolean
 
310
egg_debug_is_verbose (void)
 
311
{
 
312
        return _verbose;
 
313
}
 
314
 
 
315
/**
 
316
 * egg_debug_set_log_filename:
 
317
 **/
 
318
void
 
319
egg_debug_set_log_filename (const gchar *filename)
 
320
{
 
321
        g_free (_log_filename);
 
322
        _log_filename = g_strdup (filename);
 
323
}
 
324
 
 
325
/**
 
326
 * egg_debug_strv_split_to_ptr_array:
 
327
 **/
 
328
static GPtrArray *
 
329
egg_debug_strv_split_to_ptr_array (gchar **modules)
 
330
{
 
331
        GPtrArray *array = NULL;
 
332
        guint i, j;
 
333
        gchar **split;
 
334
 
 
335
        /* nothing */
 
336
        if (modules == NULL)
 
337
                goto out;
 
338
 
 
339
        /* create array of strings */
 
340
        array = g_ptr_array_new_with_free_func (g_free);
 
341
 
 
342
        /* parse each --debug-foo option */
 
343
        for (i=0; modules[i] != NULL; i++) {
 
344
                /* use a comma to delimit multiple entries */
 
345
                split = g_strsplit (modules[i], ",", -1);
 
346
                for (j=0; split[j] != NULL; j++)
 
347
                        g_ptr_array_add (array, g_strdup (split[j]));
 
348
                g_strfreev (split);
 
349
        }
 
350
out:
 
351
        return array;
 
352
}
 
353
 
 
354
/**
 
355
 * egg_debug_pre_parse_hook:
 
356
 */
 
357
static gboolean
 
358
egg_debug_pre_parse_hook (GOptionContext *context, GOptionGroup *group, gpointer data, GError **error)
 
359
{
 
360
        const gchar *env_string;
 
361
        const GOptionEntry main_entries[] = {
 
362
                { "verbose", 'v', 0, G_OPTION_ARG_NONE, &_verbose,
 
363
                  /* TRANSLATORS: turn on all debugging */
 
364
                  N_("Show debugging information for all files"), NULL },
 
365
                { NULL}
 
366
        };
 
367
 
 
368
        /* global variable */
 
369
        env_string = g_getenv ("VERBOSE");
 
370
        if (env_string != NULL)
 
371
                _verbose = TRUE;
 
372
 
 
373
        /* add main entry */
 
374
        g_option_context_add_main_entries (context, main_entries, NULL);
 
375
 
 
376
        return TRUE;
 
377
}
 
378
 
 
379
/**
 
380
 * egg_debug_free:
 
381
 **/
 
382
static void
 
383
egg_debug_free (void)
 
384
{
 
385
        if (!_initialized)
 
386
                return;
 
387
 
 
388
        /* close file */
 
389
        if (_fd != -1)
 
390
                close (_fd);
 
391
 
 
392
        /* free memory */
 
393
        g_free (_log_filename);
 
394
        if (_modules_array != NULL)
 
395
                g_ptr_array_unref (_modules_array);
 
396
        if (_functions_array != NULL)
 
397
                g_ptr_array_unref (_functions_array);
 
398
        g_strfreev (_modules);
 
399
        g_strfreev (_functions);
 
400
 
 
401
        /* can not re-init */
 
402
        _initialized = FALSE;
 
403
}
 
404
 
 
405
/**
 
406
 * egg_debug_post_parse_hook:
 
407
 */
 
408
static gboolean
 
409
egg_debug_post_parse_hook (GOptionContext *context, GOptionGroup *group, gpointer data, GError **error)
 
410
{
 
411
        _initialized = TRUE;
 
412
        _modules_array = egg_debug_strv_split_to_ptr_array (_modules);
 
413
        _functions_array = egg_debug_strv_split_to_ptr_array (_functions);
 
414
        _console = (isatty (fileno (stdout)) == 1);
 
415
        egg_debug ("Verbose debugging %i (on console %i)", _verbose, _console);
 
416
 
 
417
        /* run this function on cleanup */
 
418
        atexit (egg_debug_free);
 
419
 
 
420
        return TRUE;
 
421
}
 
422
 
 
423
/**
 
424
 * egg_debug_get_option_group:
 
425
 *
 
426
 * Returns a #GOptionGroup for the commandline arguments recognized
 
427
 * by debugging. You should add this group to your #GOptionContext
 
428
 * with g_option_context_add_group(), if you are using
 
429
 * g_option_context_parse() to parse your commandline arguments.
 
430
 *
 
431
 * Returns: a #GOptionGroup for the commandline arguments
 
432
 */
 
433
GOptionGroup *
 
434
egg_debug_get_option_group (void)
 
435
{
 
436
        GOptionGroup *group;
 
437
        const GOptionEntry debug_entries[] = {
 
438
                { "debug-modules", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &_modules,
 
439
                  /* TRANSLATORS: a list of modules to debug */
 
440
                  N_("Debug these specific modules"), NULL },
 
441
                { "debug-functions", '\0', 0, G_OPTION_ARG_STRING_ARRAY, &_functions,
 
442
                  /* TRANSLATORS: a list of functions to debug */
 
443
                  N_("Debug these specific functions"), NULL },
 
444
                { "debug-log-filename", '\0', 0, G_OPTION_ARG_STRING, &_log_filename,
 
445
                  /* TRANSLATORS: save to a log */
 
446
                  N_("Log debugging data to a file"), NULL },
 
447
                { NULL}
 
448
        };
 
449
 
 
450
        group = g_option_group_new ("debug", _("Debugging Options"), _("Show debugging options"), NULL, NULL);
 
451
        g_option_group_set_parse_hooks (group, egg_debug_pre_parse_hook, egg_debug_post_parse_hook);
 
452
        g_option_group_add_entries (group, debug_entries);
 
453
        return group;
 
454
}
 
455
 
 
456
/**
 
457
 * egg_debug_init:
 
458
 * @argc: a pointer to the number of command line arguments.
 
459
 * @argv: a pointer to the array of command line arguments.
 
460
 *
 
461
 * Parses command line arguments.
 
462
 *
 
463
 * Return value: %TRUE if initialization succeeded, otherwise %FALSE.
 
464
 **/
 
465
gboolean
 
466
egg_debug_init (gint *argc, gchar ***argv)
 
467
{
 
468
        GOptionContext *context;
 
469
 
 
470
        /* already initialized */
 
471
        if (_initialized)
 
472
                return TRUE;
 
473
 
 
474
        context = g_option_context_new (NULL);
 
475
        g_option_context_set_ignore_unknown_options (context, TRUE);
 
476
        g_option_context_add_group (context, egg_debug_get_option_group ());
 
477
        g_option_context_parse (context, argc, argv, NULL);
 
478
        g_option_context_free (context);
 
479
 
 
480
        return TRUE;
 
481
}
 
482