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