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