1 /*
2 * Copyright (c) 2011 Collabora Ltd
3 * Copyright (c) 2012 Stef Walter
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * * Redistributions of source code must retain the above
10 * copyright notice, this list of conditions and the
11 * following disclaimer.
12 * * Redistributions in binary form must reproduce the
13 * above copyright notice, this list of conditions and
14 * the following disclaimer in the documentation and/or
15 * other materials provided with the distribution.
16 * * The names of contributors to this software may not be
17 * used to endorse or promote products derived from this
18 * software without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24 * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27 * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
30 * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31 * DAMAGE.
32 *
33 *
34 * CONTRIBUTORS
35 * Stef Walter <stef@thewalter.net>
36 */
37
38 #include "config.h"
39
40 /*
41 * Oh god. glibc is nasty. Changes behavior and definitions of POSIX
42 * functions to completely different signatures depending on defines
43 */
44 #if !defined(__DragonFly__)
45 #define _POSIX_C_SOURCE 200112L
46 #endif
47
48 #include "compat.h"
49 #define P11_DEBUG_FLAG P11_DEBUG_LIB
50 #include "debug.h"
51 #include "message.h"
52
53 #include <assert.h>
54 #include <errno.h>
55 #ifdef HAVE_LOCALE_H
56 #include <locale.h>
57 #endif
58 #include <stdarg.h>
59 #include <stdlib.h>
60 #include <stdio.h>
61 #include <string.h>
62
63 bool p11_print_messages = false;
64
65 #ifdef HAVE_STRERROR_L
66 locale_t p11_message_locale = (locale_t) 0;
67 #endif
68
69 static char *
default_message_storage(void)70 default_message_storage (void)
71 {
72 static char message[P11_MESSAGE_MAX] = { 0, };
73 return message;
74 }
75
76 /* Function pointer declared in message.h as extern */
77 char * (* p11_message_storage) (void) = default_message_storage;
78
79 void
p11_message_store(const char * msg,size_t length)80 p11_message_store (const char* msg,
81 size_t length)
82 {
83 char *buffer;
84
85 /*
86 * p11_message_storage() is called to get a storage location for
87 * the last message. It defaults to a globally allocated buffer
88 * but is overridden in library.c with a function that returns
89 * per thread buffers.
90 *
91 * The returned value is P11_MESSAGE_MAX bytes long
92 */
93 buffer = p11_message_storage ();
94
95 if (length > P11_MESSAGE_MAX - 1)
96 length = P11_MESSAGE_MAX - 1;
97
98 if (buffer != NULL) {
99 memcpy (buffer, msg, length);
100 buffer[length] = 0;
101 }
102 }
103
104 void
p11_message_err(int errnum,const char * msg,...)105 p11_message_err (int errnum,
106 const char* msg,
107 ...)
108 {
109 char buffer[P11_MESSAGE_MAX];
110 char strerr[P11_MESSAGE_MAX];
111 va_list va;
112 size_t length;
113
114 va_start (va, msg);
115 length = vsnprintf (buffer, P11_MESSAGE_MAX - 1, msg, va);
116 va_end (va);
117
118 /* Was it truncated? */
119 if (length > P11_MESSAGE_MAX - 1)
120 length = P11_MESSAGE_MAX - 1;
121 buffer[length] = 0;
122
123 snprintf (strerr, sizeof (strerr), "Unknown error %d", errnum);
124 #ifdef HAVE_STRERROR_L
125 if (p11_message_locale != (locale_t) 0)
126 strncpy (strerr, strerror_l (errnum, p11_message_locale), sizeof (strerr));
127 #else
128 strerror_r (errnum, strerr, sizeof (strerr));
129 #endif
130 strerr[P11_MESSAGE_MAX - 1] = 0;
131
132 p11_message ("%s: %s", buffer, strerr);
133 }
134
135 void
p11_message(const char * msg,...)136 p11_message (const char* msg,
137 ...)
138 {
139 char buffer[P11_MESSAGE_MAX];
140 va_list va;
141 size_t length;
142
143 va_start (va, msg);
144 length = vsnprintf (buffer, P11_MESSAGE_MAX - 1, msg, va);
145 va_end (va);
146
147 /* Was it truncated? */
148 if (length > P11_MESSAGE_MAX - 1)
149 length = P11_MESSAGE_MAX - 1;
150 buffer[length] = 0;
151
152 /* If printing is not disabled, just print out */
153 if (p11_print_messages)
154 fprintf (stderr, "p11-kit: %s\n", buffer);
155 else
156 p11_debug_message (P11_DEBUG_LIB, "message: %s", buffer);
157 p11_message_store (buffer, length);
158 }
159
160 void
p11_message_quiet(void)161 p11_message_quiet (void)
162 {
163 p11_print_messages = false;
164 }
165
166 void
p11_message_loud(void)167 p11_message_loud (void)
168 {
169 p11_print_messages = true;
170 }
171
172 const char *
p11_message_last(void)173 p11_message_last (void)
174 {
175 char *buffer;
176 buffer = p11_message_storage ();
177 return buffer && buffer[0] ? buffer : NULL;
178 }
179
180 void
p11_message_clear(void)181 p11_message_clear (void)
182 {
183 char *buffer;
184 buffer = p11_message_storage ();
185 if (buffer != NULL)
186 buffer[0] = 0;
187 }
188