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