xref: /onnv-gate/usr/src/cmd/logadm/err.c (revision 12986:04c3fb904c79)
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