Imported Upstream version 1.8.7
[debian/sudo] / common / error.c
1 /*
2  * Copyright (c) 2004-2005, 2010-2013 Todd C. Miller <Todd.Miller@courtesan.com>
3  *
4  * Permission to use, copy, modify, and distribute this software for any
5  * purpose with or without fee is hereby granted, provided that the above
6  * copyright notice and this permission notice appear in all copies.
7  *
8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15  */
16
17 #include <config.h>
18
19 #include <sys/types.h>
20
21 #include <errno.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #ifdef HAVE_STDBOOL_H
26 # include <stdbool.h>
27 #else
28 # include "compat/stdbool.h"
29 #endif /* HAVE_STDBOOL_H */
30
31 #include "missing.h"
32 #include "alloc.h"
33 #include "error.h"
34 #include "sudo_plugin.h"
35
36 #define DEFAULT_TEXT_DOMAIN     "sudo"
37 #include "gettext.h"
38
39 sigjmp_buf fatal_jmp;
40 static bool setjmp_enabled = false;
41 static struct sudo_fatal_callback {
42     void (*func)(void);
43     struct sudo_fatal_callback *next;
44 } *callbacks;
45
46 static void _warning(int, const char *, va_list);
47
48 static void
49 do_cleanup(void)
50 {
51     struct sudo_fatal_callback *cb;
52
53     /* Run callbacks, removing them from the list as we go. */
54     while ((cb = callbacks) != NULL) {
55         callbacks = cb->next;
56         cb->func();
57         free(cb);
58     }
59 }
60
61 void
62 fatal2(const char *fmt, ...)
63 {
64     va_list ap;
65
66     va_start(ap, fmt);
67     _warning(1, fmt, ap);
68     va_end(ap);
69     do_cleanup();
70     if (setjmp_enabled)
71         siglongjmp(fatal_jmp, 1);
72     else
73         exit(EXIT_FAILURE);
74 }
75
76 void
77 fatalx2(const char *fmt, ...)
78 {
79     va_list ap;
80
81     va_start(ap, fmt);
82     _warning(0, fmt, ap);
83     va_end(ap);
84     do_cleanup();
85     if (setjmp_enabled)
86         siglongjmp(fatal_jmp, 1);
87     else
88         exit(EXIT_FAILURE);
89 }
90
91 void
92 vfatal2(const char *fmt, va_list ap)
93 {
94     _warning(1, fmt, ap);
95     do_cleanup();
96     if (setjmp_enabled)
97         siglongjmp(fatal_jmp, 1);
98     else
99         exit(EXIT_FAILURE);
100 }
101
102 void
103 vfatalx2(const char *fmt, va_list ap)
104 {
105     _warning(0, fmt, ap);
106     do_cleanup();
107     if (setjmp_enabled)
108         siglongjmp(fatal_jmp, 1);
109     else
110         exit(EXIT_FAILURE);
111 }
112
113 void
114 warning2(const char *fmt, ...)
115 {
116     va_list ap;
117
118     va_start(ap, fmt);
119     _warning(1, fmt, ap);
120     va_end(ap);
121 }
122
123 void
124 warningx2(const char *fmt, ...)
125 {
126     va_list ap;
127     va_start(ap, fmt);
128     _warning(0, fmt, ap);
129     va_end(ap);
130 }
131
132 void
133 vwarning2(const char *fmt, va_list ap)
134 {
135     _warning(1, fmt, ap);
136 }
137
138 void
139 vwarningx2(const char *fmt, va_list ap)
140 {
141     _warning(0, fmt, ap);
142 }
143
144 static void
145 _warning(int use_errno, const char *fmt, va_list ap)
146 {
147     int serrno = errno;
148     char *str;
149
150     evasprintf(&str, fmt, ap);
151     if (use_errno) {
152         if (fmt != NULL) {
153             sudo_printf(SUDO_CONV_ERROR_MSG,
154                 _("%s: %s: %s\n"), getprogname(), str, strerror(serrno));
155         } else {
156             sudo_printf(SUDO_CONV_ERROR_MSG,
157                 _("%s: %s\n"), getprogname(), strerror(serrno));
158         }
159     } else {
160         sudo_printf(SUDO_CONV_ERROR_MSG,
161             _("%s: %s\n"), getprogname(), str ? str : "(null)");
162     }
163     efree(str);
164     errno = serrno;
165 }
166
167 int
168 fatal_callback_register(void (*func)(void))
169 {
170     struct sudo_fatal_callback *cb;
171
172     cb = malloc(sizeof(*cb));
173     if (cb == NULL)
174         return -1;
175     cb->func = func;
176     cb->next = callbacks;
177     callbacks = cb;
178
179     return 0;
180 }
181
182 void
183 fatal_disable_setjmp(void)
184 {
185     setjmp_enabled = false;
186 }
187
188 void
189 fatal_enable_setjmp(void)
190 {
191     setjmp_enabled = true;
192 }