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