10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
52397Sbasabi * Common Development and Distribution License (the "License").
62397Sbasabi * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*12986SJohn.Zolnowsky@Sun.COM * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
230Sstevel@tonic-gate *
240Sstevel@tonic-gate * logadm/err.c -- some basic error routines
250Sstevel@tonic-gate *
260Sstevel@tonic-gate */
270Sstevel@tonic-gate
280Sstevel@tonic-gate #include <stdio.h>
290Sstevel@tonic-gate #include <unistd.h>
300Sstevel@tonic-gate #include <libintl.h>
310Sstevel@tonic-gate #include <stdlib.h>
320Sstevel@tonic-gate #include <stdarg.h>
330Sstevel@tonic-gate #include <string.h>
340Sstevel@tonic-gate #include <errno.h>
350Sstevel@tonic-gate #include "err.h"
360Sstevel@tonic-gate
37*12986SJohn.Zolnowsky@Sun.COM jmp_buf *Err_env_ptr;
380Sstevel@tonic-gate static const char *Myname;
390Sstevel@tonic-gate static int Exitcode;
400Sstevel@tonic-gate static FILE *Errorfile;
410Sstevel@tonic-gate
420Sstevel@tonic-gate /*
430Sstevel@tonic-gate * err_init -- initialize the error handling routine
440Sstevel@tonic-gate *
450Sstevel@tonic-gate */
460Sstevel@tonic-gate void
err_init(const char * myname)470Sstevel@tonic-gate err_init(const char *myname)
480Sstevel@tonic-gate {
490Sstevel@tonic-gate char *ptr;
500Sstevel@tonic-gate
510Sstevel@tonic-gate if ((ptr = strrchr(myname, '/')) == NULL)
520Sstevel@tonic-gate Myname = myname;
530Sstevel@tonic-gate else
540Sstevel@tonic-gate Myname = ptr + 1;
550Sstevel@tonic-gate }
560Sstevel@tonic-gate
570Sstevel@tonic-gate static const char *File;
580Sstevel@tonic-gate static int Line;
590Sstevel@tonic-gate
600Sstevel@tonic-gate /*
610Sstevel@tonic-gate * err_fileline -- record the filename/line number for err(EF_FILE, ...)
620Sstevel@tonic-gate */
630Sstevel@tonic-gate void
err_fileline(const char * file,int line)640Sstevel@tonic-gate err_fileline(const char *file, int line)
650Sstevel@tonic-gate {
660Sstevel@tonic-gate File = file;
670Sstevel@tonic-gate Line = line;
680Sstevel@tonic-gate }
690Sstevel@tonic-gate
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate * err -- print an error message and return, exit or longjmp based on flags
720Sstevel@tonic-gate *
730Sstevel@tonic-gate * this routine calls gettext() to translate the fmt string.
740Sstevel@tonic-gate */
750Sstevel@tonic-gate /*PRINTFLIKE2*/
760Sstevel@tonic-gate void
err(int flags,const char * fmt,...)770Sstevel@tonic-gate err(int flags, const char *fmt, ...)
780Sstevel@tonic-gate {
790Sstevel@tonic-gate va_list ap;
800Sstevel@tonic-gate int safe_errno = errno;
810Sstevel@tonic-gate char *errno_msg = NULL;
820Sstevel@tonic-gate int as_is = 0;
830Sstevel@tonic-gate int jump = 0;
840Sstevel@tonic-gate int warning = 0;
850Sstevel@tonic-gate int fileline = 0;
860Sstevel@tonic-gate char *prefix = "Error: ";
870Sstevel@tonic-gate const char *intlfmt;
880Sstevel@tonic-gate
890Sstevel@tonic-gate va_start(ap, fmt);
900Sstevel@tonic-gate intlfmt = gettext(fmt);
910Sstevel@tonic-gate
920Sstevel@tonic-gate if (flags & EF_WARN) {
930Sstevel@tonic-gate warning = 1;
940Sstevel@tonic-gate prefix = "Warning: ";
950Sstevel@tonic-gate }
960Sstevel@tonic-gate if (flags & EF_FILE) {
970Sstevel@tonic-gate fileline = 1;
980Sstevel@tonic-gate Exitcode++;
990Sstevel@tonic-gate }
1000Sstevel@tonic-gate if (flags & EF_SYS)
1010Sstevel@tonic-gate errno_msg = strerror(safe_errno);
1020Sstevel@tonic-gate if (flags & EF_JMP)
1030Sstevel@tonic-gate jump = 1;
1040Sstevel@tonic-gate if (flags & EF_RAW)
1050Sstevel@tonic-gate as_is = 1;
1060Sstevel@tonic-gate
1070Sstevel@tonic-gate /* print a copy to stderr */
1080Sstevel@tonic-gate if (!as_is) {
1092397Sbasabi if (Myname != NULL) {
1100Sstevel@tonic-gate (void) fprintf(stderr, "%s: ", Myname);
1110Sstevel@tonic-gate if (Errorfile)
1120Sstevel@tonic-gate (void) fprintf(Errorfile, "%s: ", Myname);
1130Sstevel@tonic-gate }
1140Sstevel@tonic-gate if (fileline && File) {
1150Sstevel@tonic-gate (void) fprintf(stderr, "%s line %d: ", File, Line);
1160Sstevel@tonic-gate if (Errorfile)
1170Sstevel@tonic-gate (void) fprintf(Errorfile,
1180Sstevel@tonic-gate "%s line %d: ", File, Line);
1190Sstevel@tonic-gate }
1200Sstevel@tonic-gate (void) fputs(gettext(prefix), stderr);
1210Sstevel@tonic-gate if (Errorfile)
1220Sstevel@tonic-gate (void) fputs(gettext(prefix), Errorfile);
1230Sstevel@tonic-gate }
1240Sstevel@tonic-gate (void) vfprintf(stderr, intlfmt, ap);
1250Sstevel@tonic-gate if (Errorfile)
1260Sstevel@tonic-gate (void) vfprintf(Errorfile, intlfmt, ap);
1272397Sbasabi if (errno_msg != NULL) {
1280Sstevel@tonic-gate (void) fprintf(stderr, ": %s", errno_msg);
1290Sstevel@tonic-gate if (Errorfile)
1300Sstevel@tonic-gate (void) fprintf(Errorfile, ": %s", errno_msg);
1310Sstevel@tonic-gate }
1320Sstevel@tonic-gate if (!as_is) {
1330Sstevel@tonic-gate (void) fprintf(stderr, "\n");
1340Sstevel@tonic-gate if (Errorfile)
1350Sstevel@tonic-gate (void) fprintf(Errorfile, "\n");
1360Sstevel@tonic-gate }
1370Sstevel@tonic-gate (void) fflush(stderr);
1380Sstevel@tonic-gate if (Errorfile)
1390Sstevel@tonic-gate (void) fflush(Errorfile);
1400Sstevel@tonic-gate
1410Sstevel@tonic-gate va_end(ap);
1420Sstevel@tonic-gate
1430Sstevel@tonic-gate if (jump)
144*12986SJohn.Zolnowsky@Sun.COM longjmp(*Err_env_ptr, 1);
1450Sstevel@tonic-gate
1460Sstevel@tonic-gate if (!warning && !fileline) {
1470Sstevel@tonic-gate err_done(1);
1480Sstevel@tonic-gate /*NOTREACHED*/
1490Sstevel@tonic-gate }
1500Sstevel@tonic-gate }
1510Sstevel@tonic-gate
1520Sstevel@tonic-gate /*
1530Sstevel@tonic-gate * out -- print a message and return
1540Sstevel@tonic-gate *
1550Sstevel@tonic-gate * this routine calls gettext() to translate the fmt string.
1560Sstevel@tonic-gate */
1570Sstevel@tonic-gate /*PRINTFLIKE1*/
1580Sstevel@tonic-gate void
out(const char * fmt,...)1590Sstevel@tonic-gate out(const char *fmt, ...)
1600Sstevel@tonic-gate {
1610Sstevel@tonic-gate va_list ap;
1620Sstevel@tonic-gate
1630Sstevel@tonic-gate va_start(ap, fmt);
1640Sstevel@tonic-gate
1650Sstevel@tonic-gate (void) vfprintf(stdout, gettext(fmt), ap);
1660Sstevel@tonic-gate
1670Sstevel@tonic-gate va_end(ap);
1680Sstevel@tonic-gate }
1690Sstevel@tonic-gate
1700Sstevel@tonic-gate #define CHUNKSIZE 8192 /* for copying stderr */
1710Sstevel@tonic-gate /*
1720Sstevel@tonic-gate * err_fromfd -- copy data from fd to stderr
1730Sstevel@tonic-gate */
1740Sstevel@tonic-gate void
err_fromfd(int fd)1750Sstevel@tonic-gate err_fromfd(int fd)
1760Sstevel@tonic-gate {
1770Sstevel@tonic-gate char buf[CHUNKSIZE];
1780Sstevel@tonic-gate int count;
1790Sstevel@tonic-gate
1800Sstevel@tonic-gate while ((count = read(fd, buf, CHUNKSIZE)) > 0) {
1810Sstevel@tonic-gate (void) fwrite(buf, 1, count, stderr);
1820Sstevel@tonic-gate if (Errorfile)
1830Sstevel@tonic-gate (void) fwrite(buf, 1, count, Errorfile);
1840Sstevel@tonic-gate }
1850Sstevel@tonic-gate (void) fflush(stderr);
1860Sstevel@tonic-gate if (Errorfile)
1870Sstevel@tonic-gate (void) fflush(Errorfile);
1880Sstevel@tonic-gate }
1890Sstevel@tonic-gate
1900Sstevel@tonic-gate /*
1910Sstevel@tonic-gate * err_done -- exit the program
1920Sstevel@tonic-gate */
1930Sstevel@tonic-gate void
err_done(int exitcode)1940Sstevel@tonic-gate err_done(int exitcode)
1950Sstevel@tonic-gate {
1960Sstevel@tonic-gate /* send error mail if applicable */
1970Sstevel@tonic-gate err_mailto(NULL);
1980Sstevel@tonic-gate
1990Sstevel@tonic-gate if (exitcode)
2000Sstevel@tonic-gate exit(exitcode);
2010Sstevel@tonic-gate else
2020Sstevel@tonic-gate exit(Exitcode);
2030Sstevel@tonic-gate /*NOTREACHED*/
2040Sstevel@tonic-gate }
2050Sstevel@tonic-gate
2060Sstevel@tonic-gate #define MAXLINE 8192 /* for tmp file line buffer */
2070Sstevel@tonic-gate /*
2080Sstevel@tonic-gate * err_mailto -- arrange for error output to be mailed to someone
2090Sstevel@tonic-gate */
2100Sstevel@tonic-gate void
err_mailto(const char * recipient)2110Sstevel@tonic-gate err_mailto(const char *recipient)
2120Sstevel@tonic-gate {
2130Sstevel@tonic-gate static const char *lastrecipient;
2140Sstevel@tonic-gate static char mailcmd[] = "/bin/mailx -s 'logadm error output'";
2150Sstevel@tonic-gate char *cmd;
2160Sstevel@tonic-gate int len;
2170Sstevel@tonic-gate FILE *pfp;
2180Sstevel@tonic-gate char line[MAXLINE];
2190Sstevel@tonic-gate
2202397Sbasabi if (lastrecipient != NULL) {
2212397Sbasabi if (recipient != NULL &&
2222397Sbasabi strcmp(recipient, lastrecipient) == 0)
2230Sstevel@tonic-gate return; /* keep going, same recipient */
2240Sstevel@tonic-gate
2250Sstevel@tonic-gate /* stop saving output for lastrecipient and send message */
2260Sstevel@tonic-gate if (ftell(Errorfile)) {
2270Sstevel@tonic-gate rewind(Errorfile);
2280Sstevel@tonic-gate len = strlen(lastrecipient) + strlen(mailcmd) + 2;
2290Sstevel@tonic-gate cmd = MALLOC(len);
2300Sstevel@tonic-gate (void) snprintf(cmd, len, "%s %s",
2310Sstevel@tonic-gate mailcmd, lastrecipient);
2320Sstevel@tonic-gate if ((pfp = popen(cmd, "w")) == NULL)
2330Sstevel@tonic-gate err(EF_SYS, "popen to mailx");
2340Sstevel@tonic-gate while (fgets(line, MAXLINE, Errorfile) != NULL)
2350Sstevel@tonic-gate (void) fputs(line, pfp);
2360Sstevel@tonic-gate (void) pclose(pfp);
2370Sstevel@tonic-gate }
2380Sstevel@tonic-gate (void) fclose(Errorfile);
2390Sstevel@tonic-gate Errorfile = NULL;
2400Sstevel@tonic-gate }
2410Sstevel@tonic-gate
2422397Sbasabi if (recipient != NULL) {
2430Sstevel@tonic-gate /* start saving error output for this recipient */
2440Sstevel@tonic-gate if ((Errorfile = tmpfile()) == NULL)
2450Sstevel@tonic-gate err(EF_SYS, "tmpfile");
2460Sstevel@tonic-gate }
2470Sstevel@tonic-gate lastrecipient = recipient;
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate
2500Sstevel@tonic-gate /*
2510Sstevel@tonic-gate * err_malloc -- a malloc() with checks
2520Sstevel@tonic-gate *
2530Sstevel@tonic-gate * this routine is typically called via the MALLOC() macro in err.h
2540Sstevel@tonic-gate */
2550Sstevel@tonic-gate void *
err_malloc(int nbytes,const char * fname,int line)2560Sstevel@tonic-gate err_malloc(int nbytes, const char *fname, int line)
2570Sstevel@tonic-gate {
2580Sstevel@tonic-gate void *retval = malloc(nbytes);
2590Sstevel@tonic-gate
2600Sstevel@tonic-gate if (retval == NULL)
2610Sstevel@tonic-gate err(0, "%s:%d: out of memory", fname, line);
2620Sstevel@tonic-gate
2630Sstevel@tonic-gate return (retval);
2640Sstevel@tonic-gate }
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * err_realloc -- a realloc() with checks
2680Sstevel@tonic-gate *
2690Sstevel@tonic-gate * this routine is typically called via the REALLOC() macro in err.h
2700Sstevel@tonic-gate */
2710Sstevel@tonic-gate void *
err_realloc(void * ptr,int nbytes,const char * fname,int line)2720Sstevel@tonic-gate err_realloc(void *ptr, int nbytes, const char *fname, int line)
2730Sstevel@tonic-gate {
2740Sstevel@tonic-gate void *retval = realloc(ptr, nbytes);
2750Sstevel@tonic-gate
2760Sstevel@tonic-gate if (retval == NULL)
2770Sstevel@tonic-gate err(0, "%s:%d: out of memory", fname, line);
2780Sstevel@tonic-gate
2790Sstevel@tonic-gate return (retval);
2800Sstevel@tonic-gate }
2810Sstevel@tonic-gate
2820Sstevel@tonic-gate /*
2830Sstevel@tonic-gate * err_strdup -- a strdup() with checks
2840Sstevel@tonic-gate *
2850Sstevel@tonic-gate * this routine is typically called via the STRDUP() macro in err.h
2860Sstevel@tonic-gate */
2870Sstevel@tonic-gate char *
err_strdup(const char * ptr,const char * fname,int line)2880Sstevel@tonic-gate err_strdup(const char *ptr, const char *fname, int line)
2890Sstevel@tonic-gate {
2902397Sbasabi char *retval = NULL;
2910Sstevel@tonic-gate
2922397Sbasabi if (ptr != NULL) {
2932397Sbasabi retval = strdup(ptr);
2942397Sbasabi if (retval == NULL)
2952397Sbasabi err(0, "%s:%d: out of memory", fname, line);
2962397Sbasabi } else
2972397Sbasabi err(0, "%s:%d: could not strdup", fname, line);
2982397Sbasabi
2990Sstevel@tonic-gate
3000Sstevel@tonic-gate return (retval);
3012397Sbasabi
3020Sstevel@tonic-gate }
3030Sstevel@tonic-gate
3040Sstevel@tonic-gate /*
3050Sstevel@tonic-gate * err_free -- a free() with checks
3060Sstevel@tonic-gate *
3070Sstevel@tonic-gate * this routine is typically called via the FREE() macro in err.h
3080Sstevel@tonic-gate */
3090Sstevel@tonic-gate /*ARGSUSED1*/
3100Sstevel@tonic-gate void
err_free(void * ptr,const char * fname,int line)3110Sstevel@tonic-gate err_free(void *ptr, const char *fname, int line)
3120Sstevel@tonic-gate {
3130Sstevel@tonic-gate /* nothing to check in this version */
3140Sstevel@tonic-gate free(ptr);
3150Sstevel@tonic-gate }
3160Sstevel@tonic-gate
3170Sstevel@tonic-gate /*
3180Sstevel@tonic-gate * err_exitcode -- set an error exit code for when done(0) is called
3190Sstevel@tonic-gate */
3200Sstevel@tonic-gate void
err_exitcode(int exitcode)3210Sstevel@tonic-gate err_exitcode(int exitcode)
3220Sstevel@tonic-gate {
3230Sstevel@tonic-gate Exitcode = exitcode;
3240Sstevel@tonic-gate }
325