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