xref: /illumos-gate/usr/src/cmd/fm/eversholt/common/out.c (revision 9164a50bf932130cbb5097a16f6986873ce0e6e5)
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
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
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
93 out_altfp(FILE *fp)
94 {
95 	Altfp = fp;
96 }
97 
98 /*
99  * voutbufprintf -- like vprintf, but appends to Outbuf
100  */
101 static void
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
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
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
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
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
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
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
291 out_warncount(void)
292 {
293 	return (stats_counter_value(Warncount));
294 }
295