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