1 | /* |
---|
2 | * Message and error reporting (fatal). |
---|
3 | * |
---|
4 | * Usage: |
---|
5 | * |
---|
6 | * extern int cleanup(void); |
---|
7 | * extern void log(int, const char *, va_list, int); |
---|
8 | * |
---|
9 | * message_fatal_cleanup = cleanup; |
---|
10 | * message_program_name = argv[0]; |
---|
11 | * |
---|
12 | * die("Something fatal happened at %lu", time); |
---|
13 | * sysdie("open of %s failed", filename); |
---|
14 | * |
---|
15 | * message_handlers_die(1, log); |
---|
16 | * die("This now goes through our log function"); |
---|
17 | * |
---|
18 | * die() implements message reporting through user-configurable handler |
---|
19 | * functions and then exits, normally with a status of 1. sysdie() does the |
---|
20 | * same but appends a colon, a space, and the results of strerror(errno) to |
---|
21 | * the end of the message. Both functions accept printf-style formatting |
---|
22 | * strings and arguments. |
---|
23 | * |
---|
24 | * If message_fatal_cleanup is non-NULL, it is called before exit by die and |
---|
25 | * sysdie and its return value is used as the argument to exit. It is a |
---|
26 | * pointer to a function taking no arguments and returning an int, and can be |
---|
27 | * used to call cleanup functions or to exit in some alternate fashion (such |
---|
28 | * as by calling _exit). |
---|
29 | * |
---|
30 | * If message_program_name is non-NULL, the string it points to, followed by a |
---|
31 | * colon and a space, is prepended to all error messages logged through the |
---|
32 | * message_log_stderr message handler (the default for die). |
---|
33 | * |
---|
34 | * Honoring error_program_name and printing to stderr is just the default |
---|
35 | * handler; with message_handlers_die the handler for die() can be changed. |
---|
36 | * By default, die prints to stderr. message_handlers_die takes a count of |
---|
37 | * handlers and then that many function pointers, each one to a function that |
---|
38 | * takes a message length (the number of characters snprintf generates given |
---|
39 | * the format and arguments), a format, an argument list as a va_list, and the |
---|
40 | * applicable errno value (if any). |
---|
41 | * |
---|
42 | * This file is separate from messages.c so that the potentially fatal |
---|
43 | * functions aren't linked with code that will never call exit(). This helps |
---|
44 | * automated analysis ensure that shared libraries don't call exit(). |
---|
45 | * |
---|
46 | * Copyright 2009 Russ Allbery <rra@stanford.edu> |
---|
47 | * Copyright 2008 Board of Trustees, Leland Stanford Jr. University |
---|
48 | * Copyright (c) 2004, 2005, 2006 |
---|
49 | * by Internet Systems Consortium, Inc. ("ISC") |
---|
50 | * Copyright (c) 1991, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, |
---|
51 | * 2002, 2003 by The Internet Software Consortium and Rich Salz |
---|
52 | * |
---|
53 | * See LICENSE for licensing terms. |
---|
54 | */ |
---|
55 | |
---|
56 | #include <config.h> |
---|
57 | #include <portable/system.h> |
---|
58 | |
---|
59 | #include <errno.h> |
---|
60 | |
---|
61 | #include <util/util.h> |
---|
62 | |
---|
63 | /* The default message handler. */ |
---|
64 | static message_handler_func stderr_handlers[2] = { |
---|
65 | message_log_stderr, NULL |
---|
66 | }; |
---|
67 | static message_handler_func *die_handlers = stderr_handlers; |
---|
68 | |
---|
69 | /* If non-NULL, called before exit and its return value passed to exit. */ |
---|
70 | int (*message_fatal_cleanup)(void) = NULL; |
---|
71 | |
---|
72 | |
---|
73 | /* |
---|
74 | * Set the handlers for die. This duplicates code from messages.c but seems |
---|
75 | * to be the best way to handle separating the potentially fatal functions |
---|
76 | * from the rest. |
---|
77 | */ |
---|
78 | void |
---|
79 | message_handlers_die(int count, ...) |
---|
80 | { |
---|
81 | va_list args; |
---|
82 | int i; |
---|
83 | |
---|
84 | va_start(args, count); |
---|
85 | if (die_handlers != stderr_handlers) |
---|
86 | free(die_handlers); |
---|
87 | die_handlers = xmalloc(sizeof(message_handler_func) * (count + 1)); |
---|
88 | for (i = 0; i < count; i++) |
---|
89 | die_handlers[i] = va_arg(args, message_handler_func); |
---|
90 | die_handlers[count] = NULL; |
---|
91 | va_end(args); |
---|
92 | } |
---|
93 | |
---|
94 | |
---|
95 | /* |
---|
96 | * The error reporting functions. There is code duplication between the two |
---|
97 | * functions that could be avoided with judicious use of va_copy(), but it's |
---|
98 | * never seemed worth the effort. |
---|
99 | */ |
---|
100 | void |
---|
101 | die(const char *format, ...) |
---|
102 | { |
---|
103 | va_list args; |
---|
104 | message_handler_func *log; |
---|
105 | int length; |
---|
106 | |
---|
107 | va_start(args, format); |
---|
108 | length = vsnprintf(NULL, 0, format, args); |
---|
109 | va_end(args); |
---|
110 | if (length >= 0) |
---|
111 | for (log = die_handlers; *log != NULL; log++) { |
---|
112 | va_start(args, format); |
---|
113 | (**log)(length, format, args, 0); |
---|
114 | va_end(args); |
---|
115 | } |
---|
116 | exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); |
---|
117 | } |
---|
118 | |
---|
119 | void |
---|
120 | sysdie(const char *format, ...) |
---|
121 | { |
---|
122 | va_list args; |
---|
123 | message_handler_func *log; |
---|
124 | int length; |
---|
125 | int error = errno; |
---|
126 | |
---|
127 | va_start(args, format); |
---|
128 | length = vsnprintf(NULL, 0, format, args); |
---|
129 | va_end(args); |
---|
130 | if (length >= 0) |
---|
131 | for (log = die_handlers; *log != NULL; log++) { |
---|
132 | va_start(args, format); |
---|
133 | (**log)(length, format, args, error); |
---|
134 | va_end(args); |
---|
135 | } |
---|
136 | exit(message_fatal_cleanup ? (*message_fatal_cleanup)() : 1); |
---|
137 | } |
---|