/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved. * * logadm/err.c -- some basic error routines * */ #include #include #include #include #include #include #include #include "err.h" jmp_buf Err_env; jmp_buf *Err_env_ptr; static const char *Myname; static int Exitcode; static FILE *Errorfile; /* * err_init -- initialize the error handling routine * */ void err_init(const char *myname) { char *ptr; if ((ptr = strrchr(myname, '/')) == NULL) Myname = myname; else Myname = ptr + 1; } static const char *File; static int Line; /* * err_fileline -- record the filename/line number for err(EF_FILE, ...) */ void err_fileline(const char *file, int line) { File = file; Line = line; } /* * err -- print an error message and return, exit or longjmp based on flags * * this routine calls gettext() to translate the fmt string. */ /*PRINTFLIKE2*/ void err(int flags, const char *fmt, ...) { va_list ap; int safe_errno = errno; char *errno_msg = NULL; int as_is = 0; int jump = 0; int warning = 0; int fileline = 0; char *prefix = "Error: "; const char *intlfmt; va_start(ap, fmt); intlfmt = gettext(fmt); if (flags & EF_WARN) { warning = 1; prefix = "Warning: "; } if (flags & EF_FILE) { fileline = 1; Exitcode++; } if (flags & EF_SYS) errno_msg = strerror(safe_errno); if (flags & EF_JMP) jump = 1; if (flags & EF_RAW) as_is = 1; /* print a copy to stderr */ if (!as_is) { if (Myname != NULL) { (void) fprintf(stderr, "%s: ", Myname); if (Errorfile) (void) fprintf(Errorfile, "%s: ", Myname); } if (fileline && File) { (void) fprintf(stderr, "%s line %d: ", File, Line); if (Errorfile) (void) fprintf(Errorfile, "%s line %d: ", File, Line); } (void) fputs(gettext(prefix), stderr); if (Errorfile) (void) fputs(gettext(prefix), Errorfile); } (void) vfprintf(stderr, intlfmt, ap); if (Errorfile) (void) vfprintf(Errorfile, intlfmt, ap); if (errno_msg != NULL) { (void) fprintf(stderr, ": %s", errno_msg); if (Errorfile) (void) fprintf(Errorfile, ": %s", errno_msg); } if (!as_is) { (void) fprintf(stderr, "\n"); if (Errorfile) (void) fprintf(Errorfile, "\n"); } (void) fflush(stderr); if (Errorfile) (void) fflush(Errorfile); va_end(ap); if (jump) longjmp(*Err_env_ptr, 1); if (!warning && !fileline) { err_done(1); /*NOTREACHED*/ } } /* * out -- print a message and return * * this routine calls gettext() to translate the fmt string. */ /*PRINTFLIKE1*/ void out(const char *fmt, ...) { va_list ap; va_start(ap, fmt); (void) vfprintf(stdout, gettext(fmt), ap); va_end(ap); } #define CHUNKSIZE 8192 /* for copying stderr */ /* * err_fromfd -- copy data from fd to stderr */ void err_fromfd(int fd) { char buf[CHUNKSIZE]; int count; while ((count = read(fd, buf, CHUNKSIZE)) > 0) { (void) fwrite(buf, 1, count, stderr); if (Errorfile) (void) fwrite(buf, 1, count, Errorfile); } (void) fflush(stderr); if (Errorfile) (void) fflush(Errorfile); } /* * err_done -- exit the program */ void err_done(int exitcode) { /* send error mail if applicable */ err_mailto(NULL); if (exitcode) exit(exitcode); else exit(Exitcode); /*NOTREACHED*/ } #define MAXLINE 8192 /* for tmp file line buffer */ /* * err_mailto -- arrange for error output to be mailed to someone */ void err_mailto(const char *recipient) { static const char *lastrecipient; static char mailcmd[] = "/bin/mailx -s 'logadm error output'"; char *cmd; int len; FILE *pfp; char line[MAXLINE]; if (lastrecipient != NULL) { if (recipient != NULL && strcmp(recipient, lastrecipient) == 0) return; /* keep going, same recipient */ /* stop saving output for lastrecipient and send message */ if (ftell(Errorfile)) { rewind(Errorfile); len = strlen(lastrecipient) + strlen(mailcmd) + 2; cmd = MALLOC(len); (void) snprintf(cmd, len, "%s %s", mailcmd, lastrecipient); if ((pfp = popen(cmd, "w")) == NULL) err(EF_SYS, "popen to mailx"); while (fgets(line, MAXLINE, Errorfile) != NULL) (void) fputs(line, pfp); (void) pclose(pfp); } (void) fclose(Errorfile); Errorfile = NULL; } if (recipient != NULL) { /* start saving error output for this recipient */ if ((Errorfile = tmpfile()) == NULL) err(EF_SYS, "tmpfile"); } lastrecipient = recipient; } /* * err_malloc -- a malloc() with checks * * this routine is typically called via the MALLOC() macro in err.h */ void * err_malloc(int nbytes, const char *fname, int line) { void *retval = malloc(nbytes); if (retval == NULL) err(0, "%s:%d: out of memory", fname, line); return (retval); } /* * err_realloc -- a realloc() with checks * * this routine is typically called via the REALLOC() macro in err.h */ void * err_realloc(void *ptr, int nbytes, const char *fname, int line) { void *retval = realloc(ptr, nbytes); if (retval == NULL) err(0, "%s:%d: out of memory", fname, line); return (retval); } /* * err_strdup -- a strdup() with checks * * this routine is typically called via the STRDUP() macro in err.h */ char * err_strdup(const char *ptr, const char *fname, int line) { char *retval = NULL; if (ptr != NULL) { retval = strdup(ptr); if (retval == NULL) err(0, "%s:%d: out of memory", fname, line); } else err(0, "%s:%d: could not strdup", fname, line); return (retval); } /* * err_free -- a free() with checks * * this routine is typically called via the FREE() macro in err.h */ /*ARGSUSED1*/ void err_free(void *ptr, const char *fname, int line) { /* nothing to check in this version */ free(ptr); } /* * err_exitcode -- set an error exit code for when done(0) is called */ void err_exitcode(int exitcode) { Exitcode = exitcode; }