1 /* $Id$ */
2
3 /*
4 *
5 * Copyright (C) 1998 David Mazieres (dm@uun.org)
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2, or (at
10 * your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
20 * USA
21 *
22 */
23
24 #include "err.h"
25
26 #undef warn
27 #undef warnx
28 #undef vwarn
29 #undef vwarnx
30 #undef fatal
31 #undef panic
32
33 bssstr progname;
34 bssstr progpid;
35 str progdir;
36 void (*fatalhook) ();
37
38 int errfd = 2;
39 bool fatal_no_destruct;
40 void (*_err_output) (suio *uio, int flags) = _err_output_sync;
41 void (*_err_reset_hook) ();
42
43 #if DMALLOC_VERSION_MAJOR < 5
44 #define dmalloc_logpath _dmalloc_logpath
45 extern "C" char *dmalloc_logpath;
46 #endif /* DMALLOC_VERSION_MAJOR < 5 */
47
48 void
setprogname(char * argv0)49 setprogname (char *argv0)
50 {
51 char *cp;
52 if ((cp = strrchr (argv0, '/')))
53 cp++;
54 else
55 cp = argv0;
56 /* Libtool shell wrappers leave lt- in argv[0] */
57 if (cp[0] == 'l' && cp[1] == 't' && cp[2] == '-')
58 progname = cp + 3;
59 else
60 progname = cp;
61 if (cp > argv0)
62 progdir.setbuf (argv0, cp - argv0);
63 else
64 progdir = NULL;
65 #ifdef DMALLOC
66 if (dmalloc_logpath) {
67 str logname;
68 const char *p;
69 if (!(p = strrchr (dmalloc_logpath, '/')) || !(p = strrchr (p, '.')))
70 p = dmalloc_logpath + strlen (dmalloc_logpath);
71 logname = strbuf ("%.*s.%s", int (p - dmalloc_logpath), dmalloc_logpath,
72 progname.cstr ());
73 static char *lp;
74 if (lp)
75 xfree (lp);
76 lp = xstrdup (logname);
77 dmalloc_logpath = lp;
78 }
79 #endif /* DMALLOC */
80 }
81
82 void
setprogpid(int p)83 setprogpid (int p)
84 {
85 strbuf b ("%d", p);
86 progpid = b;
87 }
88
89 void
err_reset()90 err_reset ()
91 {
92 if (_err_reset_hook)
93 (*_err_reset_hook) ();
94 _err_reset_hook = NULL;
95 _err_output = _err_output_sync;
96 }
97
98 void
_err_output_sync(suio * uio,int flags)99 _err_output_sync (suio *uio, int flags)
100 {
101 int saved_errno = errno;
102 uio->output (errfd);
103 if (flags & warnobj::panicflag)
104 myabort ();
105 if (flags & warnobj::fatalflag) {
106 if (fatalhook)
107 (*fatalhook) ();
108 if (fatal_no_destruct)
109 _exit (1);
110 exit (1);
111 }
112 errno = saved_errno;
113 }
114
115 static const char *
timestring()116 timestring ()
117 {
118 timespec ts;
119 clock_gettime (CLOCK_REALTIME, &ts);
120 static str buf;
121 buf = strbuf ("%d.%06d", int (ts.tv_sec), int (ts.tv_nsec/1000));
122 return buf;
123 }
124
125 /*
126 * warnobj
127 */
128
warnobj(int f)129 warnobj::warnobj (int f)
130 : flags (f)
131 {
132 if (flags & timeflag)
133 cat (timestring ()).cat (" ");
134 if (!(flags & xflag) && progname) {
135 if (progpid)
136 cat (progname).cat ("[").cat (progpid).cat ("]: ");
137 else
138 cat (progname).cat (": ");
139 }
140 if (flags & panicflag)
141 cat ("PANIC: ");
142 else if (flags & fatalflag)
143 cat ("fatal: ");
144 }
145
146 const warnobj &
operator()147 warnobj::operator() (const char *fmt, ...) const
148 {
149 va_list ap;
150 va_start (ap, fmt);
151 vfmt (fmt, ap);
152 va_end (ap);
153 return *this;
154 }
155
~warnobj()156 warnobj::~warnobj ()
157 {
158 _err_output (uio, flags);
159 }
160
161 #ifndef fatalobj
~fatalobj()162 fatalobj::~fatalobj ()
163 {
164 /* Of course, gcc won't let this function return, so we have to jump
165 * through a few hoops rather than simply implement ~fatalobj as
166 * {}. */
167 static_cast<warnobj *> (this)->~warnobj ();
168 myabort ();
169 }
170 #endif /* !fatalobj */
171
172 void
init()173 traceobj::init ()
174 {
175 if (progname)
176 cat (progname).cat (": ");
177 cat (prefix);
178 if (dotime)
179 cat (timestring ()).cat (" ");
180 }
181
~traceobj()182 traceobj::~traceobj ()
183 {
184 if (doprint)
185 _err_output (uio, 0);
186 }
187
188 const traceobj &
operator()189 traceobj::operator() (const int threshold)
190 {
191 doprint = current_level >= threshold;
192 if (doprint)
193 init ();
194 return *this;
195 }
196
197 const traceobj &
operator()198 traceobj::operator() (const int threshold, const char *fmt, ...)
199 {
200 doprint = current_level >= threshold;
201 if (doprint) {
202 init ();
203 va_list ap;
204 va_start (ap, fmt);
205 vfmt (fmt, ap);
206 va_end (ap);
207 }
208 return *this;
209 }
210
211 /*
212 * Traditional functions
213 */
214
215 void
sfs_vwarn(const char * fmt,va_list ap)216 sfs_vwarn (const char *fmt, va_list ap)
217 {
218 suio uio;
219 if (progname)
220 uio.print (progname.cstr (), progname.len ());
221 suio_vuprintf (&uio, fmt, ap);
222 _err_output (&uio, 0);
223 }
224
225 void
sfs_vwarnx(const char * fmt,va_list ap)226 sfs_vwarnx (const char *fmt, va_list ap)
227 {
228 suio uio;
229 suio_vuprintf (&uio, fmt, ap);
230 _err_output (&uio, warnobj::xflag);
231 }
232
233 void
sfs_warn(const char * fmt,...)234 sfs_warn (const char *fmt, ...)
235 {
236 va_list ap;
237 va_start (ap, fmt);
238 sfs_vwarn (fmt, ap);
239 va_end (ap);
240 }
241
242 void
sfs_warnx(const char * fmt,...)243 sfs_warnx (const char *fmt, ...)
244 {
245 va_list ap;
246 va_start (ap, fmt);
247 sfs_vwarnx (fmt, ap);
248 va_end (ap);
249 }
250
251 void
fatal(const char * fmt,...)252 fatal (const char *fmt, ...)
253 {
254 va_list ap;
255 strbuf b;
256 if (progname)
257 b << progname << ": ";
258 b << "fatal: ";
259
260 va_start (ap, fmt);
261 b.vfmt (fmt, ap);
262 va_end (ap);
263
264 _err_output (b.tosuio (), warnobj::fatalflag);
265 exit (1);
266 }
267
268 void
panic(const char * fmt,...)269 panic (const char *fmt, ...)
270 {
271 va_list ap;
272 strbuf b;
273 if (progname)
274 b << progname << ": ";
275 b << "PANIC: " << __BACKTRACE__ << "\n";
276
277 va_start (ap, fmt);
278 b.vfmt (fmt, ap);
279 va_end (ap);
280
281 _err_output (b.tosuio (), warnobj::panicflag);
282 myabort ();
283 }
284
285 GLOBALDESTRUCT;
286