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 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 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 95 out_altfp(FILE *fp) 96 { 97 Altfp = fp; 98 } 99 100 /* 101 * voutbufprintf -- like vprintf, but appends to Outbuf 102 */ 103 static void 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 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 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 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 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 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 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 293 out_warncount(void) 294 { 295 return (stats_counter_value(Warncount)); 296 } 297