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