Initial commit to Gerrit
[profile/ivi/ntp.git] / ElectricFence / print.c
1 #include "efence.h"
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <stdarg.h>
5 #include <string.h>
6 #include <signal.h>
7
8 /*
9  * These routines do their printing without using stdio. Stdio can't
10  * be used because it calls malloc(). Internal routines of a malloc()
11  * debugger should not re-enter malloc(), so stdio is out.
12  */
13
14 /*
15  * NUMBER_BUFFER_SIZE is the longest character string that could be needed
16  * to represent an unsigned integer, assuming we might print in base 2.
17  */
18 #define NUMBER_BUFFER_SIZE      (sizeof(ef_number) * NBBY)
19
20 static void
21 printNumber(ef_number number, ef_number base)
22 {
23         char            buffer[NUMBER_BUFFER_SIZE];
24         char *          s = &buffer[NUMBER_BUFFER_SIZE];
25         int             size;
26         
27         do {
28                 ef_number       digit;
29
30                 if ( --s == buffer )
31                         EF_Abort("Internal error printing number.");
32
33                 digit = number % base;
34
35                 if ( digit < 10 )
36                         *s = '0' + digit;
37                 else
38                         *s = 'a' + digit - 10;
39
40         } while ( (number /= base) > 0 );
41
42         size = &buffer[NUMBER_BUFFER_SIZE] - s;
43
44         if ( size > 0 )
45                 write(2, s, size);
46 }
47
48 static void
49 vprint(const char * pattern, va_list args)
50 {
51         static const char       bad_pattern[] =
52          "\nBad pattern specifier %%%c in EF_Print().\n";
53         const char *    s = pattern;
54         char            c;
55
56         while ( (c = *s++) != '\0' ) {
57                 if ( c == '%' ) {
58                         c = *s++;
59                         switch ( c ) {
60                         case '%':
61                                 (void) write(2, &c, 1);
62                                 break;
63                         case 'a':
64                                 /*
65                                  * Print an address passed as a void pointer.
66                                  * The type of ef_number must be set so that
67                                  * it is large enough to contain all of the
68                                  * bits of a void pointer.
69                                  */
70                                 printNumber(
71                                  (ef_number)va_arg(args, void *)
72                                 ,0x10);
73                                 break;
74                         case 's':
75                                 {
76                                         const char *    string;
77                                         size_t          length;
78
79                                         string = va_arg(args, char *);
80                                         length = strlen(string);
81
82                                         (void) write(2, string, length);
83                                 }
84                                 break;
85                         case 'd':
86                                 {
87                                         int     n = va_arg(args, int);
88
89                                         if ( n < 0 ) {
90                                                 char    c = '-';
91                                                 write(2, &c, 1);
92                                                 n = -n;
93                                         }
94                                         printNumber(n, 10);
95                                 }
96                                 break;
97                         case 'x':
98                                 printNumber(va_arg(args, u_int), 0x10);
99                                 break;
100                         case 'c':
101                                 {
102                                         char    c = va_arg(args, char);
103                                         
104                                         (void) write(2, &c, 1);
105                                 }
106                                 break;
107                         default:
108                                 {
109                                         EF_Print(bad_pattern, c);
110                                 }
111                 
112                         }
113                 }
114                 else
115                         (void) write(2, &c, 1);
116         }
117 }
118
119 void
120 EF_Abort(const char * pattern, ...)
121 {
122         va_list args;
123
124         va_start(args, pattern);
125
126         EF_Print("\nElectricFence Aborting: ");
127         vprint(pattern, args);
128         EF_Print("\n");
129
130         va_end(args);
131
132         /*
133          * I use kill(getpid(), SIGILL) instead of abort() because some
134          * mis-guided implementations of abort() flush stdio, which can
135          * cause malloc() or free() to be called.
136          */
137         kill(getpid(), SIGILL);
138         /* Just in case something handles SIGILL and returns, exit here. */
139         _exit(-1);
140 }
141
142 void
143 EF_Exit(const char * pattern, ...)
144 {
145         va_list args;
146
147         va_start(args, pattern);
148
149         EF_Print("\nElectricFence Exiting: ");
150         vprint(pattern, args);
151         EF_Print("\n");
152
153         va_end(args);
154
155         /*
156          * I use _exit() because the regular exit() flushes stdio,
157          * which may cause malloc() or free() to be called.
158          */
159         _exit(-1);
160 }
161
162 void
163 EF_Print(const char * pattern, ...)
164 {
165         va_list args;
166
167         va_start(args, pattern);
168         vprint(pattern, args);
169         va_end(args);
170 }