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