1/*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 4. Neither the name of the University nor the names of its contributors 14 * may be used to endorse or promote products derived from this software 15 * without specific prior written permission. 16 * 17 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30#if defined(LIBC_SCCS) && !defined(lint) 31static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93"; 32#endif /* LIBC_SCCS and not lint */ 33#include <sys/cdefs.h> 34__FBSDID("$FreeBSD: src/lib/libc/gen/err.c,v 1.15 2008/04/03 20:36:44 imp Exp $"); 35 36#include "namespace.h" 37#include <err.h> 38#include <errno.h> 39#include <stdarg.h> 40#include <stdio.h> 41#include <stdlib.h> 42#include <string.h> 43#include <vis.h> 44#include "un-namespace.h" 45 46#ifdef __BLOCKS__ 47#include <Block.h> 48#endif /* __BLOCKS__ */ 49#include "libc_private.h" 50 51#define ERR_EXIT_UNDEF 0 52#ifdef __BLOCKS__ 53#define ERR_EXIT_BLOCK 1 54#endif /* __BLOCKS__ */ 55#define ERR_EXIT_FUNC 2 56struct _e_err_exit { 57 unsigned int type; 58#ifdef __BLOCKS__ 59 union { 60#endif /* __BLOCKS__ */ 61 void (*func)(int); 62#ifdef __BLOCKS__ 63 void (^block)(int); 64 }; 65#endif /* __BLOCKS__ */ 66}; 67 68#ifdef BUILDING_VARIANT 69 70__private_extern__ FILE *_e_err_file; /* file to use for error output */ 71__private_extern__ struct _e_err_exit _e_err_exit; 72__private_extern__ void _e_visprintf(FILE * __restrict, const char * __restrict, va_list); 73 74#else /* !BUILDING_VARIANT */ 75 76__private_extern__ FILE *_e_err_file = NULL; /* file to use for error output */ 77__private_extern__ struct _e_err_exit _e_err_exit = {ERR_EXIT_UNDEF}; 78 79/* 80 * zero means pass as is 81 * 255 means use \nnn (octal) 82 * otherwise use \x (x is value) 83 * (NUL isn't used) 84 */ 85static const unsigned char escape[256] = { 86 /* NUL */ 87 0, /* Unused: strings can't contain nulls */ 88 /* SOH STX ETX EOT ENQ ACK BEL */ 89 255, 255, 255, 255, 255, 255, 'a', 90 /* BS HT NL VT NP CR SO SI */ 91 'b', 0, 0, 'v', 'f', 'r', 255, 255, 92 /* DLE DC1 DC2 DC3 DC4 NAK SYN ETB */ 93 255, 255, 255, 255, 255, 255, 255, 255, 94 /* CAN EM SUB ESC FS GS RS US */ 95 255, 255, 255, 255, 255, 255, 255, 255, 96 /* the rest are zero */ 97}; 98 99/* 100 * Make characters visible. If we can't allocate enough 101 * memory, we fall back on vfprintf(). 102 */ 103__private_extern__ void 104_e_visprintf(FILE * __restrict stream, const char * __restrict format, va_list ap) 105{ 106 int failed = 0; 107 char *str, *visstr; 108 va_list backup; 109 110 va_copy(backup, ap); 111 vasprintf(&str, format, ap); 112 if (str != NULL) { 113 if ((visstr = malloc(4 * strlen(str) + 1)) != NULL) { 114 unsigned char *fp = (unsigned char *)str; 115 unsigned char *tp = (unsigned char *)visstr; 116 while(*fp) { 117 switch(escape[*fp]) { 118 case 0: 119 *tp++ = *fp; 120 break; 121 case 255: 122 sprintf((char *)tp, "\\%03o", *fp); 123 tp += 4; 124 break; 125 default: 126 *tp++ = '\\'; 127 *tp++ = escape[*fp]; 128 break; 129 } 130 fp++; 131 } 132 *tp = 0; 133 fputs(visstr, stream); 134 free(visstr); 135 } else 136 failed = 1; 137 free(str); 138 } else 139 failed = 1; 140 if (failed) 141 vfprintf(stream, format, backup); 142 va_end(backup); 143} 144 145/* 146 * This is declared to take a `void *' so that the caller is not required 147 * to include <stdio.h> first. However, it is really a `FILE *', and the 148 * manual page documents it as such. 149 */ 150void 151err_set_file(void *fp) 152{ 153 if (fp) 154 _e_err_file = fp; 155 else 156 _e_err_file = stderr; 157} 158 159void 160err_set_exit(void (*ef)(int)) 161{ 162 _e_err_exit.type = ERR_EXIT_FUNC; 163 _e_err_exit.func = ef; 164} 165 166#ifdef __BLOCKS__ 167void 168err_set_exit_b(void (^ef)(int)) 169{ 170 _e_err_exit.type = ERR_EXIT_BLOCK; 171 _e_err_exit.block = Block_copy(ef); 172} 173#endif /* __BLOCKS__ */ 174#endif /* !BUILDING_VARIANT */ 175 176__weak_reference(_err, err); 177 178void 179_err(int eval, const char *fmt, ...) 180{ 181 va_list ap; 182 va_start(ap, fmt); 183 verrc(eval, errno, fmt, ap); 184 va_end(ap); 185} 186 187void 188verr(eval, fmt, ap) 189 int eval; 190 const char *fmt; 191 va_list ap; 192{ 193 verrc(eval, errno, fmt, ap); 194} 195 196void 197errc(int eval, int code, const char *fmt, ...) 198{ 199 va_list ap; 200 va_start(ap, fmt); 201 verrc(eval, code, fmt, ap); 202 va_end(ap); 203} 204 205void 206verrc(int eval, int code, const char *fmt, va_list ap) 207{ 208 if (_e_err_file == 0) 209 err_set_file((FILE *)0); 210 fprintf(_e_err_file, "%s: ", _getprogname()); 211 if (fmt != NULL) { 212 _e_visprintf(_e_err_file, fmt, ap); 213 fprintf(_e_err_file, ": "); 214 } 215 fprintf(_e_err_file, "%s\n", strerror(code)); 216 if (_e_err_exit.type) { 217#ifdef __BLOCKS__ 218 if (_e_err_exit.type == ERR_EXIT_BLOCK) { 219 _e_err_exit.block(eval); 220 } else { 221 _e_err_exit.func(eval); 222 } 223#else 224 _e_err_exit.func(eval); 225#endif /* __BLOCKS__ */ 226 } 227 exit(eval); 228} 229 230void 231errx(int eval, const char *fmt, ...) 232{ 233 va_list ap; 234 va_start(ap, fmt); 235 verrx(eval, fmt, ap); 236 va_end(ap); 237} 238 239void 240verrx(int eval, const char *fmt, va_list ap) 241{ 242 if (_e_err_file == 0) 243 err_set_file((FILE *)0); 244 fprintf(_e_err_file, "%s: ", _getprogname()); 245 if (fmt != NULL) 246 _e_visprintf(_e_err_file, fmt, ap); 247 fprintf(_e_err_file, "\n"); 248 if (_e_err_exit.type) { 249#ifdef __BLOCKS__ 250 if (_e_err_exit.type == ERR_EXIT_BLOCK) { 251 _e_err_exit.block(eval); 252 } else { 253 _e_err_exit.func(eval); 254 } 255#else 256 _e_err_exit.func(eval); 257#endif /* __BLOCKS__ */ 258 } 259 exit(eval); 260} 261 262__weak_reference(_warn, warn); 263 264void 265_warn(const char *fmt, ...) 266{ 267 va_list ap; 268 va_start(ap, fmt); 269 vwarnc(errno, fmt, ap); 270 va_end(ap); 271} 272 273void 274vwarn(const char *fmt, va_list ap) 275{ 276 vwarnc(errno, fmt, ap); 277} 278 279void 280warnc(int code, const char *fmt, ...) 281{ 282 va_list ap; 283 va_start(ap, fmt); 284 vwarnc(code, fmt, ap); 285 va_end(ap); 286} 287 288void 289vwarnc(int code, const char *fmt, va_list ap) 290{ 291 if (_e_err_file == 0) 292 err_set_file((FILE *)0); 293 fprintf(_e_err_file, "%s: ", _getprogname()); 294 if (fmt != NULL) { 295 _e_visprintf(_e_err_file, fmt, ap); 296 fprintf(_e_err_file, ": "); 297 } 298 fprintf(_e_err_file, "%s\n", strerror(code)); 299} 300 301void 302warnx(const char *fmt, ...) 303{ 304 va_list ap; 305 va_start(ap, fmt); 306 vwarnx(fmt, ap); 307 va_end(ap); 308} 309 310void 311vwarnx(const char *fmt, va_list ap) 312{ 313 if (_e_err_file == 0) 314 err_set_file((FILE *)0); 315 fprintf(_e_err_file, "%s: ", _getprogname()); 316 if (fmt != NULL) 317 _e_visprintf(_e_err_file, fmt, ap); 318 fprintf(_e_err_file, "\n"); 319} 320