/** * WinPR: Windows Portable Runtime * WinPR Logger * * Copyright © 2015 Thincast Technologies GmbH * Copyright © 2015 David FORT * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include "JournaldAppender.h" #include #include #include #include #include typedef struct { wLogAppender common; char* identifier; FILE* stream; } wLogJournaldAppender; static BOOL WLog_JournaldAppender_Open(wLog* log, wLogAppender* appender) { int fd = 0; wLogJournaldAppender* journaldAppender = nullptr; if (!log || !appender) return FALSE; journaldAppender = (wLogJournaldAppender*)appender; if (journaldAppender->stream) return TRUE; fd = sd_journal_stream_fd(journaldAppender->identifier, LOG_INFO, 1); if (fd < 0) return FALSE; journaldAppender->stream = fdopen(fd, "w"); if (!journaldAppender->stream) { close(fd); return FALSE; } setbuffer(journaldAppender->stream, nullptr, 0); return TRUE; } static BOOL WLog_JournaldAppender_Close(wLog* log, wLogAppender* appender) { wLogJournaldAppender* journaldAppender = (wLogJournaldAppender*)appender; if (!log || !appender) return FALSE; if (journaldAppender->stream) (void)fclose(journaldAppender->stream); free(journaldAppender->identifier); journaldAppender->stream = nullptr; journaldAppender->identifier = nullptr; return TRUE; } static BOOL WLog_JournaldAppender_WriteMessage(wLog* log, wLogAppender* appender, const wLogMessage* cmessage) { if (!log || !appender || !cmessage) return FALSE; wLogJournaldAppender* journaldAppender = (wLogJournaldAppender*)appender; const char* formatStr = nullptr; switch (cmessage->Level) { case WLOG_TRACE: case WLOG_DEBUG: formatStr = "<7>%s%s\n"; break; case WLOG_INFO: formatStr = "<6>%s%s\n"; break; case WLOG_WARN: formatStr = "<4>%s%s\n"; break; case WLOG_ERROR: formatStr = "<3>%s%s\n"; break; case WLOG_FATAL: formatStr = "<2>%s%s\n"; break; case WLOG_OFF: return TRUE; default: (void)fprintf(stderr, "%s: unknown level %" PRIu32 "\n", __func__, cmessage->Level); return FALSE; } char prefix[WLOG_MAX_PREFIX_SIZE] = WINPR_C_ARRAY_INIT; WLog_Layout_GetMessagePrefix(log, appender->Layout, cmessage, prefix, sizeof(prefix)); if (cmessage->Level != WLOG_OFF) { WINPR_PRAGMA_DIAG_PUSH WINPR_PRAGMA_DIAG_IGNORED_FORMAT_NONLITERAL(void) fprintf(journaldAppender->stream, formatStr, prefix, cmessage->TextString); WINPR_PRAGMA_DIAG_POP } return TRUE; } static BOOL WLog_JournaldAppender_WriteDataMessage(wLog* log, wLogAppender* appender, const wLogMessage* message) { if (!log || !appender || !message) return FALSE; (void)fprintf(stderr, "[TODO: %s] data messages not implemented! Ignoring.\n", __func__); return TRUE; } static BOOL WLog_JournaldAppender_WriteImageMessage(wLog* log, wLogAppender* appender, const wLogMessage* message) { if (!log || !appender || !message) return FALSE; (void)fprintf(stderr, "[TODO: %s] image messages not implemented! Ignoring.\n", __func__); return TRUE; } static BOOL WLog_JournaldAppender_Set(wLogAppender* appender, const char* setting, void* value) { wLogJournaldAppender* journaldAppender = (wLogJournaldAppender*)appender; /* Just check the value string is not empty */ if (!value || (strnlen(value, 2) == 0)) return FALSE; if (strcmp("identifier", setting) != 0) return FALSE; /* If the stream is already open the identifier can't be changed */ if (journaldAppender->stream) return FALSE; if (journaldAppender->identifier) free(journaldAppender->identifier); return ((journaldAppender->identifier = _strdup((const char*)value)) != nullptr); } static void WLog_JournaldAppender_Free(wLogAppender* appender) { wLogJournaldAppender* journaldAppender = nullptr; if (appender) { journaldAppender = (wLogJournaldAppender*)appender; if (journaldAppender->stream) (void)fclose(journaldAppender->stream); free(journaldAppender->identifier); free(journaldAppender); } } wLogAppender* WLog_JournaldAppender_New(wLog* log) { LPCSTR name = "WLOG_JOURNALD_ID"; wLogJournaldAppender* appender = (wLogJournaldAppender*)calloc(1, sizeof(wLogJournaldAppender)); if (!appender) return nullptr; appender->common.Type = WLOG_APPENDER_JOURNALD; appender->common.Open = WLog_JournaldAppender_Open; appender->common.Close = WLog_JournaldAppender_Close; appender->common.WriteMessage = WLog_JournaldAppender_WriteMessage; appender->common.WriteDataMessage = WLog_JournaldAppender_WriteDataMessage; appender->common.WriteImageMessage = WLog_JournaldAppender_WriteImageMessage; appender->common.Set = WLog_JournaldAppender_Set; appender->common.Free = WLog_JournaldAppender_Free; const DWORD nSize = GetEnvironmentVariableA(name, nullptr, 0); if (nSize) { appender->identifier = (LPSTR)malloc(nSize); if (!appender->identifier) goto error_open; if (GetEnvironmentVariableA(name, appender->identifier, nSize) != nSize - 1) goto error_open; if (!WLog_JournaldAppender_Open(log, (wLogAppender*)appender)) goto error_open; } return (wLogAppender*)appender; error_open: free(appender->identifier); free(appender); return nullptr; }