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