1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22 /*
23 * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 *
26 * out.c -- some basic output routines
27 *
28 */
29
30 #pragma ident "%Z%%M% %I% %E% SMI"
31
32 #include <stdio.h>
33 #include <fm/fmd_api.h>
34 #include <unistd.h>
35 #include <stdlib.h>
36 #include <stdarg.h>
37 #include <string.h>
38 #include <strings.h>
39 #include <errno.h>
40 #include <time.h>
41 #include "out.h"
42 #include "stats.h"
43 #include "io.h"
44
45 /* stats we keep for "out" module */
46 static struct stats *Outcount;
47 static struct stats *Errcount;
48 static struct stats *Warncount;
49
50 static int Exitcode;
51
52 static const char *Myname;
53 static FILE *Altfp;
54
55 /* buffer used to format all prints */
56 #define MAXOUT 8192
57 static char Outbuf[MAXOUT];
58 static int Outidx; /* next unused char in Outbuf[] */
59
60 /*
61 * out_init -- initialize this module
62 */
63 void
out_init(const char * myname)64 out_init(const char *myname)
65 {
66 Outcount = stats_new_counter("output.calls", "total calls", 1);
67 Errcount = stats_new_counter("output.errors", "total errors", 0);
68 Warncount = stats_new_counter("output.warnings", "total warnings", 0);
69
70 if (myname == NULL)
71 return;
72
73 if ((Myname = strrchr(myname, '/')) == NULL &&
74 (Myname = strrchr(myname, '\\')) == NULL)
75 Myname = myname;
76 else
77 Myname++;
78 }
79
80 void
out_fini(void)81 out_fini(void)
82 {
83 stats_delete(Outcount);
84 Outcount = NULL;
85 stats_delete(Errcount);
86 Errcount = NULL;
87 stats_delete(Warncount);
88 Warncount = NULL;
89 }
90
91 /*
92 * out_altfp -- store an alternate fp for O_ALTFP
93 */
94 void
out_altfp(FILE * fp)95 out_altfp(FILE *fp)
96 {
97 Altfp = fp;
98 }
99
100 /*
101 * voutbufprintf -- like vprintf, but appends to Outbuf
102 */
103 static void
voutbufprintf(const char * fmt,va_list ap)104 voutbufprintf(const char *fmt, va_list ap)
105 {
106 int len = vsnprintf(&Outbuf[Outidx], MAXOUT - Outidx, fmt, ap);
107
108 Outidx += len;
109 if (Outidx >= MAXOUT)
110 Outidx = MAXOUT - 1;
111 }
112
113 /*
114 * outbufprintf -- like printf, but appends to Outbuf
115 */
116 /*PRINTFLIKE1*/
117 static void
outbufprintf(const char * fmt,...)118 outbufprintf(const char *fmt, ...)
119 {
120 va_list ap;
121 va_start(ap, fmt);
122 voutbufprintf(fmt, ap);
123 va_end(ap);
124 }
125
126 /*
127 * vout -- va_list version of out()
128 *
129 * all the output processing work is done here.
130 */
131 static void
vout(int flags,const char * fmt,va_list ap)132 vout(int flags, const char *fmt, va_list ap)
133 {
134 int safe_errno = errno;
135
136 stats_counter_bump(Outcount);
137
138 /*
139 * just return if called with a disabled output type. this
140 * prevents debug prints when Debug is off, verbose prints
141 * when Verbose is off, and language warnings when warnings
142 * are quenched (which they are when we're loading a .eft file).
143 *
144 */
145 if ((flags & O_DEBUG) && Debug == 0)
146 return;
147
148 if ((flags & O_VERB) && Verbose == 0)
149 return;
150
151 if ((flags & O_VERB2) && Verbose < 2)
152 return;
153
154 if ((flags & O_VERB3) && Verbose < 3)
155 return;
156
157 if ((flags & O_WARN) && Warn == 0)
158 return;
159
160 if ((flags & O_ALTFP) && Altfp == NULL)
161 return;
162
163 /* some things only happen at the beginning of a print */
164 if (Outidx == 0) {
165 if (flags & O_USAGE) {
166 Exitcode++;
167 outbufprintf("usage: %s ", Myname);
168 } else {
169 if (Myname && flags & (O_DIE|O_ERR|O_WARN|O_PROG))
170 outbufprintf("%s: ", Myname);
171
172 if (flags & O_DIE) {
173 Exitcode++;
174 outbufprintf("fatal error: ");
175 } else if (flags & O_ERR) {
176 Exitcode++;
177 stats_counter_bump(Errcount);
178 outbufprintf("error: ");
179 } else if (flags & O_WARN) {
180 stats_counter_bump(Warncount);
181 outbufprintf("warning: ");
182 }
183 }
184 }
185
186 /* fmt can be NULL if the caller just wanted flags processed */
187 if (fmt != NULL)
188 voutbufprintf(fmt, ap);
189
190 /* O_SYS means convert errno to a string and append it */
191 if (flags & O_SYS) {
192 const char *msg = strerror(safe_errno);
193
194 if (Outidx != 0)
195 outbufprintf(": ");
196
197 if (msg)
198 outbufprintf("%s", msg);
199 else
200 outbufprintf("(error %d)", safe_errno);
201 }
202
203 /* O_STAMP means convert add a timestamp */
204 if (flags & O_STAMP) {
205 time_t clock;
206 char *tmsg;
207
208 (void) time(&clock);
209 tmsg = ctime(&clock);
210 if (tmsg && *tmsg) {
211 tmsg[strlen(tmsg) - 1] = '\0';
212
213 if (Outidx != 0)
214 outbufprintf(" ");
215
216 outbufprintf("%s", tmsg);
217 }
218 }
219
220 if (flags & O_NONL)
221 return; /* not done filling Outbuf */
222
223 /* done filling Outbuf, platform calls will add newline */
224 if (flags & O_ALTFP)
225 (void) fprintf(Altfp, "%s\n", Outbuf);
226 else if (flags & O_ABORT)
227 io_abort(Outbuf);
228 else if (flags & O_DIE)
229 io_die(Outbuf);
230 else if (flags & O_ERR)
231 io_err(Outbuf);
232 else
233 io_out(Outbuf);
234
235 /* reset output buffer */
236 Outidx = 0;
237 Outbuf[0] = '\0';
238 }
239
240 /*
241 * out -- spew a line of output, with various options
242 */
243 /*PRINTFLIKE2*/
244 void
out(int flags,const char * fmt,...)245 out(int flags, const char *fmt, ...)
246 {
247 va_list ap;
248 va_start(ap, fmt);
249 vout(flags, fmt, ap);
250 va_end(ap);
251 }
252
253 /*
254 * outfl -- spew a filename:linenumber message
255 */
256 /*PRINTFLIKE4*/
257 void
outfl(int flags,const char * fname,int line,const char * fmt,...)258 outfl(int flags, const char *fname, int line, const char *fmt, ...)
259 {
260 va_list ap;
261 va_start(ap, fmt);
262
263 if (fname)
264 out(flags|O_NONL, "%s:%d: ", fname, line);
265
266 vout(flags, fmt, ap);
267
268 va_end(ap);
269 }
270
271 /*
272 * out_exit -- exit the program
273 */
274 void
out_exit(int code)275 out_exit(int code)
276 {
277 io_exit(Exitcode + code);
278 }
279
280 /*
281 * out_errcount -- return the number of O_ERR messages issued so far
282 */
283 int
out_errcount(void)284 out_errcount(void)
285 {
286 return (stats_counter_value(Errcount));
287 }
288
289 /*
290 * out_warncount -- return the number of O_WARN messages issued so far
291 */
292 int
out_warncount(void)293 out_warncount(void)
294 {
295 return (stats_counter_value(Warncount));
296 }
297