OpenDNSSEC-enforcer  1.4.1
message.c
Go to the documentation of this file.
1 /*
2  * $Id: message.c 7018 2013-02-05 13:59:43Z sion $
3  *
4  * Copyright (c) 2008-2009 Nominet UK. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  * notice, this list of conditions and the following disclaimer in the
13  * documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23  * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24  * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  *
27  */
28 
29 /*+
30  * message.c - Message Functions
31  *
32  * Abstract:
33  * The message module outputs error messages to the stdout.
34  *
35  * Modules register their message text and message code ranges with this
36  * module. When invoked, this module searches all the registered code
37  * ranges for one containing the status code in question, and takes the
38  * appropriate action.
39 -*/
40 
41 #include <stdarg.h>
42 #include <stdio.h>
43 #include <string.h>
44 
45 #include "ksm/message.h"
46 #include "ksm/string_util.h"
47 
48 #define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
49 #define MIN(X, Y) ((X) < (Y) ? (X) : (Y))
50 
52 int m_numblocks = 0; /* Count of code blocks */
53 
54 
55 /*+
56  * MsgInit - Initialize Message Processing
57  *
58  * Description:
59  * Initialises the message module.
60  *
61  * Arguments:
62  * None.
63 -*/
64 
65 void MsgInit(void)
66 {
67  m_codeblock = NULL;
68  m_numblocks = 0;
69 
70  return;
71 }
72 
73 
74 
75 /*+
76  * MsgDefaultOutput
77  *
78  * Description:
79  * Default output function; outputs a line of text to stdout.
80  *
81  * Arguments:
82  * const char* text
83  * Text to output.
84 -*/
85 
86 void MsgDefaultOutput(const char* text)
87 {
88  printf("%s\n", text);
89 
90  return;
91 }
92 
93 
94 
95 /*+
96  * MsgNoOutput - Produce No Output
97  *
98  * Description:
99  * Null output function; does not output anything.
100  *
101  * Arguments:
102  * const char* text
103  * Text (not) to output.
104 -*/
105 
106 void MsgNoOutput(const char* text)
107 {
108  /* Unused parameter*/
109  (void)text;
110 
111  return;
112 }
113 
114 
115 
116 /*+
117  * MsgRegister - Register Status Codes
118  *
119  * Description:
120  * Registers a block of status codes (and associated text) with the message
121  * module.
122  *
123  * Arguments:
124  * int min
125  * Minimum status code value in the range.
126  *
127  * int max
128  * Maximum status code value in the range.
129  *
130  * const char** message
131  * List of messages for each code. message[0] corresponds to
132  * a value of "min", message 1 to "min + 1" etc. There should be
133  * (max - min + 1) entries in this list.
134  *
135  * If a message entry is NULL, default text will be used.
136  *
137  * MSG_OUTPUT_FUNCTION output
138  * Output function used to output the text when MsgLog is called.
139  * If NULL, the default function (which outputs to stdout) will be
140  * used.
141 -*/
142 
143 void MsgRegister(int min, int max, const char** message,
144  MSG_OUTPUT_FUNCTION output)
145 {
146  if (m_numblocks == 0) {
147  m_codeblock = MemCalloc(1, sizeof(MSG_CODEBLOCK));
148  }
149  else {
150  m_codeblock = MemRealloc(m_codeblock,
151  (m_numblocks + 1) * sizeof(MSG_CODEBLOCK));
152  }
153 
154  /*
155  * Fill in the code block. On the principle of "being liberal with what
156  * you accept", allow the caller to get max and min confused.
157  */
158 
159  m_codeblock[m_numblocks].min = MIN(min, max);
160  m_codeblock[m_numblocks].max = MAX(min, max);
161  m_codeblock[m_numblocks].message = message;
162  m_codeblock[m_numblocks].output = output ? output : MsgDefaultOutput;
163 
164  ++m_numblocks;
165 
166  return;
167 }
168 
169 
170 
171 /*+
172  * MsgFindCodeBlock - Find Code Block
173  *
174  * Description:
175  * Local function used to locate the code block for a particular status
176  * code.
177  *
178  * Arguments:
179  * int status
180  * Status code for which the block is sought.
181  *
182  * Returns:
183  * int
184  * Index into the code block array of the appropriate block, or -1
185  * if no block contains that status code.
186 -*/
187 
188 int MsgFindCodeBlock(int status)
189 {
190  int block = -1; /* Returned code block */
191  int i; /* Loop counter */
192 
193  for (i = 0; i < m_numblocks; ++i) {
194  if ((status >= m_codeblock[i].min) && (status <= m_codeblock[i].max)) {
195  block = i;
196  break;
197  }
198  }
199 
200  return block;
201 }
202 
203 
204 
205 /*+
206  * MsgText - Return Error Message Text
207  *
208  * Description:
209  * Returns message text associated with the status code.
210  *
211  * Arguments:
212  * int status
213  * Status code. If one of the registered message codes, the
214  * corresponding text will be returned, otherwise it will be the text
215  * returned by strerror.
216  *
217  * Returns:
218  * const char*
219  * Pointer to the message text. This is a pointer to internal
220  * memory, and should not be modified or freed by the caller.
221  *
222  * Note that this could be NULL if strerror() felt so inclined.
223 -*/
224 
225 const char* MsgText(int status)
226 {
227  int block; /* Code block associated with the message */
228  const char* text = NULL; /* Returned message */
229 
230  block = MsgFindCodeBlock(status);
231  if (block >= 0) {
232  text = m_codeblock[block].message[status - m_codeblock[block].min];
233  }
234 
235  if (text == NULL) {
236  text = strerror(status);
237  }
238 
239  return text;
240 }
241 
242 
243 
244 /*+
245  * MsgGetOutput - Get Current Output Function
246  *
247  * Description:
248  * Returns the current output function for a particular status code range.
249  *
250  * Arguments:
251  * int status
252  * Status code within the specified range.
253  *
254  * Returns:
255  * MSG_OUTPUT_FUNCTION
256  * Pointer to the current output function. NULL if the code is not
257  * recognised.
258 -*/
259 
261 {
262  int block; /* Block number */
263  MSG_OUTPUT_FUNCTION output = NULL; /* Returned function */
264 
265  /* Locate the output function */
266 
267  block = MsgFindCodeBlock(status);
268  if (block != -1) {
269  output = m_codeblock[block].output;
270  }
271 
272  return output;
273 }
274 
275 
276 
277 /*+
278  * MsgSetOutput - Set Current Output Function
279  *
280  * Description:
281  * Sets the current output function for a particular status code range.
282  *
283  * Arguments:
284  * int status
285  * Status code within the specified range.
286  *
287  * MSG_OUTPUT_FUNCTION output
288  * Output function. If NULL, the default output function (which
289  * outputs to stdout) will be used.
290 -*/
291 
292 void MsgSetOutput(int status, MSG_OUTPUT_FUNCTION output)
293 {
294  int block; /* Block number */
295 
296  /* Locate the output function */
297 
298  block = MsgFindCodeBlock(status);
299  if (block != -1) {
300  m_codeblock[block].output = output ? output : MsgDefaultOutput;
301  }
302 
303  return;
304 }
305 
306 
307 
308 /*+
309  * MsgLog - Log Message
310  *
311  * Description:
312  * Obtains the message text, substitutes any parameters, and uses the
313  * output function associated with that status code to output it.
314  *
315  * Note that it uses an internal buffer to expand the message, so there is
316  * a 4096-byte limit on the size of the message output.
317  *
318  * Arguments:
319  * int status
320  * Status code used to access a format string that is the used to
321  * format the remaining arguments.
322  *
323  * ...
324  * Arguments for the format string.
325  *
326  * Returns:
327  * int
328  * Always identical to the status passed in. This allows constructs
329  * of the form:
330  *
331  * return MsgLog(error_number...)
332  *
333  * ... which both reports the stored error and returns the error number
334  * to the caller.
335  */
336 
337 int MsgLog(int status, ...)
338 {
339  va_list ap; /* Variable arguments */
340  int retstat; /* Return status */
341 
342  va_start(ap, status);
343  retstat = MsgLogAp(status, ap);
344  va_end(ap);
345 
346  return retstat;
347 }
348 
349 
350 
351 /*+
352  * MsgLogAp - Log Message With Variable Arguments
353  *
354  * Description:
355  * See MsgLog.
356  *
357  * This function is used when the variable arguments are in the form of
358  * a variable argument list.
359  *
360  * Arguments:
361  * int status
362  * Status code. This is a format string that is used to format
363  * the remaining arguments.
364  *
365  * va_list ap
366  * Arguments for the format
367  *
368  * Returns:
369  * int
370  * See MsgLog.
371  */
372 
373 int MsgLogAp(int status, va_list ap)
374 {
375  char buffer[4096]; /* Buffer to store the text */
376  const char* message; /* Message string */
377  MSG_OUTPUT_FUNCTION output = NULL;
378 
379  /* Locate the text for the message and use it to format the text */
380 
381  message = MsgText(status);
382  if (message) {
383  vsnprintf(buffer, sizeof(buffer), message, ap);
384  buffer[sizeof(buffer) - 1] = '\0'; /* Ensure trailing NULL */
385 
386  output = MsgGetOutput(status);
387  }
388  else {
389  snprintf(buffer, sizeof(buffer), "?????: unknown message number %d", status);
390  output = MsgDefaultOutput;
391  }
392 
393  /* If a function is available, use it to output the error */
394 
395  if (output) {
396  (*output)(buffer);
397  }
398 
399  return status;
400 }
401 
402 
403 /*+
404  * MsgRundown - Rundown Message Module
405  *
406  * Description:
407  * Frees up any resources allocated to the message module and resets it to
408  * the initial conditions.
409  *
410  * Arguments:
411  * None.
412 -*/
413 
414 void MsgRundown(void)
415 {
416  if (m_codeblock) {
417  MemFree(m_codeblock);
418  m_codeblock = NULL;
419  }
420 
421  m_numblocks = 0;
422 
423  return;
424 }
425 
426