1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates.
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
88#if GLOBALERRORS
89static XrmDatabase errorDB = NULL;
90static Boolean error_inited = FALSE;
91void _XtDefaultErrorMsg(String, String, String, String, String *, Cardinal *);
92void _XtDefaultWarningMsg(String, String, String, String, String *, Cardinal *);
93void
94_XtDefaultError(String)
95    _X_NORETURN;
96void
97_XtDefaultWarning(String);
98static XtErrorMsgHandler errorMsgHandler = _XtDefaultErrorMsg;
99static XtErrorMsgHandler warningMsgHandler = _XtDefaultWarningMsg;
100static XtErrorHandler errorHandler _X_NORETURN = _XtDefaultError;
101static XtErrorHandler warningHandler = _XtDefaultWarning;
102#endif                          /* GLOBALERRORS */
103
104XrmDatabase *
105XtGetErrorDatabase(void)
106{
107    XrmDatabase *retval;
108
109#if GLOBALERRORS
110    LOCK_PROCESS;
111    retval = &errorDB;
112    UNLOCK_PROCESS;
113#else
114    retval = XtAppGetErrorDatabase(_XtDefaultAppContext());
115#endif                          /* GLOBALERRORS */
116    return retval;
117}
118
119XrmDatabase *
120XtAppGetErrorDatabase(XtAppContext app _X_UNUSED)
121{
122    XrmDatabase *retval;
123
124#if GLOBALERRORS
125    LOCK_PROCESS;
126    retval = &errorDB;
127    UNLOCK_PROCESS;
128#else
129    LOCK_APP(app);
130    retval = &app->errorDB;
131    UNLOCK_APP(app);
132#endif                          /* GLOBALERRORS */
133    return retval;
134}
135
136void
137XtGetErrorDatabaseText(register _Xconst char *name,
138                       register _Xconst char *type,
139                       register _Xconst char *class,
140                       _Xconst char *defaultp,
141                       _XtString buffer, int nbytes)
142{
143#if GLOBALERRORS
144    XtAppGetErrorDatabaseText(NULL,
145                              name, type, class, defaultp, buffer, nbytes,
146                              NULL);
147#else
148    XtAppGetErrorDatabaseText(_XtDefaultAppContext(),
149                              name, type, class, defaultp, buffer, nbytes,
150                              NULL);
151#endif                          /* GLOBALERRORS */
152}
153
154void
155XtAppGetErrorDatabaseText(XtAppContext app _X_UNUSED,
156                          register _Xconst char *name,
157                          register _Xconst char *type,
158                          register _Xconst char *class,
159                          _Xconst char *defaultp,
160                          _XtString buffer,
161                          int nbytes,
162                          XrmDatabase db)
163{
164    String str_class;
165    _XtString type_str;
166    XrmValue result;
167    char *str_name = NULL;
168    char *temp = NULL;
169
170#if GLOBALERRORS
171    LOCK_PROCESS;
172    if (error_inited == FALSE) {
173        InitErrorHandling(&errorDB);
174        error_inited = TRUE;
175    }
176#else
177    LOCK_APP(app);
178    if (app->error_inited == FALSE) {
179        InitErrorHandling(&app->errorDB);
180        app->error_inited = TRUE;
181    }
182#endif                          /* GLOBALERRORS */
183    if (!(str_name = ALLOCATE_LOCAL(strlen(name) + strlen(type) + 2)))
184        _XtAllocError(NULL);
185    (void) sprintf(str_name, "%s.%s", name, type);
186    /* XrmGetResource requires the name and class to be fully qualified
187     * and to have the same number of components. */
188    str_class = (String) class;
189    if (!strchr(class, '.')) {
190        if (!(temp = ALLOCATE_LOCAL(2 * strlen(class) + 2)))
191            _XtAllocError(NULL);
192        (void) sprintf(temp, "%s.%s", class, class);
193        str_class = temp;
194    }
195    if (db == NULL) {
196#if GLOBALERRORS
197        (void) XrmGetResource(errorDB, str_name, str_class, &type_str, &result);
198#else
199        (void) XrmGetResource(app->errorDB, str_name, str_class, &type_str,
200                              &result);
201#endif                          /* GLOBALERRORS */
202    }
203    else
204        (void) XrmGetResource(db, str_name, str_class, &type_str, &result);
205    if (result.addr) {
206        (void) strncpy(buffer, result.addr, (size_t) nbytes);
207        if (result.size > (unsigned) nbytes)
208            buffer[nbytes - 1] = 0;
209    }
210    else {
211        int len = (int) strlen(defaultp);
212
213        if (len >= nbytes)
214            len = nbytes - 1;
215        (void) memmove(buffer, defaultp, (size_t) len);
216        buffer[len] = '\0';
217    }
218    if (str_name)
219        DEALLOCATE_LOCAL(str_name);
220    if (temp)
221        DEALLOCATE_LOCAL(temp);
222#if GLOBALERRORS
223    UNLOCK_PROCESS;
224#else
225    UNLOCK_APP(app);
226#endif
227}
228
229static void
230InitErrorHandling(XrmDatabase *db)
231{
232    XrmDatabase errordb;
233
234    errordb = XrmGetFileDatabase(ERRORDB);
235    XrmMergeDatabases(errordb, db);
236}
237
238static void
239DefaultMsg(String name,
240           String type,
241           String class,
242           String defaultp,
243           String *params,
244           const Cardinal *num_params,
245           Bool error,
246           void (*fn) (_Xconst _XtString))
247{
248#define BIGBUF 1024
249    char buffer[BIGBUF];
250    char *message;
251
252    XtGetErrorDatabaseText(name, type, class, defaultp, buffer, BIGBUF);
253/*need better solution here, perhaps use lower level printf primitives? */
254    if (params == NULL || num_params == NULL || *num_params == 0)
255        (*fn) (buffer);
256#ifndef WIN32                   /* and OS/2 */
257    else if ((getuid() != geteuid()) || getuid() == 0) {
258        if ((error && errorHandler == _XtDefaultError) ||
259            (!error && warningHandler == _XtDefaultWarning)) {
260            /*
261             * if it's just going to go to stderr anyway, then we'll
262             * fprintf to stderr ourselves and skip the insecure sprintf.
263             */
264            Cardinal i = *num_params;
265            String par[10];
266
267            if (i > 10)
268                i = 10;
269            (void) memcpy(par, params, i * sizeof(String));
270            memset(&par[i], 0, (10 - i) * sizeof(String));
271            (void) fprintf(stderr, "%s%s",
272                           error ? XTERROR_PREFIX : XTWARNING_PREFIX,
273                           error ? "Error: " : "Warning: ");
274            (void) fprintf(stderr, buffer,
275                           par[0], par[1], par[2], par[3], par[4],
276                           par[5], par[6], par[7], par[8], par[9]);
277            (void) fprintf(stderr, "%c", '\n');
278            if (i != *num_params)
279                (*fn) ("Some arguments in previous message were lost");
280            else if (error)
281                exit(1);
282        }
283        else {
284            /*
285             * can't tell what it might do, so we'll play it safe
286             */
287            XtWarning("\
288This program is an suid-root program or is being run by the root user.\n\
289The full text of the error or warning message cannot be safely formatted\n\
290in this environment. You may get a more descriptive message by running the\n\
291program as a non-root user or by removing the suid bit on the executable.");
292            (*fn) (buffer);     /* if *fn is an ErrorHandler it should exit */
293        }
294    }
295#endif
296    else {
297        /*
298         * If you have snprintf the worst thing that could happen is you'd
299         * lose some information. Without snprintf you're probably going to
300         * scramble your heap and perhaps SEGV -- sooner or later.
301         * If it hurts when you go like this then don't go like this! :-)
302         */
303        Cardinal i = *num_params;
304        String par[10];
305
306        if (i > 10)
307            i = 10;
308        (void) memcpy(par, params, i * sizeof(String));
309        memset(&par[i], 0, (10 - i) * sizeof(String));
310        if (i != *num_params)
311            XtWarning("Some arguments in following message were lost");
312        /*
313         * resist any temptation you might have to make `message' a
314         * local buffer on the stack. Doing so is a security hole
315         * in programs executing as root. Error and Warning
316         * messages shouldn't be called frequently enough for this
317         * to be a performance issue.
318         */
319        if ((message = __XtMalloc(BIGBUF))) {
320            (void) snprintf(message, BIGBUF, buffer,
321                            par[0], par[1], par[2], par[3], par[4],
322                            par[5], par[6], par[7], par[8], par[9]);
323            (*fn) (message);
324            XtFree(message);
325        }
326        else {
327            XtWarning
328                ("Memory allocation failed, arguments in the following message were lost");
329            (*fn) (buffer);
330        }
331    }
332}
333
334void
335_XtDefaultErrorMsg(String name,
336                   String type,
337                   String class,
338                   String defaultp,
339                   String *params,
340                   Cardinal *num_params)
341{
342    DefaultMsg(name, type, class, defaultp, params, num_params, True, XtError);
343}
344
345void
346_XtDefaultWarningMsg(String name,
347                     String type,
348                     String class,
349                     String defaultp,
350                     String *params,
351                     Cardinal *num_params)
352{
353    DefaultMsg(name, type, class, defaultp, params, num_params, False,
354               XtWarning);
355}
356
357void
358XtErrorMsg(_Xconst char *name,
359           _Xconst char *type,
360           _Xconst char *class,
361           _Xconst char *defaultp,
362           String *params,
363           Cardinal *num_params)
364{
365#if GLOBALERRORS
366    LOCK_PROCESS;
367    (*errorMsgHandler) ((String) name, (String) type, (String) class,
368                        (String) defaultp, params, num_params);
369    UNLOCK_PROCESS;
370    exit(1);
371#else
372    XtAppErrorMsg(_XtDefaultAppContext(), name, type, class,
373                  defaultp, params, num_params);
374#endif                          /* GLOBALERRORS */
375}
376
377void
378XtAppErrorMsg(XtAppContext app _X_UNUSED,
379              _Xconst char *name,
380              _Xconst char *type,
381              _Xconst char *class,
382              _Xconst char *defaultp,
383              String *params,
384              Cardinal *num_params)
385{
386#if GLOBALERRORS
387    LOCK_PROCESS;
388    (*errorMsgHandler) ((String) name, (String) type, (String) class,
389                        (String) defaultp, params, num_params);
390    UNLOCK_PROCESS;
391    exit(1);
392#else
393    LOCK_APP(app);
394    (*app->errorMsgHandler) (name, type, class, defaultp, params, num_params);
395    UNLOCK_APP(app);
396#endif                          /* GLOBALERRORS */
397}
398
399void
400XtWarningMsg(_Xconst char *name,
401             _Xconst char *type,
402             _Xconst char *class,
403             _Xconst char *defaultp,
404             String *params,
405             Cardinal *num_params)
406{
407#if GLOBALERRORS
408    LOCK_PROCESS;
409    (*warningMsgHandler) ((String) name, (String) type, (String) class,
410                          (String) defaultp, params, num_params);
411    UNLOCK_PROCESS;
412#else
413    XtAppWarningMsg(_XtDefaultAppContext(), name, type, class,
414                    defaultp, params, num_params);
415#endif                          /* GLOBALERRORS */
416}
417
418void
419XtAppWarningMsg(XtAppContext app _X_UNUSED,
420                _Xconst char *name,
421                _Xconst char *type,
422                _Xconst char *class,
423                _Xconst char *defaultp,
424                String *params,
425                Cardinal *num_params)
426{
427#if GLOBALERRORS
428    LOCK_PROCESS;
429    (*warningMsgHandler) ((String) name, (String) type, (String) class,
430                          (String) defaultp, params, num_params);
431    UNLOCK_PROCESS;
432#else
433    LOCK_APP(app);
434    (*app->warningMsgHandler) (name, type, class, defaultp, params, num_params);
435    UNLOCK_APP(app);
436#endif                          /* GLOBALERRORS */
437}
438
439void
440XtSetErrorMsgHandler(XtErrorMsgHandler handler _X_NORETURN)
441{
442#if GLOBALERRORS
443    LOCK_PROCESS;
444    if (handler != NULL)
445        errorMsgHandler = handler;
446    else
447        errorMsgHandler = _XtDefaultErrorMsg;
448    UNLOCK_PROCESS;
449#else
450    XtAppSetErrorMsgHandler(_XtDefaultAppContext(), handler);
451#endif                          /* GLOBALERRORS */
452}
453
454XtErrorMsgHandler
455XtAppSetErrorMsgHandler(XtAppContext app _X_UNUSED,
456                        XtErrorMsgHandler handler _X_NORETURN)
457{
458    XtErrorMsgHandler old;
459
460#if GLOBALERRORS
461    LOCK_PROCESS;
462    old = errorMsgHandler;
463    if (handler != NULL)
464        errorMsgHandler = handler;
465    else
466        errorMsgHandler = _XtDefaultErrorMsg;
467    UNLOCK_PROCESS;
468#else
469    LOCK_APP(app);
470    old = app->errorMsgHandler;
471    if (handler != NULL)
472        app->errorMsgHandler = handler;
473    else
474        app->errorMsgHandler = _XtDefaultErrorMsg;
475    UNLOCK_APP(app);
476#endif                          /* GLOBALERRORS */
477    return old;
478}
479
480void
481XtSetWarningMsgHandler(XtErrorMsgHandler handler)
482{
483#if GLOBALERRORS
484    LOCK_PROCESS;
485    if (handler != NULL)
486        warningMsgHandler = handler;
487    else
488        warningMsgHandler = _XtDefaultWarningMsg;
489    UNLOCK_PROCESS;
490#else
491    XtAppSetWarningMsgHandler(_XtDefaultAppContext(), handler);
492#endif                          /* GLOBALERRORS */
493}
494
495XtErrorMsgHandler
496XtAppSetWarningMsgHandler(XtAppContext app _X_UNUSED, XtErrorMsgHandler handler)
497{
498    XtErrorMsgHandler old;
499
500#if GLOBALERRORS
501    LOCK_PROCESS;
502    old = warningMsgHandler;
503    if (handler != NULL)
504        warningMsgHandler = handler;
505    else
506        warningMsgHandler = _XtDefaultWarningMsg;
507    UNLOCK_PROCESS;
508#else
509    LOCK_APP(app);
510    old = app->warningMsgHandler;
511    if (handler != NULL)
512        app->warningMsgHandler = handler;
513    else
514        app->warningMsgHandler = _XtDefaultWarningMsg;
515    UNLOCK_APP(app);
516#endif                          /* GLOBALERRORS */
517    return old;
518}
519
520void
521_XtDefaultError(String message)
522{
523    if (message && *message)
524        (void) fprintf(stderr, "%sError: %s\n", XTERROR_PREFIX, message);
525    exit(1);
526}
527
528void
529_XtDefaultWarning(String message)
530{
531    if (message && *message)
532        (void) fprintf(stderr, "%sWarning: %s\n", XTWARNING_PREFIX, message);
533    return;
534}
535
536void
537XtError(_Xconst char *message)
538{
539#if GLOBALERRORS
540    LOCK_PROCESS;
541    (*errorHandler) ((String) message);
542    UNLOCK_PROCESS;
543#else
544    XtAppError(_XtDefaultAppContext(), message);
545#endif                          /* GLOBALERRORS */
546}
547
548void
549XtAppError(XtAppContext app _X_UNUSED, _Xconst char *message)
550{
551#if GLOBALERRORS
552    LOCK_PROCESS;
553    (*errorHandler) ((String) message);
554    UNLOCK_PROCESS;
555#else
556    LOCK_APP(app);
557    (*app->errorHandler) (message);
558    UNLOCK_APP(app);
559#endif                          /* GLOBALERRORS */
560}
561
562void
563XtWarning(_Xconst char *message)
564{
565#if GLOBALERRORS
566    LOCK_PROCESS;
567    (*warningHandler) ((String) message);
568    UNLOCK_PROCESS;
569#else
570    XtAppWarning(_XtDefaultAppContext(), message);
571#endif                          /* GLOBALERRORS */
572}
573
574void
575XtAppWarning(XtAppContext app _X_UNUSED, _Xconst char *message)
576{
577#if GLOBALERRORS
578    LOCK_PROCESS;
579    (*warningHandler) ((String) message);
580    UNLOCK_PROCESS;
581#else
582    LOCK_APP(app);
583    (*app->warningHandler) (message);
584    UNLOCK_APP(app);
585#endif                          /* GLOBALERRORS */
586}
587
588void
589XtSetErrorHandler(XtErrorHandler handler _X_NORETURN)
590{
591#if GLOBALERRORS
592    LOCK_PROCESS;
593    if (handler != NULL)
594        errorHandler = handler;
595    else
596        errorHandler = _XtDefaultError;
597    UNLOCK_PROCESS;
598#else
599    XtAppSetErrorHandler(_XtDefaultAppContext(), handler);
600#endif                          /* GLOBALERRORS */
601}
602
603XtErrorHandler
604XtAppSetErrorHandler(XtAppContext app _X_UNUSED,
605                     XtErrorHandler handler _X_NORETURN)
606{
607    XtErrorHandler old;
608
609#if GLOBALERRORS
610    LOCK_PROCESS;
611    old = errorHandler;
612    if (handler != NULL)
613        errorHandler = handler;
614    else
615        errorHandler = _XtDefaultError;
616    UNLOCK_PROCESS;
617#else
618    LOCK_APP(app);
619    old = app->errorHandler;
620    if (handler != NULL)
621        app->errorHandler = handler;
622    else
623        app->errorHandler = _XtDefaultError;
624    UNLOCK_APP(app);
625#endif                          /* GLOBALERRORS */
626    return old;
627}
628
629void
630XtSetWarningHandler(XtErrorHandler handler)
631{
632#if GLOBALERRORS
633    LOCK_PROCESS;
634    if (handler != NULL)
635        warningHandler = handler;
636    else
637        warningHandler = _XtDefaultWarning;
638    UNLOCK_PROCESS;
639#else
640    XtAppSetWarningHandler(_XtDefaultAppContext(), handler);
641#endif                          /* GLOBALERRORS */
642}
643
644XtErrorHandler
645XtAppSetWarningHandler(XtAppContext app _X_UNUSED, XtErrorHandler handler)
646{
647    XtErrorHandler old;
648
649#if GLOBALERRORS
650    LOCK_PROCESS;
651    old = warningHandler;
652    if (handler != NULL)
653        warningHandler = handler;
654    else
655        warningHandler = _XtDefaultWarning;
656    UNLOCK_PROCESS;
657#else
658    LOCK_APP(app);
659    old = app->warningHandler;
660    if (handler != NULL)
661        app->warningHandler = handler;
662    else
663        app->warningHandler = _XtDefaultWarning;
664    UNLOCK_APP(app);
665#endif                          /* GLOBALERRORS */
666    return old;
667}
668
669void
670_XtSetDefaultErrorHandlers(XtErrorMsgHandler *errMsg _X_UNUSED,
671                           XtErrorMsgHandler *warnMsg _X_UNUSED,
672                           XtErrorHandler *err _X_UNUSED,
673                           XtErrorHandler *warn _X_UNUSED)
674{
675#ifndef GLOBALERRORS
676    LOCK_PROCESS;
677    *errMsg = _XtDefaultErrorMsg;
678    *warnMsg = _XtDefaultWarningMsg;
679    *err = _XtDefaultError;
680    *warn = _XtDefaultWarning;
681    UNLOCK_PROCESS;
682#endif                          /* GLOBALERRORS */
683}
684