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 (c) 2001 by Sun Microsystems, Inc. 24 * All rights reserved. 25 * 26 * logadm/err.c -- some basic error routines 27 * 28 */ 29 30 #pragma ident "%Z%%M% %I% %E% SMI" 31 32 #include <stdio.h> 33 #include <unistd.h> 34 #include <libintl.h> 35 #include <stdlib.h> 36 #include <stdarg.h> 37 #include <string.h> 38 #include <errno.h> 39 #include "err.h" 40 41 static const char *Myname; 42 static int Exitcode; 43 static FILE *Errorfile; 44 45 /* 46 * err_init -- initialize the error handling routine 47 * 48 */ 49 void 50 err_init(const char *myname) 51 { 52 char *ptr; 53 54 if ((ptr = strrchr(myname, '/')) == NULL) 55 Myname = myname; 56 else 57 Myname = ptr + 1; 58 } 59 60 static const char *File; 61 static int Line; 62 63 /* 64 * err_fileline -- record the filename/line number for err(EF_FILE, ...) 65 */ 66 void 67 err_fileline(const char *file, int line) 68 { 69 File = file; 70 Line = line; 71 } 72 73 /* 74 * err -- print an error message and return, exit or longjmp based on flags 75 * 76 * this routine calls gettext() to translate the fmt string. 77 */ 78 /*PRINTFLIKE2*/ 79 void 80 err(int flags, const char *fmt, ...) 81 { 82 va_list ap; 83 int safe_errno = errno; 84 char *errno_msg = NULL; 85 int as_is = 0; 86 int jump = 0; 87 int warning = 0; 88 int fileline = 0; 89 char *prefix = "Error: "; 90 const char *intlfmt; 91 92 va_start(ap, fmt); 93 intlfmt = gettext(fmt); 94 95 if (flags & EF_WARN) { 96 warning = 1; 97 prefix = "Warning: "; 98 } 99 if (flags & EF_FILE) { 100 fileline = 1; 101 Exitcode++; 102 } 103 if (flags & EF_SYS) 104 errno_msg = strerror(safe_errno); 105 if (flags & EF_JMP) 106 jump = 1; 107 if (flags & EF_RAW) 108 as_is = 1; 109 110 /* print a copy to stderr */ 111 if (!as_is) { 112 if (Myname) { 113 (void) fprintf(stderr, "%s: ", Myname); 114 if (Errorfile) 115 (void) fprintf(Errorfile, "%s: ", Myname); 116 } 117 if (fileline && File) { 118 (void) fprintf(stderr, "%s line %d: ", File, Line); 119 if (Errorfile) 120 (void) fprintf(Errorfile, 121 "%s line %d: ", File, Line); 122 } 123 (void) fputs(gettext(prefix), stderr); 124 if (Errorfile) 125 (void) fputs(gettext(prefix), Errorfile); 126 } 127 (void) vfprintf(stderr, intlfmt, ap); 128 if (Errorfile) 129 (void) vfprintf(Errorfile, intlfmt, ap); 130 if (errno_msg) { 131 (void) fprintf(stderr, ": %s", errno_msg); 132 if (Errorfile) 133 (void) fprintf(Errorfile, ": %s", errno_msg); 134 } 135 if (!as_is) { 136 (void) fprintf(stderr, "\n"); 137 if (Errorfile) 138 (void) fprintf(Errorfile, "\n"); 139 } 140 (void) fflush(stderr); 141 if (Errorfile) 142 (void) fflush(Errorfile); 143 144 va_end(ap); 145 146 if (jump) 147 longjmp(Err_env, 1); 148 149 if (!warning && !fileline) { 150 err_done(1); 151 /*NOTREACHED*/ 152 } 153 } 154 155 /* 156 * out -- print a message and return 157 * 158 * this routine calls gettext() to translate the fmt string. 159 */ 160 /*PRINTFLIKE1*/ 161 void 162 out(const char *fmt, ...) 163 { 164 va_list ap; 165 166 va_start(ap, fmt); 167 168 (void) vfprintf(stdout, gettext(fmt), ap); 169 170 va_end(ap); 171 } 172 173 #define CHUNKSIZE 8192 /* for copying stderr */ 174 /* 175 * err_fromfd -- copy data from fd to stderr 176 */ 177 void 178 err_fromfd(int fd) 179 { 180 char buf[CHUNKSIZE]; 181 int count; 182 183 while ((count = read(fd, buf, CHUNKSIZE)) > 0) { 184 (void) fwrite(buf, 1, count, stderr); 185 if (Errorfile) 186 (void) fwrite(buf, 1, count, Errorfile); 187 } 188 (void) fflush(stderr); 189 if (Errorfile) 190 (void) fflush(Errorfile); 191 } 192 193 /* 194 * err_done -- exit the program 195 */ 196 void 197 err_done(int exitcode) 198 { 199 /* send error mail if applicable */ 200 err_mailto(NULL); 201 202 if (exitcode) 203 exit(exitcode); 204 else 205 exit(Exitcode); 206 /*NOTREACHED*/ 207 } 208 209 #define MAXLINE 8192 /* for tmp file line buffer */ 210 /* 211 * err_mailto -- arrange for error output to be mailed to someone 212 */ 213 void 214 err_mailto(const char *recipient) 215 { 216 static const char *lastrecipient; 217 static char mailcmd[] = "/bin/mailx -s 'logadm error output'"; 218 char *cmd; 219 int len; 220 FILE *pfp; 221 char line[MAXLINE]; 222 223 if (lastrecipient) { 224 if (recipient && strcmp(recipient, lastrecipient) == 0) 225 return; /* keep going, same recipient */ 226 227 /* stop saving output for lastrecipient and send message */ 228 if (ftell(Errorfile)) { 229 rewind(Errorfile); 230 len = strlen(lastrecipient) + strlen(mailcmd) + 2; 231 cmd = MALLOC(len); 232 (void) snprintf(cmd, len, "%s %s", 233 mailcmd, lastrecipient); 234 if ((pfp = popen(cmd, "w")) == NULL) 235 err(EF_SYS, "popen to mailx"); 236 while (fgets(line, MAXLINE, Errorfile) != NULL) 237 (void) fputs(line, pfp); 238 (void) pclose(pfp); 239 } 240 (void) fclose(Errorfile); 241 Errorfile = NULL; 242 } 243 244 if (recipient) { 245 /* start saving error output for this recipient */ 246 if ((Errorfile = tmpfile()) == NULL) 247 err(EF_SYS, "tmpfile"); 248 } 249 lastrecipient = recipient; 250 } 251 252 /* 253 * err_malloc -- a malloc() with checks 254 * 255 * this routine is typically called via the MALLOC() macro in err.h 256 */ 257 void * 258 err_malloc(int nbytes, const char *fname, int line) 259 { 260 void *retval = malloc(nbytes); 261 262 if (retval == NULL) 263 err(0, "%s:%d: out of memory", fname, line); 264 265 return (retval); 266 } 267 268 /* 269 * err_realloc -- a realloc() with checks 270 * 271 * this routine is typically called via the REALLOC() macro in err.h 272 */ 273 void * 274 err_realloc(void *ptr, int nbytes, const char *fname, int line) 275 { 276 void *retval = realloc(ptr, nbytes); 277 278 if (retval == NULL) 279 err(0, "%s:%d: out of memory", fname, line); 280 281 return (retval); 282 } 283 284 /* 285 * err_strdup -- a strdup() with checks 286 * 287 * this routine is typically called via the STRDUP() macro in err.h 288 */ 289 char * 290 err_strdup(const char *ptr, const char *fname, int line) 291 { 292 char *retval = strdup(ptr); 293 294 if (retval == NULL) 295 err(0, "%s:%d: out of memory", fname, line); 296 297 return (retval); 298 } 299 300 /* 301 * err_free -- a free() with checks 302 * 303 * this routine is typically called via the FREE() macro in err.h 304 */ 305 /*ARGSUSED1*/ 306 void 307 err_free(void *ptr, const char *fname, int line) 308 { 309 /* nothing to check in this version */ 310 free(ptr); 311 } 312 313 /* 314 * err_exitcode -- set an error exit code for when done(0) is called 315 */ 316 void 317 err_exitcode(int exitcode) 318 { 319 Exitcode = exitcode; 320 } 321