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