/* iminternal.c * This file set implements the internal messages input module for rsyslog. * Note: we currently do not have an input module spec, but * we will have one in the future. This module needs then to be * adapted. * * File begun on 2007-08-03 by RGerhards * * Copyright 2007-2022 Rainer Gerhards and Adiscon GmbH. * * This file is part of rsyslog. * * 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 * -or- * see COPYING.ASL20 in the source distribution * * 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 "config.h" #include "rsyslog.h" #include #include #include #include #include #include #include "syslogd.h" #include "linkedlist.h" #include "iminternal.h" #include "unicode-helper.h" static linkedList_t llMsgs; static pthread_mutex_t mutList = PTHREAD_MUTEX_INITIALIZER; /* destructs an iminternal object */ static rsRetVal iminternalDestruct(iminternal_t *pThis) { DEFiRet; if(pThis->pMsg != NULL) msgDestruct(&pThis->pMsg); free(pThis); RETiRet; } /* Construct an iminternal object */ static rsRetVal iminternalConstruct(iminternal_t **ppThis) { DEFiRet; if((*ppThis = (iminternal_t*) calloc(1, sizeof(iminternal_t))) == NULL) { iRet = RS_RET_OUT_OF_MEMORY; } RETiRet; } /* add a message to the linked list * Note: the pMsg reference counter is not incremented. Consequently, * the caller must NOT decrement it. The caller actually hands over * full ownership of the pMsg object. */ rsRetVal iminternalAddMsg(smsg_t *pMsg) { DEFiRet; iminternal_t *pThis = NULL; struct timespec to; int r; int is_locked = 0; /* we guard against deadlock, so we can guarantee rsyslog will never * block due to internal messages. The 1 second timeout should be * sufficient under all circumstances. */ to.tv_sec = time(NULL) + 1; to.tv_nsec = 0; #if !defined(__APPLE__) r = pthread_mutex_timedlock(&mutList, &to); #else r = pthread_mutex_trylock(&mutList); // must check #endif if(r != 0) { dbgprintf("iminternalAddMsg: timedlock for mutex failed with %d, msg %s\n", r, getMSG(pMsg)); /* the message is lost, nothing we can do against this! */ msgDestruct(&pMsg); ABORT_FINALIZE(RS_RET_ERR); } is_locked = 1; CHKiRet(iminternalConstruct(&pThis)); pThis->pMsg = pMsg; CHKiRet(llAppend(&llMsgs, NULL, (void*) pThis)); if(PREFER_FETCH_32BIT(bHaveMainQueue)) { DBGPRINTF("signaling new internal message via SIGTTOU: '%s'\n", pThis->pMsg->pszRawMsg); kill(glblGetOurPid(), SIGTTOU); } finalize_it: if(is_locked) { pthread_mutex_unlock(&mutList); } if(iRet != RS_RET_OK) { dbgprintf("iminternalAddMsg() error %d - can not otherwise report this error, message lost\n", iRet); if(pThis != NULL) iminternalDestruct(pThis); } RETiRet; } /* pull the first error message from the linked list, remove it * from the list and return it to the caller. The caller is * responsible for freeing the message! */ rsRetVal iminternalRemoveMsg(smsg_t **ppMsg) { DEFiRet; iminternal_t *pThis; linkedListCookie_t llCookie = NULL; pthread_mutex_lock(&mutList); CHKiRet(llGetNextElt(&llMsgs, &llCookie, (void*)&pThis)); if(!strcmp((char*)pThis->pMsg->pszHOSTNAME, "[localhost]")) { /* early (pre-conf) startup message detected, need to set real hostname now */ MsgSetHOSTNAME(pThis->pMsg, glblGetLocalHostName(), ustrlen(glblGetLocalHostName())); } *ppMsg = pThis->pMsg; pThis->pMsg = NULL; /* we do no longer own it - important for destructor */ if(llDestroyRootElt(&llMsgs) != RS_RET_OK) { dbgprintf("Root element of iminternal linked list could not be destroyed - there is " "nothing we can do against it, we ignore it for now. Things may go wild " "from here on. This is most probably a program logic error.\n"); } finalize_it: pthread_mutex_unlock(&mutList); RETiRet; } /* initialize the iminternal subsystem * must be called once at the start of the program */ rsRetVal modInitIminternal(void) { DEFiRet; iRet = llInit(&llMsgs, iminternalDestruct, NULL, NULL); RETiRet; } /* de-initialize the iminternal subsystem * must be called once at the end of the program * Note: the error list must have been pulled first. We do * NOT care if there are any errors left - we simply destroy * them. */ rsRetVal modExitIminternal(void) { DEFiRet; iRet = llDestroy(&llMsgs); RETiRet; }