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