1 /*
2 
3 Copyright 1987, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21 
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26 
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts,
28 Copyright 1994 Quarterdeck Office Systems.
29 
30                         All Rights Reserved
31 
32 Permission to use, copy, modify, and distribute this software and its
33 documentation for any purpose and without fee is hereby granted,
34 provided that the above copyright notice appear in all copies and that
35 both that copyright notice and this permission notice appear in
36 supporting documentation, and that the names of Digital and
37 Quarterdeck not be used in advertising or publicity pertaining to
38 distribution of the software without specific, written prior
39 permission.
40 
41 DIGITAL AND QUARTERDECK DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
42 SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
43 FITNESS, IN NO EVENT SHALL DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT
44 OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
45 OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
46 OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
47 OR PERFORMANCE OF THIS SOFTWARE.
48 
49 */
50 
51 /*
52  * Copyright (c) 1997-2003 by The XFree86 Project, Inc.
53  *
54  * Permission is hereby granted, free of charge, to any person obtaining a
55  * copy of this software and associated documentation files (the "Software"),
56  * to deal in the Software without restriction, including without limitation
57  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
58  * and/or sell copies of the Software, and to permit persons to whom the
59  * Software is furnished to do so, subject to the following conditions:
60  *
61  * The above copyright notice and this permission notice shall be included in
62  * all copies or substantial portions of the Software.
63  *
64  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
65  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
66  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
67  * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
68  * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
69  * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
70  * OTHER DEALINGS IN THE SOFTWARE.
71  *
72  * Except as contained in this notice, the name of the copyright holder(s)
73  * and author(s) shall not be used in advertising or otherwise to promote
74  * the sale, use or other dealings in this Software without prior written
75  * authorization from the copyright holder(s) and author(s).
76  */
77 
78 #ifdef HAVE_DIX_CONFIG_H
79 #include <dix-config.h>
80 #endif
81 
82 #include <X11/Xos.h>
83 #include <stdio.h>
84 #include <time.h>
85 #include <sys/stat.h>
86 #include <stdarg.h>
87 #include <stdlib.h>             /* for malloc() */
88 #include <errno.h>
89 
90 #include "input.h"
91 #include "site.h"
92 #include "opaque.h"
93 
94 #ifdef WIN32
95 #include <process.h>
96 #define getpid(x) _getpid(x)
97 #endif
98 
99 #ifdef XF86BIGFONT
100 #include "xf86bigfontsrv.h"
101 #endif
102 
103 #ifdef __clang__
104 #pragma clang diagnostic ignored "-Wformat-nonliteral"
105 #endif
106 
107 #ifdef DDXOSVERRORF
108 void (*OsVendorVErrorFProc) (const char *, va_list args) = NULL;
109 #endif
110 
111 static FILE *logFile = NULL;
112 static int logFileFd = -1;
113 static Bool logFlush = FALSE;
114 static Bool logSync = FALSE;
115 static int logVerbosity = DEFAULT_LOG_VERBOSITY;
116 static int logFileVerbosity = DEFAULT_LOG_FILE_VERBOSITY;
117 
118 /* Buffer to information logged before the log file is opened. */
119 static char *saveBuffer = NULL;
120 static int bufferSize = 0, bufferUnused = 0, bufferPos = 0;
121 static Bool needBuffer = TRUE;
122 
123 #ifdef __APPLE__
124 static char __crashreporter_info_buff__[4096] = { 0 };
125 
126 static const char *__crashreporter_info__ __attribute__ ((__used__)) =
127     &__crashreporter_info_buff__[0];
128 asm(".desc ___crashreporter_info__, 0x10");
129 #endif
130 
131 /* Prefix strings for log messages. */
132 #ifndef X_UNKNOWN_STRING
133 #define X_UNKNOWN_STRING		"(\?\?)"
134 #endif
135 #ifndef X_PROBE_STRING
136 #define X_PROBE_STRING			"(--)"
137 #endif
138 #ifndef X_CONFIG_STRING
139 #define X_CONFIG_STRING			"(**)"
140 #endif
141 #ifndef X_DEFAULT_STRING
142 #define X_DEFAULT_STRING		"(==)"
143 #endif
144 #ifndef X_CMDLINE_STRING
145 #define X_CMDLINE_STRING		"(++)"
146 #endif
147 #ifndef X_NOTICE_STRING
148 #define X_NOTICE_STRING			"(!!)"
149 #endif
150 #ifndef X_ERROR_STRING
151 #define X_ERROR_STRING			"(EE)"
152 #endif
153 #ifndef X_WARNING_STRING
154 #define X_WARNING_STRING		"(WW)"
155 #endif
156 #ifndef X_INFO_STRING
157 #define X_INFO_STRING			"(II)"
158 #endif
159 #ifndef X_NOT_IMPLEMENTED_STRING
160 #define X_NOT_IMPLEMENTED_STRING	"(NI)"
161 #endif
162 #ifndef X_DEBUG_STRING
163 #define X_DEBUG_STRING			"(DB)"
164 #endif
165 #ifndef X_NONE_STRING
166 #define X_NONE_STRING			""
167 #endif
168 
169 static size_t
strlen_sigsafe(const char * s)170 strlen_sigsafe(const char *s)
171 {
172     size_t len;
173     for (len = 0; s[len]; len++);
174     return len;
175 }
176 
177 /*
178  * LogFilePrep is called to setup files for logging, including getting
179  * an old file out of the way, but it doesn't actually open the file,
180  * since it may be used for renaming a file we're already logging to.
181  */
182 #pragma GCC diagnostic push
183 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
184 
185 static char *
LogFilePrep(const char * fname,const char * backup,const char * idstring)186 LogFilePrep(const char *fname, const char *backup, const char *idstring)
187 {
188     char *logFileName = NULL;
189 
190     /* the format string below is controlled by the user,
191        this code should never be called with elevated privileges */
192     if (asprintf(&logFileName, fname, idstring) == -1)
193         FatalError("Cannot allocate space for the log file name\n");
194 
195     if (backup && *backup) {
196         struct stat buf;
197 
198         if (!stat(logFileName, &buf) && S_ISREG(buf.st_mode)) {
199             char *suffix;
200             char *oldLog;
201 
202             if ((asprintf(&suffix, backup, idstring) == -1) ||
203                 (asprintf(&oldLog, "%s%s", logFileName, suffix) == -1)) {
204                 FatalError("Cannot allocate space for the log file name\n");
205             }
206             free(suffix);
207 
208             if (rename(logFileName, oldLog) == -1) {
209                 FatalError("Cannot move old log file \"%s\" to \"%s\"\n",
210                            logFileName, oldLog);
211             }
212             free(oldLog);
213         }
214     }
215     else {
216         if (remove(logFileName) != 0 && errno != ENOENT) {
217             FatalError("Cannot remove old log file \"%s\": %s\n",
218                        logFileName, strerror(errno));
219         }
220     }
221 
222     return logFileName;
223 }
224 #pragma GCC diagnostic pop
225 
226 /*
227  * LogInit is called to start logging to a file.  It is also called (with
228  * NULL arguments) when logging to a file is not wanted.  It must always be
229  * called, otherwise log messages will continue to accumulate in a buffer.
230  *
231  * %s, if present in the fname or backup strings, is expanded to the display
232  * string (or to a string containing the pid if the display is not yet set).
233  */
234 
235 static char *saved_log_fname;
236 static char *saved_log_backup;
237 static char *saved_log_tempname;
238 
239 const char *
LogInit(const char * fname,const char * backup)240 LogInit(const char *fname, const char *backup)
241 {
242     char *logFileName = NULL;
243 
244     if (fname && *fname) {
245         if (displayfd != -1) {
246             /* Display isn't set yet, so we can't use it in filenames yet. */
247             char pidstring[32];
248             snprintf(pidstring, sizeof(pidstring), "pid-%ld",
249                      (unsigned long) getpid());
250             logFileName = LogFilePrep(fname, backup, pidstring);
251             saved_log_tempname = logFileName;
252 
253             /* Save the patterns for use when the display is named. */
254             saved_log_fname = strdup(fname);
255             if (backup == NULL)
256                 saved_log_backup = NULL;
257             else
258                 saved_log_backup = strdup(backup);
259         } else
260             logFileName = LogFilePrep(fname, backup, display);
261         if ((logFile = fopen(logFileName, "w")) == NULL)
262             FatalError("Cannot open log file \"%s\"\n", logFileName);
263         setvbuf(logFile, NULL, _IONBF, 0);
264 
265         logFileFd = fileno(logFile);
266 
267         /* Flush saved log information. */
268         if (saveBuffer && bufferSize > 0) {
269             fwrite(saveBuffer, bufferPos, 1, logFile);
270             fflush(logFile);
271 #ifndef WIN32
272             fsync(fileno(logFile));
273 #endif
274         }
275     }
276 
277     /*
278      * Unconditionally free the buffer, and flag that the buffer is no longer
279      * needed.
280      */
281     if (saveBuffer && bufferSize > 0) {
282         free(saveBuffer);
283         saveBuffer = NULL;
284         bufferSize = 0;
285     }
286     needBuffer = FALSE;
287 
288     return logFileName;
289 }
290 
291 void
LogSetDisplay(void)292 LogSetDisplay(void)
293 {
294     if (saved_log_fname && strstr(saved_log_fname, "%s")) {
295         char *logFileName;
296 
297         logFileName = LogFilePrep(saved_log_fname, saved_log_backup, display);
298 
299         if (rename(saved_log_tempname, logFileName) == 0) {
300             LogMessageVerb(X_PROBED, 0,
301                            "Log file renamed from \"%s\" to \"%s\"\n",
302                            saved_log_tempname, logFileName);
303 
304             if (strlen(saved_log_tempname) >= strlen(logFileName))
305                 strncpy(saved_log_tempname, logFileName,
306                         strlen(saved_log_tempname));
307         }
308         else {
309             ErrorF("Failed to rename log file \"%s\" to \"%s\": %s\n",
310                    saved_log_tempname, logFileName, strerror(errno));
311         }
312 
313         /* free newly allocated string - can't free old one since existing
314            pointers to it may exist in DDX callers. */
315         free(logFileName);
316         free(saved_log_fname);
317         free(saved_log_backup);
318     }
319 }
320 
321 void
LogClose(enum ExitCode error)322 LogClose(enum ExitCode error)
323 {
324     if (logFile) {
325         int msgtype = (error == EXIT_NO_ERROR) ? X_INFO : X_ERROR;
326         LogMessageVerbSigSafe(msgtype, -1,
327                 "Server terminated %s (%d). Closing log file.\n",
328                 (error == EXIT_NO_ERROR) ? "successfully" : "with error",
329                 error);
330         fclose(logFile);
331         logFile = NULL;
332         logFileFd = -1;
333     }
334 }
335 
336 Bool
LogSetParameter(LogParameter param,int value)337 LogSetParameter(LogParameter param, int value)
338 {
339     switch (param) {
340     case XLOG_FLUSH:
341         logFlush = value ? TRUE : FALSE;
342         return TRUE;
343     case XLOG_SYNC:
344         logSync = value ? TRUE : FALSE;
345         return TRUE;
346     case XLOG_VERBOSITY:
347         logVerbosity = value;
348         return TRUE;
349     case XLOG_FILE_VERBOSITY:
350         logFileVerbosity = value;
351         return TRUE;
352     default:
353         return FALSE;
354     }
355 }
356 
357 enum {
358     LMOD_LONG     = 0x1,
359     LMOD_LONGLONG = 0x2,
360     LMOD_SHORT    = 0x4,
361     LMOD_SIZET    = 0x8,
362 };
363 
364 /**
365  * Parse non-digit length modifiers and set the corresponding flag in
366  * flags_return.
367  *
368  * @return the number of bytes parsed
369  */
parse_length_modifier(const char * format,size_t len,int * flags_return)370 static int parse_length_modifier(const char *format, size_t len, int *flags_return)
371 {
372     int idx = 0;
373     int length_modifier = 0;
374 
375     while (idx < len) {
376         switch (format[idx]) {
377             case 'l':
378                 BUG_RETURN_VAL(length_modifier & LMOD_SHORT, 0);
379 
380                 if (length_modifier & LMOD_LONG)
381                     length_modifier |= LMOD_LONGLONG;
382                 else
383                     length_modifier |= LMOD_LONG;
384                 break;
385             case 'h':
386                 BUG_RETURN_VAL(length_modifier & (LMOD_LONG|LMOD_LONGLONG), 0);
387                 length_modifier |= LMOD_SHORT;
388                 /* gcc says 'short int' is promoted to 'int' when
389                  * passed through '...', so ignored during
390                  * processing */
391                 break;
392             case 'z':
393                 length_modifier |= LMOD_SIZET;
394                 break;
395             default:
396                 goto out;
397         }
398         idx++;
399     }
400 
401 out:
402     *flags_return = length_modifier;
403     return idx;
404 }
405 
406 /**
407  * Signal-safe snprintf, with some limitations over snprintf. Be careful
408  * which directives you use.
409  */
410 static int
vpnprintf(char * string,int size_in,const char * f,va_list args)411 vpnprintf(char *string, int size_in, const char *f, va_list args)
412 {
413     int f_idx = 0;
414     int s_idx = 0;
415     int f_len = strlen_sigsafe(f);
416     char *string_arg;
417     char number[21];
418     int p_len;
419     int i;
420     uint64_t ui;
421     int64_t si;
422     size_t size = size_in;
423     int precision;
424 
425     for (; f_idx < f_len && s_idx < size - 1; f_idx++) {
426         int length_modifier = 0;
427         if (f[f_idx] != '%') {
428             string[s_idx++] = f[f_idx];
429             continue;
430         }
431 
432         f_idx++;
433 
434         /* silently swallow minimum field width */
435         if (f[f_idx] == '*') {
436             f_idx++;
437             va_arg(args, int);
438         } else {
439             while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
440                 f_idx++;
441         }
442 
443         /* is there a precision? */
444         precision = size;
445         if (f[f_idx] == '.') {
446             f_idx++;
447             if (f[f_idx] == '*') {
448                 f_idx++;
449                 /* precision is supplied in an int argument */
450                 precision = va_arg(args, int);
451             } else {
452                 /* silently swallow precision digits */
453                 while (f_idx < f_len && ((f[f_idx] >= '0' && f[f_idx] <= '9')))
454                     f_idx++;
455             }
456         }
457 
458         /* non-digit length modifiers */
459         if (f_idx < f_len) {
460             int parsed_bytes = parse_length_modifier(&f[f_idx], f_len - f_idx, &length_modifier);
461             if (parsed_bytes < 0)
462                 return 0;
463             f_idx += parsed_bytes;
464         }
465 
466         if (f_idx >= f_len)
467             break;
468 
469         switch (f[f_idx]) {
470         case 's':
471             string_arg = va_arg(args, char*);
472 
473             for (i = 0; string_arg[i] != 0 && s_idx < size - 1 && s_idx < precision; i++)
474                 string[s_idx++] = string_arg[i];
475             break;
476 
477         case 'u':
478             if (length_modifier & LMOD_LONGLONG)
479                 ui = va_arg(args, unsigned long long);
480             else if (length_modifier & LMOD_LONG)
481                 ui = va_arg(args, unsigned long);
482             else if (length_modifier & LMOD_SIZET)
483                 ui = va_arg(args, size_t);
484             else
485                 ui = va_arg(args, unsigned);
486 
487             FormatUInt64(ui, number);
488             p_len = strlen_sigsafe(number);
489 
490             for (i = 0; i < p_len && s_idx < size - 1; i++)
491                 string[s_idx++] = number[i];
492             break;
493         case 'i':
494         case 'd':
495             if (length_modifier & LMOD_LONGLONG)
496                 si = va_arg(args, long long);
497             else if (length_modifier & LMOD_LONG)
498                 si = va_arg(args, long);
499             else if (length_modifier & LMOD_SIZET)
500                 si = va_arg(args, ssize_t);
501             else
502                 si = va_arg(args, int);
503 
504             FormatInt64(si, number);
505             p_len = strlen_sigsafe(number);
506 
507             for (i = 0; i < p_len && s_idx < size - 1; i++)
508                 string[s_idx++] = number[i];
509             break;
510 
511         case 'p':
512             string[s_idx++] = '0';
513             if (s_idx < size - 1)
514                 string[s_idx++] = 'x';
515             ui = (uintptr_t)va_arg(args, void*);
516             FormatUInt64Hex(ui, number);
517             p_len = strlen_sigsafe(number);
518 
519             for (i = 0; i < p_len && s_idx < size - 1; i++)
520                 string[s_idx++] = number[i];
521             break;
522 
523         case 'x':
524             if (length_modifier & LMOD_LONGLONG)
525                 ui = va_arg(args, unsigned long long);
526             else if (length_modifier & LMOD_LONG)
527                 ui = va_arg(args, unsigned long);
528             else if (length_modifier & LMOD_SIZET)
529                 ui = va_arg(args, size_t);
530             else
531                 ui = va_arg(args, unsigned);
532 
533             FormatUInt64Hex(ui, number);
534             p_len = strlen_sigsafe(number);
535 
536             for (i = 0; i < p_len && s_idx < size - 1; i++)
537                 string[s_idx++] = number[i];
538             break;
539         case 'f':
540             {
541                 double d = va_arg(args, double);
542                 FormatDouble(d, number);
543                 p_len = strlen_sigsafe(number);
544 
545                 for (i = 0; i < p_len && s_idx < size - 1; i++)
546                     string[s_idx++] = number[i];
547             }
548             break;
549         case 'c':
550             {
551                 char c = va_arg(args, int);
552                 if (s_idx < size - 1)
553                     string[s_idx++] = c;
554             }
555             break;
556         case '%':
557             string[s_idx++] = '%';
558             break;
559         default:
560             BUG_WARN_MSG(f[f_idx], "Unsupported printf directive '%c'\n", f[f_idx]);
561             va_arg(args, char*);
562             string[s_idx++] = '%';
563             if (s_idx < size - 1)
564                 string[s_idx++] = f[f_idx];
565             break;
566         }
567     }
568 
569     string[s_idx] = '\0';
570 
571     return s_idx;
572 }
573 
574 static int
pnprintf(char * string,int size,const char * f,...)575 pnprintf(char *string, int size, const char *f, ...)
576 {
577     int rc;
578     va_list args;
579 
580     va_start(args, f);
581     rc = vpnprintf(string, size, f, args);
582     va_end(args);
583 
584     return rc;
585 }
586 
587 /* This function does the actual log message writes. It must be signal safe.
588  * When attempting to call non-signal-safe functions, guard them with a check
589  * of the inSignalContext global variable. */
590 static void
LogSWrite(int verb,const char * buf,size_t len,Bool end_line)591 LogSWrite(int verb, const char *buf, size_t len, Bool end_line)
592 {
593     static Bool newline = TRUE;
594     int ret;
595 
596     if (verb < 0 || logVerbosity >= verb)
597         ret = write(2, buf, len);
598 
599     if (verb < 0 || logFileVerbosity >= verb) {
600         if (inSignalContext && logFileFd >= 0) {
601             ret = write(logFileFd, buf, len);
602 #ifndef WIN32
603             if (logFlush && logSync)
604                 fsync(logFileFd);
605 #endif
606         }
607         else if (!inSignalContext && logFile) {
608             if (newline)
609                 fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0);
610             newline = end_line;
611             fwrite(buf, len, 1, logFile);
612             if (logFlush) {
613                 fflush(logFile);
614 #ifndef WIN32
615                 if (logSync)
616                     fsync(fileno(logFile));
617 #endif
618             }
619         }
620         else if (!inSignalContext && needBuffer) {
621             if (len > bufferUnused) {
622                 bufferSize += 1024;
623                 bufferUnused += 1024;
624                 saveBuffer = realloc(saveBuffer, bufferSize);
625                 if (!saveBuffer)
626                     FatalError("realloc() failed while saving log messages\n");
627             }
628             bufferUnused -= len;
629             memcpy(saveBuffer + bufferPos, buf, len);
630             bufferPos += len;
631         }
632     }
633 
634     /* There's no place to log an error message if the log write
635      * fails...
636      */
637     (void) ret;
638 }
639 
640 void
LogVWrite(int verb,const char * f,va_list args)641 LogVWrite(int verb, const char *f, va_list args)
642 {
643     return LogVMessageVerb(X_NONE, verb, f, args);
644 }
645 
646 void
LogWrite(int verb,const char * f,...)647 LogWrite(int verb, const char *f, ...)
648 {
649     va_list args;
650 
651     va_start(args, f);
652     LogVWrite(verb, f, args);
653     va_end(args);
654 }
655 
656 /* Returns the Message Type string to prepend to a logging message, or NULL
657  * if the message will be dropped due to insufficient verbosity. */
658 static const char *
LogMessageTypeVerbString(MessageType type,int verb)659 LogMessageTypeVerbString(MessageType type, int verb)
660 {
661     if (type == X_ERROR)
662         verb = 0;
663 
664     if (logVerbosity < verb && logFileVerbosity < verb)
665         return NULL;
666 
667     switch (type) {
668     case X_PROBED:
669         return X_PROBE_STRING;
670     case X_CONFIG:
671         return X_CONFIG_STRING;
672     case X_DEFAULT:
673         return X_DEFAULT_STRING;
674     case X_CMDLINE:
675         return X_CMDLINE_STRING;
676     case X_NOTICE:
677         return X_NOTICE_STRING;
678     case X_ERROR:
679         return X_ERROR_STRING;
680     case X_WARNING:
681         return X_WARNING_STRING;
682     case X_INFO:
683         return X_INFO_STRING;
684     case X_NOT_IMPLEMENTED:
685         return X_NOT_IMPLEMENTED_STRING;
686     case X_UNKNOWN:
687         return X_UNKNOWN_STRING;
688     case X_NONE:
689         return X_NONE_STRING;
690     case X_DEBUG:
691         return X_DEBUG_STRING;
692     default:
693         return X_UNKNOWN_STRING;
694     }
695 }
696 
697 void
LogVMessageVerb(MessageType type,int verb,const char * format,va_list args)698 LogVMessageVerb(MessageType type, int verb, const char *format, va_list args)
699 {
700     const char *type_str;
701     char buf[1024];
702     const size_t size = sizeof(buf);
703     Bool newline;
704     size_t len = 0;
705 
706     if (inSignalContext) {
707         LogVMessageVerbSigSafe(type, verb, format, args);
708         return;
709     }
710 
711     type_str = LogMessageTypeVerbString(type, verb);
712     if (!type_str)
713         return;
714 
715     /* if type_str is not "", prepend it and ' ', to message */
716     if (type_str[0] != '\0')
717         len += Xscnprintf(&buf[len], size - len, "%s ", type_str);
718 
719     if (size - len > 1)
720         len += Xvscnprintf(&buf[len], size - len, format, args);
721 
722     /* Force '\n' at end of truncated line */
723     if (size - len == 1)
724         buf[len - 1] = '\n';
725 
726     newline = (buf[len - 1] == '\n');
727     LogSWrite(verb, buf, len, newline);
728 }
729 
730 /* Log message with verbosity level specified. */
731 void
LogMessageVerb(MessageType type,int verb,const char * format,...)732 LogMessageVerb(MessageType type, int verb, const char *format, ...)
733 {
734     va_list ap;
735 
736     va_start(ap, format);
737     LogVMessageVerb(type, verb, format, ap);
738     va_end(ap);
739 }
740 
741 /* Log a message with the standard verbosity level of 1. */
742 void
LogMessage(MessageType type,const char * format,...)743 LogMessage(MessageType type, const char *format, ...)
744 {
745     va_list ap;
746 
747     va_start(ap, format);
748     LogVMessageVerb(type, 1, format, ap);
749     va_end(ap);
750 }
751 
752 /* Log a message using only signal safe functions. */
753 void
LogMessageVerbSigSafe(MessageType type,int verb,const char * format,...)754 LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...)
755 {
756     va_list ap;
757     va_start(ap, format);
758     LogVMessageVerbSigSafe(type, verb, format, ap);
759     va_end(ap);
760 }
761 
762 void
LogVMessageVerbSigSafe(MessageType type,int verb,const char * format,va_list args)763 LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args)
764 {
765     const char *type_str;
766     char buf[1024];
767     int len;
768     Bool newline;
769 
770     type_str = LogMessageTypeVerbString(type, verb);
771     if (!type_str)
772         return;
773 
774     /* if type_str is not "", prepend it and ' ', to message */
775     if (type_str[0] != '\0') {
776         LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE);
777         LogSWrite(verb, " ", 1, FALSE);
778     }
779 
780     len = vpnprintf(buf, sizeof(buf), format, args);
781 
782     /* Force '\n' at end of truncated line */
783     if (sizeof(buf) - len == 1)
784         buf[len - 1] = '\n';
785 
786     newline = (len > 0 && buf[len - 1] == '\n');
787     LogSWrite(verb, buf, len, newline);
788 }
789 
790 void
LogVHdrMessageVerb(MessageType type,int verb,const char * msg_format,va_list msg_args,const char * hdr_format,va_list hdr_args)791 LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format,
792                    va_list msg_args, const char *hdr_format, va_list hdr_args)
793 {
794     const char *type_str;
795     char buf[1024];
796     const size_t size = sizeof(buf);
797     Bool newline;
798     size_t len = 0;
799     int (*vprintf_func)(char *, int, const char* _X_RESTRICT_KYWD f, va_list args)
800             _X_ATTRIBUTE_PRINTF(3, 0);
801     int (*printf_func)(char *, int, const char* _X_RESTRICT_KYWD f, ...)
802             _X_ATTRIBUTE_PRINTF(3, 4);
803 
804     type_str = LogMessageTypeVerbString(type, verb);
805     if (!type_str)
806         return;
807 
808     if (inSignalContext) {
809         vprintf_func = vpnprintf;
810         printf_func = pnprintf;
811     } else {
812         vprintf_func = Xvscnprintf;
813         printf_func = Xscnprintf;
814     }
815 
816     /* if type_str is not "", prepend it and ' ', to message */
817     if (type_str[0] != '\0')
818         len += printf_func(&buf[len], size - len, "%s ", type_str);
819 
820     if (hdr_format && size - len > 1)
821         len += vprintf_func(&buf[len], size - len, hdr_format, hdr_args);
822 
823     if (msg_format && size - len > 1)
824         len += vprintf_func(&buf[len], size - len, msg_format, msg_args);
825 
826     /* Force '\n' at end of truncated line */
827     if (size - len == 1)
828         buf[len - 1] = '\n';
829 
830     newline = (buf[len - 1] == '\n');
831     LogSWrite(verb, buf, len, newline);
832 }
833 
834 void
LogHdrMessageVerb(MessageType type,int verb,const char * msg_format,va_list msg_args,const char * hdr_format,...)835 LogHdrMessageVerb(MessageType type, int verb, const char *msg_format,
836                   va_list msg_args, const char *hdr_format, ...)
837 {
838     va_list hdr_args;
839 
840     va_start(hdr_args, hdr_format);
841     LogVHdrMessageVerb(type, verb, msg_format, msg_args, hdr_format, hdr_args);
842     va_end(hdr_args);
843 }
844 
845 void
LogHdrMessage(MessageType type,const char * msg_format,va_list msg_args,const char * hdr_format,...)846 LogHdrMessage(MessageType type, const char *msg_format, va_list msg_args,
847               const char *hdr_format, ...)
848 {
849     va_list hdr_args;
850 
851     va_start(hdr_args, hdr_format);
852     LogVHdrMessageVerb(type, 1, msg_format, msg_args, hdr_format, hdr_args);
853     va_end(hdr_args);
854 }
855 
856 void
857 AbortServer(void)
858     _X_NORETURN;
859 
860 void
AbortServer(void)861 AbortServer(void)
862 {
863 #ifdef XF86BIGFONT
864     XF86BigfontCleanup();
865 #endif
866     CloseWellKnownConnections();
867     OsCleanup(TRUE);
868     AbortDevices();
869     AbortDDX(EXIT_ERR_ABORT);
870     fflush(stderr);
871     if (CoreDump)
872         OsAbort();
873     exit(1);
874 }
875 
876 #define AUDIT_PREFIX "AUDIT: %s: %ld: "
877 #ifndef AUDIT_TIMEOUT
878 #define AUDIT_TIMEOUT ((CARD32)(120 * 1000))    /* 2 mn */
879 #endif
880 
881 static int nrepeat = 0;
882 static int oldlen = -1;
883 static OsTimerPtr auditTimer = NULL;
884 
885 void
FreeAuditTimer(void)886 FreeAuditTimer(void)
887 {
888     if (auditTimer != NULL) {
889         /* Force output of pending messages */
890         TimerForce(auditTimer);
891         TimerFree(auditTimer);
892         auditTimer = NULL;
893     }
894 }
895 
896 static char *
AuditPrefix(void)897 AuditPrefix(void)
898 {
899     time_t tm;
900     char *autime, *s;
901     char *tmpBuf;
902     int len;
903 
904     time(&tm);
905     autime = ctime(&tm);
906     if ((s = strchr(autime, '\n')))
907         *s = '\0';
908     len = strlen(AUDIT_PREFIX) + strlen(autime) + 10 + 1;
909     tmpBuf = malloc(len);
910     if (!tmpBuf)
911         return NULL;
912     snprintf(tmpBuf, len, AUDIT_PREFIX, autime, (unsigned long) getpid());
913     return tmpBuf;
914 }
915 
916 void
AuditF(const char * f,...)917 AuditF(const char *f, ...)
918 {
919     va_list args;
920 
921     va_start(args, f);
922 
923     VAuditF(f, args);
924     va_end(args);
925 }
926 
927 static CARD32
AuditFlush(OsTimerPtr timer,CARD32 now,void * arg)928 AuditFlush(OsTimerPtr timer, CARD32 now, void *arg)
929 {
930     char *prefix;
931 
932     if (nrepeat > 0) {
933         prefix = AuditPrefix();
934         ErrorF("%slast message repeated %d times\n",
935                prefix != NULL ? prefix : "", nrepeat);
936         nrepeat = 0;
937         free(prefix);
938         return AUDIT_TIMEOUT;
939     }
940     else {
941         /* if the timer expires without anything to print, flush the message */
942         oldlen = -1;
943         return 0;
944     }
945 }
946 
947 void
VAuditF(const char * f,va_list args)948 VAuditF(const char *f, va_list args)
949 {
950     char *prefix;
951     char buf[1024];
952     int len;
953     static char oldbuf[1024];
954 
955     prefix = AuditPrefix();
956     len = vsnprintf(buf, sizeof(buf), f, args);
957 
958     if (len == oldlen && strcmp(buf, oldbuf) == 0) {
959         /* Message already seen */
960         nrepeat++;
961     }
962     else {
963         /* new message */
964         if (auditTimer != NULL)
965             TimerForce(auditTimer);
966         ErrorF("%s%s", prefix != NULL ? prefix : "", buf);
967         strlcpy(oldbuf, buf, sizeof(oldbuf));
968         oldlen = len;
969         nrepeat = 0;
970         auditTimer = TimerSet(auditTimer, 0, AUDIT_TIMEOUT, AuditFlush, NULL);
971     }
972     free(prefix);
973 }
974 
975 void
FatalError(const char * f,...)976 FatalError(const char *f, ...)
977 {
978     va_list args;
979     va_list args2;
980     static Bool beenhere = FALSE;
981 
982     if (beenhere)
983         ErrorFSigSafe("\nFatalError re-entered, aborting\n");
984     else
985         ErrorFSigSafe("\nFatal server error:\n");
986 
987     va_start(args, f);
988 
989     /* Make a copy for OsVendorFatalError */
990     va_copy(args2, args);
991 
992 #ifdef __APPLE__
993     {
994         va_list apple_args;
995 
996         va_copy(apple_args, args);
997         (void)vsnprintf(__crashreporter_info_buff__,
998                         sizeof(__crashreporter_info_buff__), f, apple_args);
999         va_end(apple_args);
1000     }
1001 #endif
1002     VErrorFSigSafe(f, args);
1003     va_end(args);
1004     ErrorFSigSafe("\n");
1005     if (!beenhere)
1006         OsVendorFatalError(f, args2);
1007     va_end(args2);
1008     if (!beenhere) {
1009         beenhere = TRUE;
1010         AbortServer();
1011     }
1012     else
1013         OsAbort();
1014  /*NOTREACHED*/}
1015 
1016 void
VErrorF(const char * f,va_list args)1017 VErrorF(const char *f, va_list args)
1018 {
1019 #ifdef DDXOSVERRORF
1020     if (OsVendorVErrorFProc)
1021         OsVendorVErrorFProc(f, args);
1022     else
1023         LogVWrite(-1, f, args);
1024 #else
1025     LogVWrite(-1, f, args);
1026 #endif
1027 }
1028 
1029 void
ErrorF(const char * f,...)1030 ErrorF(const char *f, ...)
1031 {
1032     va_list args;
1033 
1034     va_start(args, f);
1035     VErrorF(f, args);
1036     va_end(args);
1037 }
1038 
1039 void
VErrorFSigSafe(const char * f,va_list args)1040 VErrorFSigSafe(const char *f, va_list args)
1041 {
1042     LogVMessageVerbSigSafe(X_ERROR, -1, f, args);
1043 }
1044 
1045 void
ErrorFSigSafe(const char * f,...)1046 ErrorFSigSafe(const char *f, ...)
1047 {
1048     va_list args;
1049 
1050     va_start(args, f);
1051     VErrorFSigSafe(f, args);
1052     va_end(args);
1053 }
1054 
1055 void
LogPrintMarkers(void)1056 LogPrintMarkers(void)
1057 {
1058     /* Show what the message marker symbols mean. */
1059     LogWrite(0, "Markers: ");
1060     LogMessageVerb(X_PROBED, 0, "probed, ");
1061     LogMessageVerb(X_CONFIG, 0, "from config file, ");
1062     LogMessageVerb(X_DEFAULT, 0, "default setting,\n\t");
1063     LogMessageVerb(X_CMDLINE, 0, "from command line, ");
1064     LogMessageVerb(X_NOTICE, 0, "notice, ");
1065     LogMessageVerb(X_INFO, 0, "informational,\n\t");
1066     LogMessageVerb(X_WARNING, 0, "warning, ");
1067     LogMessageVerb(X_ERROR, 0, "error, ");
1068     LogMessageVerb(X_NOT_IMPLEMENTED, 0, "not implemented, ");
1069     LogMessageVerb(X_UNKNOWN, 0, "unknown.\n");
1070 }
1071