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