Error.c revision 444c061a
1/* $Xorg: Error.c,v 1.5 2001/02/09 02:03:54 xorgcvs Exp $ */
2
3/***********************************************************
4Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts
5Copyright 1993 by Sun Microsystems, Inc. Mountain View, CA.
6
7                        All Rights Reserved
8
9Permission to use, copy, modify, and distribute this software and its
10documentation for any purpose and without fee is hereby granted,
11provided that the above copyright notice appear in all copies and that
12both that copyright notice and this permission notice appear in
13supporting documentation, and that the names of Digital or Sun not be
14used in advertising or publicity pertaining to distribution of the
15software without specific, written prior permission.
16
17DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
18ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
19DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
20ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
21WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
22ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
23SOFTWARE.
24
25SUN DISCLAIMS ALL WARRANTIES WITH REGARD TO  THIS  SOFTWARE,
26INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
27NESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SUN BE  LI-
28ABLE  FOR  ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
29ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,  DATA  OR
30PROFITS,  WHETHER  IN  AN  ACTION OF CONTRACT, NEGLIGENCE OR
31OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION  WITH
32THE USE OR PERFORMANCE OF THIS SOFTWARE.
33
34******************************************************************/
35/* $XFree86: xc/lib/Xt/Error.c,v 3.13tsi Exp $ */
36
37/*
38
39Copyright 1987, 1988, 1998  The Open Group
40
41Permission to use, copy, modify, distribute, and sell this software and its
42documentation for any purpose is hereby granted without fee, provided that
43the above copyright notice appear in all copies and that both that
44copyright notice and this permission notice appear in supporting
45documentation.
46
47The above copyright notice and this permission notice shall be included in
48all copies or substantial portions of the Software.
49
50THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
51IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
52FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
53OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
54AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
55CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
56
57Except as contained in this notice, the name of The Open Group shall not be
58used in advertising or otherwise to promote the sale, use or other dealings
59in this Software without prior written authorization from The Open Group.
60
61*/
62
63#ifdef HAVE_CONFIG_H
64#include <config.h>
65#endif
66#include "IntrinsicI.h"
67#include <stdio.h>
68#include <stdlib.h>
69
70/* The error handlers in the application context aren't used since we can't
71   come up with a uniform way of using them.  If you can, define
72   GLOBALERRORS to be FALSE (or 0). */
73
74#ifndef GLOBALERRORS
75#define GLOBALERRORS 1
76#endif
77
78static void InitErrorHandling(XrmDatabase *);
79#if GLOBALERRORS
80static XrmDatabase errorDB = NULL;
81static Boolean error_inited = FALSE;
82void _XtDefaultErrorMsg(String, String, String, String, String*, Cardinal*);
83void _XtDefaultWarningMsg(String, String, String, String, String*, Cardinal*);
84void _XtDefaultError(String);
85void _XtDefaultWarning(String);
86static XtErrorMsgHandler errorMsgHandler = _XtDefaultErrorMsg;
87static XtErrorMsgHandler warningMsgHandler = _XtDefaultWarningMsg;
88static XtErrorHandler errorHandler = _XtDefaultError;
89static XtErrorHandler warningHandler = _XtDefaultWarning;
90#endif /* GLOBALERRORS */
91
92XrmDatabase *XtGetErrorDatabase(void)
93{
94    XrmDatabase* retval;
95#if GLOBALERRORS
96    LOCK_PROCESS;
97    retval = &errorDB;
98    UNLOCK_PROCESS;
99#else
100    retval = XtAppGetErrorDatabase(_XtDefaultAppContext());
101#endif /* GLOBALERRORS */
102    return retval;
103}
104
105XrmDatabase *XtAppGetErrorDatabase(
106	XtAppContext app)
107{
108    XrmDatabase* retval;
109#if GLOBALERRORS
110    LOCK_PROCESS;
111    retval = &errorDB;
112    UNLOCK_PROCESS;
113#else
114    LOCK_APP(app);
115    retval= &app->errorDB;
116    UNLOCK_APP(app);
117#endif /* GLOBALERRORS */
118    return retval;
119}
120
121void XtGetErrorDatabaseText(
122    register _Xconst char* name,
123    register _Xconst char* type,
124    register _Xconst char* class,
125    _Xconst char* defaultp,
126    String buffer,
127    int nbytes)
128{
129#if GLOBALERRORS
130    XtAppGetErrorDatabaseText(NULL,
131	    name,type,class,defaultp, buffer, nbytes, NULL);
132#else
133    XtAppGetErrorDatabaseText(_XtDefaultAppContext(),
134	    name,type,class,defaultp, buffer, nbytes, NULL);
135#endif /* GLOBALERRORS */
136}
137
138void XtAppGetErrorDatabaseText(
139    XtAppContext app,
140    register _Xconst char* name,
141    register _Xconst char* type,
142    register _Xconst char* class,
143    _Xconst char* defaultp,
144    String buffer,
145    int nbytes,
146    XrmDatabase db)
147{
148    String str_class;
149    String type_str;
150    XrmValue result;
151    char *str_name = NULL;
152    char *temp = NULL;
153
154#if GLOBALERRORS
155    LOCK_PROCESS;
156    if (error_inited == FALSE) {
157        InitErrorHandling (&errorDB);
158        error_inited = TRUE;
159    }
160#else
161    LOCK_APP(app);
162    if (app->error_inited == FALSE) {
163        InitErrorHandling (&app->errorDB);
164        app->error_inited = TRUE;
165    }
166#endif /* GLOBALERRORS */
167    if (!(str_name = ALLOCATE_LOCAL(strlen(name) + strlen(type) + 2)))
168	_XtAllocError(NULL);
169    (void) sprintf(str_name, "%s.%s", name, type);
170    /* XrmGetResource requires the name and class to be fully qualified
171     * and to have the same number of components. */
172    str_class = (char *)class;
173    if (! strchr(class, '.')) {
174	if (!(temp = ALLOCATE_LOCAL(2 * strlen(class) + 2)))
175	    _XtAllocError(NULL);
176	(void) sprintf(temp, "%s.%s", class, class);
177	str_class = temp;
178    }
179    if (db == NULL) {
180#if GLOBALERRORS
181	(void) XrmGetResource(errorDB, str_name, str_class, &type_str,
182			      &result);
183#else
184	(void) XrmGetResource(app->errorDB, str_name, str_class, &type_str,
185			      &result);
186#endif /* GLOBALERRORS */
187    } else (void) XrmGetResource(db, str_name, str_class, &type_str, &result);
188    if (result.addr) {
189        (void) strncpy (buffer, result.addr, nbytes);
190        if (result.size > (unsigned) nbytes) buffer[nbytes-1] = 0;
191    } else {
192	int len = strlen(defaultp);
193	if (len >= nbytes) len = nbytes-1;
194	(void) memmove(buffer, defaultp, len);
195	buffer[len] = '\0';
196    }
197    if (str_name)
198	DEALLOCATE_LOCAL(str_name);
199    if (temp)
200	DEALLOCATE_LOCAL(temp);
201#if GLOBALERRORS
202    UNLOCK_PROCESS;
203#else
204    UNLOCK_APP(app);
205#endif
206}
207
208static void InitErrorHandling (
209    XrmDatabase *db)
210{
211    XrmDatabase errordb;
212
213    errordb = XrmGetFileDatabase(ERRORDB);
214    XrmMergeDatabases(errordb, db);
215}
216
217static void DefaultMsg (
218    String name,
219    String type,
220    String class,
221    String defaultp,
222    String* params,
223    Cardinal* num_params,
224    Bool error,
225    void (*fn)(_Xconst _XtString))
226{
227#define BIGBUF 1024
228#ifdef notyet /* older versions don't, might want to wait until more do */
229#if defined(__linux__)  || defined(CSRG_BASED) /* everyone else needs to get with the program */
230#define USE_SNPRINTF
231#endif
232#endif
233    char buffer[BIGBUF];
234    char* message;
235    XtGetErrorDatabaseText(name,type,class,defaultp, buffer, BIGBUF);
236/*need better solution here, perhaps use lower level printf primitives? */
237    if (params == NULL || num_params == NULL || *num_params == 0)
238	(*fn)(buffer);
239#ifndef WIN32 /* and OS/2 */
240    else if ((getuid () != geteuid ()) || getuid() == 0) {
241	if ((error && errorHandler == _XtDefaultError) ||
242	    (!error && warningHandler == _XtDefaultWarning)) {
243	    /*
244	     * if it's just going to go to stderr anyway, then we'll
245	     * fprintf to stderr ourselves and skip the insecure sprintf.
246	     */
247	    Cardinal i = *num_params;
248	    String par[10];
249	    if (i > 10) i = 10;
250	    (void) memmove((char*)par, (char*)params, i * sizeof(String) );
251	    bzero( &par[i], (10-i) * sizeof(String) );
252	    (void) fprintf (stderr, "%s%s",
253			    error ? XTERROR_PREFIX : XTWARNING_PREFIX,
254			    error ? "Error: " : "Warning: ");
255	    (void) fprintf (stderr, buffer,
256			    par[0], par[1], par[2], par[3], par[4],
257			    par[5], par[6], par[7], par[8], par[9]);
258	    (void) fprintf (stderr, "%c", '\n');
259	    if (i != *num_params)
260		(*fn) ( "Some arguments in previous message were lost" );
261	    else if (error) exit (1);
262	} else {
263	    /*
264	     * can't tell what it might do, so we'll play it safe
265	     */
266	    XtWarning ("\
267This program is an suid-root program or is being run by the root user.\n\
268The full text of the error or warning message cannot be safely formatted\n\
269in this environment. You may get a more descriptive message by running the\n\
270program as a non-root user or by removing the suid bit on the executable.");
271	    (*fn)(buffer); /* if *fn is an ErrorHandler it should exit */
272	}
273    }
274#endif
275    else {
276	/*
277	 * If you have snprintf the worst thing that could happen is you'd
278	 * lose some information. Without snprintf you're probably going to
279	 * scramble your heap and perhaps SEGV -- sooner or later.
280	 * If it hurts when you go like this then don't go like this! :-)
281	 */
282	Cardinal i = *num_params;
283	String par[10];
284	if (i > 10) i = 10;
285	(void) memmove((char*)par, (char*)params, i * sizeof(String) );
286	bzero( &par[i], (10-i) * sizeof(String) );
287	if (i != *num_params)
288	    XtWarning( "Some arguments in following message were lost" );
289	/*
290	 * resist any temptation you might have to make `message' a
291	 * local buffer on the stack. Doing so is a security hole
292	 * in programs executing as root. Error and Warning
293	 * messages shouldn't be called frequently enough for this
294	 * to be a performance issue.
295	 */
296	if ((message = __XtMalloc (BIGBUF))) {
297#ifndef USE_SNPRINTF
298	    message[BIGBUF-1] = 0;
299	    (void) sprintf (message, buffer,
300#else
301	    (void) snprintf (message, BIGBUF, buffer,
302#endif
303			    par[0], par[1], par[2], par[3], par[4],
304			    par[5], par[6], par[7], par[8], par[9]);
305#ifndef USE_SNPRINTF
306	    if (message[BIGBUF-1] != '\0')
307		XtWarning ("Possible heap corruption in Xt{Error,Warning}MsgHandler");
308#endif
309	    (*fn)(message);
310	    XtFree(message);
311	} else {
312	    XtWarning ("Memory allocation failed, arguments in the following message were lost");
313	    (*fn)(buffer);
314	}
315    }
316}
317
318void _XtDefaultErrorMsg (
319    String name,
320    String type,
321    String class,
322    String defaultp,
323    String* params,
324    Cardinal* num_params)
325{
326    DefaultMsg (name,type,class,defaultp,params,num_params,True,XtError);
327}
328
329void _XtDefaultWarningMsg (
330    String name,
331    String type,
332    String class,
333    String defaultp,
334    String* params,
335    Cardinal* num_params)
336{
337    DefaultMsg (name,type,class,defaultp,params,num_params,False,XtWarning);
338}
339
340void XtErrorMsg(
341    _Xconst char* name,
342    _Xconst char* type,
343    _Xconst char* class,
344    _Xconst char* defaultp,
345    String* params,
346    Cardinal* num_params)
347{
348#if GLOBALERRORS
349    LOCK_PROCESS;
350    (*errorMsgHandler)((String)name,(String)type,(String)class,
351		       (String)defaultp,params,num_params);
352    UNLOCK_PROCESS;
353#else
354    XtAppErrorMsg(_XtDefaultAppContext(),name,type,class,
355	    defaultp,params,num_params);
356#endif /* GLOBALERRORS */
357}
358
359void XtAppErrorMsg(
360    XtAppContext app,
361    _Xconst char* name,
362    _Xconst char* type,
363    _Xconst char* class,
364    _Xconst char* defaultp,
365    String* params,
366    Cardinal* num_params)
367{
368#if GLOBALERRORS
369    LOCK_PROCESS;
370    (*errorMsgHandler)((String)name,(String)type,(String)class,
371		       (String)defaultp,params,num_params);
372    UNLOCK_PROCESS;
373#else
374    LOCK_APP(app);
375    (*app->errorMsgHandler)(name,type,class,defaultp,params,num_params);
376    UNLOCK_APP(app);
377#endif /* GLOBALERRORS */
378}
379
380void XtWarningMsg(
381    _Xconst char* name,
382    _Xconst char* type,
383    _Xconst char* class,
384    _Xconst char* defaultp,
385    String* params,
386    Cardinal* num_params)
387{
388#if GLOBALERRORS
389    LOCK_PROCESS;
390    (*warningMsgHandler)((String)name,(String)type,(String)class,
391			 (String)defaultp,params,num_params);
392    UNLOCK_PROCESS;
393#else
394    XtAppWarningMsg(_XtDefaultAppContext(),name,type,class,
395	    defaultp,params,num_params);
396#endif /* GLOBALERRORS */
397}
398
399void XtAppWarningMsg(
400    XtAppContext app,
401    _Xconst char* name,
402    _Xconst char* type,
403    _Xconst char* class,
404    _Xconst char* defaultp,
405    String* params,
406    Cardinal* num_params)
407{
408#if GLOBALERRORS
409    LOCK_PROCESS;
410    (*warningMsgHandler)((String)name,(String)type,(String)class,
411			 (String)defaultp,params,num_params);
412    UNLOCK_PROCESS;
413#else
414    LOCK_APP(app);
415    (*app->warningMsgHandler)(name,type,class,defaultp,params,num_params);
416    UNLOCK_APP(app);
417#endif /* GLOBALERRORS */
418}
419
420void XtSetErrorMsgHandler(
421    XtErrorMsgHandler handler)
422{
423#if GLOBALERRORS
424    LOCK_PROCESS;
425    if (handler != NULL) errorMsgHandler = handler;
426    else errorMsgHandler  = _XtDefaultErrorMsg;
427    UNLOCK_PROCESS;
428#else
429    XtAppSetErrorMsgHandler(_XtDefaultAppContext(), handler);
430#endif /* GLOBALERRORS */
431}
432
433XtErrorMsgHandler XtAppSetErrorMsgHandler(
434    XtAppContext app,
435    XtErrorMsgHandler handler)
436{
437    XtErrorMsgHandler old;
438#if GLOBALERRORS
439    LOCK_PROCESS;
440    old = errorMsgHandler;
441    if (handler != NULL) errorMsgHandler = handler;
442    else errorMsgHandler  = _XtDefaultErrorMsg;
443    UNLOCK_PROCESS;
444#else
445    LOCK_APP(app);
446    old = app->errorMsgHandler;
447    if (handler != NULL) app->errorMsgHandler = handler;
448    else app->errorMsgHandler  = _XtDefaultErrorMsg;
449    UNLOCK_APP(app);
450#endif /* GLOBALERRORS */
451    return old;
452}
453
454void XtSetWarningMsgHandler(
455    XtErrorMsgHandler handler)
456{
457#if GLOBALERRORS
458    LOCK_PROCESS;
459    if (handler != NULL) warningMsgHandler  = handler;
460    else warningMsgHandler = _XtDefaultWarningMsg;
461    UNLOCK_PROCESS;
462#else
463    XtAppSetWarningMsgHandler(_XtDefaultAppContext(),handler);
464#endif /* GLOBALERRORS */
465}
466
467XtErrorMsgHandler XtAppSetWarningMsgHandler(
468    XtAppContext app,
469    XtErrorMsgHandler handler)
470{
471    XtErrorMsgHandler old;
472#if GLOBALERRORS
473    LOCK_PROCESS;
474    old = warningMsgHandler;
475    if (handler != NULL) warningMsgHandler  = handler;
476    else warningMsgHandler = _XtDefaultWarningMsg;
477    UNLOCK_PROCESS;
478#else
479    LOCK_APP(app);
480    old = app->warningMsgHandler;
481    if (handler != NULL) app->warningMsgHandler  = handler;
482    else app->warningMsgHandler = _XtDefaultWarningMsg;
483    UNLOCK_APP(app);
484#endif /* GLOBALERRORS */
485    return old;
486}
487
488void _XtDefaultError(String message)
489{
490    if (message && *message)
491	(void)fprintf(stderr, "%sError: %s\n", XTERROR_PREFIX, message);
492    exit(1);
493}
494
495void _XtDefaultWarning(String message)
496{
497    if (message && *message)
498       (void)fprintf(stderr, "%sWarning: %s\n", XTWARNING_PREFIX, message);
499    return;
500}
501
502void XtError(
503    _Xconst char* message)
504{
505#if GLOBALERRORS
506    LOCK_PROCESS;
507    (*errorHandler)((String)message);
508    UNLOCK_PROCESS;
509#else
510    XtAppError(_XtDefaultAppContext(),message);
511#endif /* GLOBALERRORS */
512}
513
514void XtAppError(
515    XtAppContext app,
516    _Xconst char* message)
517{
518#if GLOBALERRORS
519    LOCK_PROCESS;
520    (*errorHandler)((String)message);
521    UNLOCK_PROCESS;
522#else
523    LOCK_APP(app);
524    (*app->errorHandler)(message);
525    UNLOCK_APP(app);
526#endif /* GLOBALERRORS */
527}
528
529void XtWarning(
530    _Xconst char* message)
531{
532#if GLOBALERRORS
533    LOCK_PROCESS;
534    (*warningHandler)((String)message);
535    UNLOCK_PROCESS;
536#else
537    XtAppWarning(_XtDefaultAppContext(),message);
538#endif /* GLOBALERRORS */
539}
540
541void XtAppWarning(
542    XtAppContext app,
543    _Xconst char* message)
544{
545#if GLOBALERRORS
546    LOCK_PROCESS;
547    (*warningHandler)((String)message);
548    UNLOCK_PROCESS;
549#else
550    LOCK_APP(app);
551    (*app->warningHandler)(message);
552    UNLOCK_APP(app);
553#endif /* GLOBALERRORS */
554}
555
556void XtSetErrorHandler(XtErrorHandler handler)
557{
558#if GLOBALERRORS
559    LOCK_PROCESS;
560    if (handler != NULL) errorHandler = handler;
561    else errorHandler  = _XtDefaultError;
562    UNLOCK_PROCESS;
563#else
564    XtAppSetErrorHandler(_XtDefaultAppContext(),handler);
565#endif /* GLOBALERRORS */
566}
567
568XtErrorHandler XtAppSetErrorHandler(
569    XtAppContext app,
570    XtErrorHandler handler)
571{
572    XtErrorHandler old;
573#if GLOBALERRORS
574    LOCK_PROCESS;
575    old = errorHandler;
576    if (handler != NULL) errorHandler = handler;
577    else errorHandler  = _XtDefaultError;
578    UNLOCK_PROCESS;
579#else
580    LOCK_APP(app);
581    old = app->errorHandler;
582    if (handler != NULL) app->errorHandler = handler;
583    else app->errorHandler  = _XtDefaultError;
584    UNLOCK_APP(app);
585#endif /* GLOBALERRORS */
586    return old;
587}
588
589void XtSetWarningHandler(XtErrorHandler handler)
590{
591#if GLOBALERRORS
592    LOCK_PROCESS;
593    if (handler != NULL) warningHandler = handler;
594    else warningHandler = _XtDefaultWarning;
595    UNLOCK_PROCESS;
596#else
597    XtAppSetWarningHandler(_XtDefaultAppContext(),handler);
598#endif /* GLOBALERRORS */
599}
600
601XtErrorHandler XtAppSetWarningHandler(
602    XtAppContext app,
603    XtErrorHandler handler)
604{
605    XtErrorHandler old;
606#if GLOBALERRORS
607    LOCK_PROCESS;
608    old = warningHandler;
609    if (handler != NULL) warningHandler  = handler;
610    else warningHandler = _XtDefaultWarning;
611    UNLOCK_PROCESS;
612#else
613    LOCK_APP(app);
614    old = app->warningHandler;
615    if (handler != NULL) app->warningHandler  = handler;
616    else app->warningHandler = _XtDefaultWarning;
617    UNLOCK_APP(app);
618#endif /* GLOBALERRORS */
619    return old;
620}
621
622void _XtSetDefaultErrorHandlers(
623    XtErrorMsgHandler *errMsg,
624    XtErrorMsgHandler *warnMsg,
625    XtErrorHandler *err,
626    XtErrorHandler *warn)
627{
628#ifndef GLOBALERRORS
629    LOCK_PROCESS;
630    *errMsg = _XtDefaultErrorMsg;
631    *warnMsg = _XtDefaultWarningMsg;
632    *err = _XtDefaultError;
633    *warn = _XtDefaultWarning;
634    UNLOCK_PROCESS;
635#endif /* GLOBALERRORS */
636}
637