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 (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2006 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 * 25 * logadm/err.c -- some basic error routines 26 * 27 */ 28 29 #pragma ident "%Z%%M% %I% %E% SMI" 30 31 #include <stdio.h> 32 #include <unistd.h> 33 #include <libintl.h> 34 #include <stdlib.h> 35 #include <stdarg.h> 36 #include <string.h> 37 #include <errno.h> 38 #include "err.h" 39 40 static const char *Myname; 41 static int Exitcode; 42 static FILE *Errorfile; 43 44 /* 45 * err_init -- initialize the error handling routine 46 * 47 */ 48 void 49 err_init(const char *myname) 50 { 51 char *ptr; 52 53 if ((ptr = strrchr(myname, '/')) == NULL) 54 Myname = myname; 55 else 56 Myname = ptr + 1; 57 } 58 59 static const char *File; 60 static int Line; 61 62 /* 63 * err_fileline -- record the filename/line number for err(EF_FILE, ...) 64 */ 65 void 66 err_fileline(const char *file, int line) 67 { 68 File = file; 69 Line = line; 70 } 71 72 /* 73 * err -- print an error message and return, exit or longjmp based on flags 74 * 75 * this routine calls gettext() to translate the fmt string. 76 */ 77 /*PRINTFLIKE2*/ 78 void 79 err(int flags, const char *fmt, ...) 80 { 81 va_list ap; 82 int safe_errno = errno; 83 char *errno_msg = NULL; 84 int as_is = 0; 85 int jump = 0; 86 int warning = 0; 87 int fileline = 0; 88 char *prefix = "Error: "; 89 const char *intlfmt; 90 91 va_start(ap, fmt); 92 intlfmt = gettext(fmt); 93 94 if (flags & EF_WARN) { 95 warning = 1; 96 prefix = "Warning: "; 97 } 98 if (flags & EF_FILE) { 99 fileline = 1; 100 Exitcode++; 101 } 102 if (flags & EF_SYS) 103 errno_msg = strerror(safe_errno); 104 if (flags & EF_JMP) 105 jump = 1; 106 if (flags & EF_RAW) 107 as_is = 1; 108 109 /* print a copy to stderr */ 110 if (!as_is) { 111 if (Myname != NULL) { 112 (void) fprintf(stderr, "%s: ", Myname); 113 if (Errorfile) 114 (void) fprintf(Errorfile, "%s: ", Myname); 115 } 116 if (fileline && File) { 117 (void) fprintf(stderr, "%s line %d: ", File, Line); 118 if (Errorfile) 119 (void) fprintf(Errorfile, 120 "%s line %d: ", File, Line); 121 } 122 (void) fputs(gettext(prefix), stderr); 123 if (Errorfile) 124 (void) fputs(gettext(prefix), Errorfile); 125 } 126 (void) vfprintf(stderr, intlfmt, ap); 127 if (Errorfile) 128 (void) vfprintf(Errorfile, intlfmt, ap); 129 if (errno_msg != NULL) { 130 (void) fprintf(stderr, ": %s", errno_msg); 131 if (Errorfile) 132 (void) fprintf(Errorfile, ": %s", errno_msg); 133 } 134 if (!as_is) { 135 (void) fprintf(stderr, "\n"); 136 if (Errorfile) 137 (void) fprintf(Errorfile, "\n"); 138 } 139 (void) fflush(stderr); 140 if (Errorfile) 141 (void) fflush(Errorfile); 142 143 va_end(ap); 144 145 if (jump) 146 longjmp(Err_env, 1); 147 148 if (!warning && !fileline) { 149 err_done(1); 150 /*NOTREACHED*/ 151 } 152 } 153 154 /* 155 * out -- print a message and return 156 * 157 * this routine calls gettext() to translate the fmt string. 158 */ 159 /*PRINTFLIKE1*/ 160 void 161 out(const char *fmt, ...) 162 { 163 va_list ap; 164 165 va_start(ap, fmt); 166 167 (void) vfprintf(stdout, gettext(fmt), ap); 168 169 va_end(ap); 170 } 171 172 #define CHUNKSIZE 8192 /* for copying stderr */ 173 /* 174 * err_fromfd -- copy data from fd to stderr 175 */ 176 void 177 err_fromfd(int fd) 178 { 179 char buf[CHUNKSIZE]; 180 int count; 181 182 while ((count = read(fd, buf, CHUNKSIZE)) > 0) { 183 (void) fwrite(buf, 1, count, stderr); 184 if (Errorfile) 185 (void) fwrite(buf, 1, count, Errorfile); 186 } 187 (void) fflush(stderr); 188 if (Errorfile) 189 (void) fflush(Errorfile); 190 } 191 192 /* 193 * err_done -- exit the program 194 */ 195 void 196 err_done(int exitcode) 197 { 198 /* send error mail if applicable */ 199 err_mailto(NULL); 200 201 if (exitcode) 202 exit(exitcode); 203 else 204 exit(Exitcode); 205 /*NOTREACHED*/ 206 } 207 208 #define MAXLINE 8192 /* for tmp file line buffer */ 209 /* 210 * err_mailto -- arrange for error output to be mailed to someone 211 */ 212 void 213 err_mailto(const char *recipient) 214 { 215 static const char *lastrecipient; 216 static char mailcmd[] = "/bin/mailx -s 'logadm error output'"; 217 char *cmd; 218 int len; 219 FILE *pfp; 220 char line[MAXLINE]; 221 222 if (lastrecipient != NULL) { 223 if (recipient != NULL && 224 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 != NULL) { 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 = NULL; 293 294 if (ptr != NULL) { 295 retval = strdup(ptr); 296 if (retval == NULL) 297 err(0, "%s:%d: out of memory", fname, line); 298 } else 299 err(0, "%s:%d: could not strdup", fname, line); 300 301 302 return (retval); 303 304 } 305 306 /* 307 * err_free -- a free() with checks 308 * 309 * this routine is typically called via the FREE() macro in err.h 310 */ 311 /*ARGSUSED1*/ 312 void 313 err_free(void *ptr, const char *fname, int line) 314 { 315 /* nothing to check in this version */ 316 free(ptr); 317 } 318 319 /* 320 * err_exitcode -- set an error exit code for when done(0) is called 321 */ 322 void 323 err_exitcode(int exitcode) 324 { 325 Exitcode = exitcode; 326 } 327