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