diff options
author | Chase Douglas <chase.douglas@canonical.com> | 2012-04-06 08:28:40 -0700 |
---|---|---|
committer | Keith Packard <keithp@keithp.com> | 2012-07-02 22:34:32 -0700 |
commit | 164b38c72fe9c69d13ea4f9c46d4ccc46566d826 (patch) | |
tree | ad76b14f240a7cf7f442b3b4e4937ff8b75e7aaf /os/log.c | |
parent | 704b847abfd29e9adde27127a15a963414f8bcf4 (diff) |
Add LogMessageVerbSigSafe() for logging messages while in signal context
[whot: edited to use varargs, squashed commit below]
Signed-off-by: Chase Douglas <chase.douglas@canonical.com>
Reviewed-by: Peter Hutterer <peter.hutterer@who-t.net>
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
os: fix vararg length calculation
Make %u and %x sizeof(unsigned int), %p sizeof(void*). This is printf
behaviour and we can't guarantee that void* is uint64_t anyway.
Signed-off-by: Peter Hutterer <peter.hutterer@who-t.net>
Reviewed-by: Chase Douglas <chase.douglas@canonical.com>
Diffstat (limited to 'os/log.c')
-rw-r--r-- | os/log.c | 135 |
1 files changed, 131 insertions, 4 deletions
@@ -172,6 +172,14 @@ asm(".desc ___crashreporter_info__, 0x10"); #define X_NONE_STRING "" #endif +static size_t +strlen_sigsafe(const char *s) +{ + size_t len; + for (len = 0; s[len]; len++); + return len; +} + /* * LogInit is called to start logging to a file. It is also called (with * NULL arguments) when logging to a file is not wanted. It must always be @@ -271,16 +279,97 @@ LogSetParameter(LogParameter param, int value) } } -/* This function does the actual log message writes. */ +static int +pnprintf(char *string, size_t size, const char *f, va_list args) +{ + int f_idx = 0; + int s_idx = 0; + int f_len = strlen_sigsafe(f); + char *string_arg; + char number[21]; + int p_len; + int i; + uint64_t ui; + + for (; f_idx < f_len && s_idx < size - 1; f_idx++) { + if (f[f_idx] != '%') { + string[s_idx++] = f[f_idx]; + continue; + } + + switch (f[++f_idx]) { + case 's': + string_arg = va_arg(args, char*); + p_len = strlen_sigsafe(string_arg); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = string_arg[i]; + break; + + case 'u': + ui = va_arg(args, unsigned); + FormatUInt64(ui, number); + p_len = strlen_sigsafe(number); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = number[i]; + break; + + case 'p': + string[s_idx++] = '0'; + if (s_idx < size - 1) + string[s_idx++] = 'x'; + ui = (uintptr_t)va_arg(args, void*); + FormatUInt64Hex(ui, number); + p_len = strlen_sigsafe(number); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = number[i]; + break; + + case 'x': + ui = va_arg(args, unsigned); + FormatUInt64Hex(ui, number); + p_len = strlen_sigsafe(number); + + for (i = 0; i < p_len && s_idx < size - 1; i++) + string[s_idx++] = number[i]; + break; + + default: + va_arg(args, char*); + string[s_idx++] = '%'; + if (s_idx < size - 1) + string[s_idx++] = f[f_idx]; + break; + } + } + + string[s_idx] = '\0'; + + return s_idx; +} + +/* This function does the actual log message writes. It must be signal safe. + * When attempting to call non-signal-safe functions, guard them with a check + * of the inSignalContext global variable. */ static void LogSWrite(int verb, const char *buf, size_t len, Bool end_line) { static Bool newline = TRUE; if (verb < 0 || logVerbosity >= verb) - fwrite(buf, len, 1, stderr); + write(2, buf, len); + if (verb < 0 || logFileVerbosity >= verb) { - if (logFile) { + if (inSignalContext && logFileFd >= 0) { + write(logFileFd, buf, len); +#ifdef WIN32 + if (logFlush && logSync) + fsync(logFileFd); +#endif + } + else if (!inSignalContext && logFile) { if (newline) fprintf(logFile, "[%10.3f] ", GetTimeInMillis() / 1000.0); newline = end_line; @@ -293,7 +382,7 @@ LogSWrite(int verb, const char *buf, size_t len, Bool end_line) #endif } } - else if (needBuffer) { + else if (!inSignalContext && needBuffer) { if (len > bufferUnused) { bufferSize += 1024; bufferUnused += 1024; @@ -415,6 +504,44 @@ LogMessage(MessageType type, const char *format, ...) va_end(ap); } +/* Log a message using only signal safe functions. */ +void +LogMessageVerbSigSafe(MessageType type, int verb, const char *format, ...) +{ + va_list ap; + va_start(ap, format); + LogVMessageVerbSigSafe(type, verb, format, ap); + va_end(ap); +} + +void +LogVMessageVerbSigSafe(MessageType type, int verb, const char *format, va_list args) +{ + const char *type_str; + char buf[1024]; + int len; + Bool newline; + + type_str = LogMessageTypeVerbString(type, verb); + if (!type_str) + return; + + /* if type_str is not "", prepend it and ' ', to message */ + if (type_str[0] != '\0') { + LogSWrite(verb, type_str, strlen_sigsafe(type_str), FALSE); + LogSWrite(verb, " ", 1, FALSE); + } + + len = pnprintf(buf, sizeof(buf), format, args); + + /* Force '\n' at end of truncated line */ + if (sizeof(buf) - len == 1) + buf[len - 1] = '\n'; + + newline = (buf[len - 1] == '\n'); + LogSWrite(verb, buf, len, newline); +} + void LogVHdrMessageVerb(MessageType type, int verb, const char *msg_format, va_list msg_args, const char *hdr_format, va_list hdr_args) |