OpenDNSSEC-enforcer  1.3.14
message.c
Go to the documentation of this file.
1 /*
2  * $Id: message.c 4169 2010-11-04 14:24:23Z 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 /*+
57  * MsgInit - Initialize Message Processing
58  *
59  * Description:
60  * Initialises the message module.
61  *
62  * Arguments:
63  * None.
64 -*/
65 
66 void MsgInit(void)
67 {
68  m_codeblock = NULL;
69  m_numblocks = 0;
70 
71  return;
72 }
73 
74 
75 
76 /*+
77  * MsgDefaultOutput
78  *
79  * Description:
80  * Default output function; outputs a line of text to stdout.
81  *
82  * Arguments:
83  * const char* text
84  * Text to output.
85 -*/
86 
87 void MsgDefaultOutput(const char* text)
88 {
89  printf("%s\n", text);
90 
91  return;
92 }
93 
94 
95 
96 /*+
97  * MsgNoOutput - Produce No Output
98  *
99  * Description:
100  * Null output function; does not output anything.
101  *
102  * Arguments:
103  * const char* text
104  * Text (not) to output.
105 -*/
106 
107 void MsgNoOutput(const char* text)
108 {
109  /* Unused parameter*/
110  (void)text;
111 
112  return;
113 }
114 
115 
116 
117 /*+
118  * MsgRegister - Register Status Codes
119  *
120  * Description:
121  * Registers a block of status codes (and associated text) with the message
122  * module.
123  *
124  * Arguments:
125  * int min
126  * Minimum status code value in the range.
127  *
128  * int max
129  * Maximum status code value in the range.
130  *
131  * const char** message
132  * List of messages for each code. message[0] corresponds to
133  * a value of "min", message 1 to "min + 1" etc. There should be
134  * (max - min + 1) entries in this list.
135  *
136  * If a message entry is NULL, default text will be used.
137  *
138  * MSG_OUTPUT_FUNCTION output
139  * Output function used to output the text when MsgLog is called.
140  * If NULL, the default function (which outputs to stdout) will be
141  * used.
142 -*/
143 
144 void MsgRegister(int min, int max, const char** message,
145  MSG_OUTPUT_FUNCTION output)
146 {
147  if (m_numblocks == 0) {
148  m_codeblock = MemCalloc(1, sizeof(MSG_CODEBLOCK));
149  }
150  else {
151  m_codeblock = MemRealloc(m_codeblock,
152  (m_numblocks + 1) * sizeof(MSG_CODEBLOCK));
153  }
154 
155  /*
156  * Fill in the code block. On the principle of "being liberal with what
157  * you accept", allow the caller to get max and min confused.
158  */
159 
160  m_codeblock[m_numblocks].min = MIN(min, max);
161  m_codeblock[m_numblocks].max = MAX(min, max);
162  m_codeblock[m_numblocks].message = message;
163  m_codeblock[m_numblocks].output = output ? output : MsgDefaultOutput;
164 
165  ++m_numblocks;
166 
167  return;
168 }
169 
170 
171 
172 /*+
173  * MsgFindCodeBlock - Find Code Block
174  *
175  * Description:
176  * Local function used to locate the code block for a particular status
177  * code.
178  *
179  * Arguments:
180  * int status
181  * Status code for which the block is sought.
182  *
183  * Returns:
184  * int
185  * Index into the code block array of the appropriate block, or -1
186  * if no block contains that status code.
187 -*/
188 
189 int MsgFindCodeBlock(int status)
190 {
191  int block = -1; /* Returned code block */
192  int i; /* Loop counter */
193 
194  for (i = 0; i < m_numblocks; ++i) {
195  if ((status >= m_codeblock[i].min) && (status <= m_codeblock[i].max)) {
196  block = i;
197  break;
198  }
199  }
200 
201  return block;
202 }
203 
204 
205 
206 /*+
207  * MsgText - Return Error Message Text
208  *
209  * Description:
210  * Returns message text associated with the status code.
211  *
212  * Arguments:
213  * int status
214  * Status code. If one of the registered message codes, the
215  * corresponding text will be returned, otherwise it will be the text
216  * returned by strerror.
217  *
218  * Returns:
219  * const char*
220  * Pointer to the message text. This is a pointer to internal
221  * memory, and should not be modified or freed by the caller.
222  *
223  * Note that this could be NULL if strerror() felt so inclined.
224 -*/
225 
226 const char* MsgText(int status)
227 {
228  int block; /* Code block associated with the message */
229  const char* text = NULL; /* Returned message */
230 
231  block = MsgFindCodeBlock(status);
232  if (block >= 0) {
233  text = m_codeblock[block].message[status - m_codeblock[block].min];
234  }
235 
236  if (text == NULL) {
237  text = strerror(status);
238  }
239 
240  return text;
241 }
242 
243 
244 
245 /*+
246  * MsgGetOutput - Get Current Output Function
247  *
248  * Description:
249  * Returns the current output function for a particular status code range.
250  *
251  * Arguments:
252  * int status
253  * Status code within the specified range.
254  *
255  * Returns:
256  * MSG_OUTPUT_FUNCTION
257  * Pointer to the current output function. NULL if the code is not
258  * recognised.
259 -*/
260 
262 {
263  int block; /* Block number */
264  MSG_OUTPUT_FUNCTION output = NULL; /* Returned function */
265 
266  /* Locate the output function */
267 
268  block = MsgFindCodeBlock(status);
269  if (block != -1) {
270  output = m_codeblock[block].output;
271  }
272 
273  return output;
274 }
275 
276 
277 
278 /*+
279  * MsgSetOutput - Set Current Output Function
280  *
281  * Description:
282  * Sets the current output function for a particular status code range.
283  *
284  * Arguments:
285  * int status
286  * Status code within the specified range.
287  *
288  * MSG_OUTPUT_FUNCTION output
289  * Output function. If NULL, the default output function (which
290  * outputs to stdout) will be used.
291 -*/
292 
293 void MsgSetOutput(int status, MSG_OUTPUT_FUNCTION output)
294 {
295  int block; /* Block number */
296 
297  /* Locate the output function */
298 
299  block = MsgFindCodeBlock(status);
300  if (block != -1) {
301  m_codeblock[block].output = output ? output : MsgDefaultOutput;
302  }
303 
304  return;
305 }
306 
307 
308 
309 /*+
310  * MsgLog - Log Message
311  *
312  * Description:
313  * Obtains the message text, substitutes any parameters, and uses the
314  * output function associated with that status code to output it.
315  *
316  * Note that it uses an internal buffer to expand the message, so there is
317  * a 4096-byte limit on the size of the message output.
318  *
319  * Arguments:
320  * int status
321  * Status code used to access a format string that is the used to
322  * format the remaining arguments.
323  *
324  * ...
325  * Arguments for the format string.
326  *
327  * Returns:
328  * int
329  * Always identical to the status passed in. This allows constructs
330  * of the form:
331  *
332  * return MsgLog(error_number...)
333  *
334  * ... which both reports the stored error and returns the error number
335  * to the caller.
336  */
337 
338 int MsgLog(int status, ...)
339 {
340  va_list ap; /* Variable arguments */
341  int retstat; /* Return status */
342 
343  va_start(ap, status);
344  retstat = MsgLogAp(status, ap);
345  va_end(ap);
346 
347  return retstat;
348 }
349 
350 
351 
352 /*+
353  * MsgLogAp - Log Message With Variable Arguments
354  *
355  * Description:
356  * See MsgLog.
357  *
358  * This function is used when the variable arguments are in the form of
359  * a variable argument list.
360  *
361  * Arguments:
362  * int status
363  * Status code. This is a format string that is used to format
364  * the remaining arguments.
365  *
366  * va_list ap
367  * Arguments for the format
368  *
369  * Returns:
370  * int
371  * See MsgLog.
372  */
373 
374 int MsgLogAp(int status, va_list ap)
375 {
376  char buffer[4096]; /* Buffer to store the text */
377  const char* message; /* Message string */
378  MSG_OUTPUT_FUNCTION output = NULL;
379 
380  /* Locate the text for the message and use it to format the text */
381 
382  message = MsgText(status);
383  if (message) {
384  vsnprintf(buffer, sizeof(buffer), message, ap);
385  buffer[sizeof(buffer) - 1] = '\0'; /* Ensure trailing NULL */
386 
387  output = MsgGetOutput(status);
388  }
389  else {
390  snprintf(buffer, sizeof(buffer), "?????: unknown message number %d", status);
391  output = MsgDefaultOutput;
392  }
393 
394  /* If a function is available, use it to output the error */
395 
396  if (output) {
397  (*output)(buffer);
398  }
399 
400  return status;
401 }
402 
403 
404 /*+
405  * MsgRundown - Rundown Message Module
406  *
407  * Description:
408  * Frees up any resources allocated to the message module and resets it to
409  * the initial conditions.
410  *
411  * Arguments:
412  * None.
413 -*/
414 
415 void MsgRundown(void)
416 {
417  if (m_codeblock) {
418  MemFree(m_codeblock);
419  m_codeblock = NULL;
420  }
421 
422  m_numblocks = 0;
423 
424  return;
425 }