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