/* * SPDX license identifier: MPL-2.0 * * Copyright (C) 2011-2015, BMW AG * * This file is part of GENIVI Project DLT - Diagnostic Log and Trace. * * This Source Code Form is subject to the terms of the * Mozilla Public License (MPL), v. 2.0. * If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. * * For further information see http://www.genivi.org/. */ /*! * \author Lassi Marttala * * \copyright Copyright © 2011-2015 BMW AG. \n * License MPL-2.0: Mozilla Public License version 2.0 http://mozilla.org/MPL/2.0/. * * \file dlt-system-process-handling.c */ /******************************************************************************* ** ** ** SRC-MODULE: dlt-systemprocess-handling.c ** ** ** ** TARGET : linux ** ** ** ** PROJECT : DLT ** ** ** ** AUTHOR : Lassi Marttala ** ** ** ** PURPOSE : ** ** ** ** REMARKS : ** ** ** ** PLATFORM DEPENDANT [yes/no]: yes ** ** ** ** TO BE CHANGED BY USER [yes/no]: no ** ** ** *******************************************************************************/ #include "dlt.h" #include "dlt-system.h" #include #include #include #include #include #include #include #include #include #include DLT_IMPORT_CONTEXT(dltsystem) DLT_IMPORT_CONTEXT(syslogContext) DLT_IMPORT_CONTEXT(journalContext) DLT_IMPORT_CONTEXT(watchdogContext) DLT_IMPORT_CONTEXT(procContext) DLT_IMPORT_CONTEXT(filetransferContext) extern DltContext logfileContext[DLT_SYSTEM_LOG_FILE_MAX]; volatile uint8_t quit = 0; #if defined(DLT_FILETRANSFER_ENABLE) extern s_ft_inotify ino; #endif int daemonize() { DLT_LOG(dltsystem, DLT_LOG_DEBUG, DLT_STRING("dlt-system-process-handling, daemonize")); /* Fork new process */ int f = fork(); if (f < 0) return f; if (f > 0) exit(0); /* Create a new process group */ if (setsid() < 0) return -1; /** * Close all file descriptors and point * stdin, stdout and stderr to /dev/null */ int i; for (i = getdtablesize(); i >= 0; i--) close(i); int fd = open("/dev/null", O_RDWR); if (fd < 0) return -1; if ((dup(fd) < 0) || (dup(fd) < 0)) { close(fd); return -1; } /** * Ignore signals related to child processes and * terminal handling. */ signal(SIGCHLD, SIG_IGN); signal(SIGTSTP, SIG_IGN); signal(SIGTTOU, SIG_IGN); signal(SIGTTIN, SIG_IGN); /*no close(fd); - we just intentionally pointed stdx to null! tbd: set ignore for coverity */ return 0; } /* Unregisters all DLT Contexts and closes all file descriptors */ void cleanup_processes(struct pollfd *pollfd, sd_journal *j, DltSystemConfiguration *config) { //Syslog cleanup if (config->Syslog.Enable) DLT_UNREGISTER_CONTEXT(syslogContext); //Journal cleanup #if defined(DLT_SYSTEMD_JOURNAL_ENABLE) if (config->Journal.Enable) DLT_UNREGISTER_CONTEXT(journalContext); if(j != NULL) sd_journal_close(j); #endif //Logfile cleanup if (config->LogFile.Enable) { for (int i = 0; i < config->LogFile.Count; i++) DLT_UNREGISTER_CONTEXT(logfileContext[i]); } //LogProcess cleanup if (config->LogProcesses.Enable) { DLT_UNREGISTER_CONTEXT(procContext); } //Watchdog cleanup #if defined(DLT_SYSTEMD_WATCHDOG_ENABLE) DLT_UNREGISTER_CONTEXT(watchdogContext); #endif //FileTransfer cleanup #if defined(DLT_FILETRANSFER_ENABLE) if (config->Filetransfer.Enable) { DLT_UNREGISTER_CONTEXT(filetransferContext); } #endif for (int i = 0; i < MAX_FD_NUMBER; i++) { if(pollfd[i].fd > 0) close(pollfd[i].fd); } } /* Creates timer for LogFile and LogProcess, that need to be called every second. */ int register_timer_fd(struct pollfd *pollfd, int fdcnt) { struct itimerspec timerValue; memset(&timerValue, '\0', sizeof(timerValue)); timerValue.it_value.tv_sec = 1; timerValue.it_value.tv_nsec = 0; timerValue.it_interval.tv_sec = 1; timerValue.it_interval.tv_nsec = 0; int timerfd = timerfd_create(CLOCK_MONOTONIC, 0); if (timerfd < 0) { DLT_LOG(dltsystem, DLT_LOG_ERROR, DLT_STRING("Failed to create timer fd")); return -1; } pollfd[fdcnt].fd = timerfd; pollfd[fdcnt].events = POLLIN; if (timerfd_settime(timerfd, 0, &timerValue, NULL) < 0) { // init timer with 1 second DLT_LOG(dltsystem, DLT_LOG_ERROR, DLT_STRING("Could not start timer")); return -1; } return 0; } /* Routine for executing LogProcess and LogFile, when timer expires */ void timer_fd_handler(int fd, DltSystemConfiguration *config) { uint64_t timersElapsed = 0ULL; int r = read(fd, &timersElapsed, 8U); // only needed to reset fd event if (r < 0) DLT_LOG(dltsystem, DLT_LOG_ERROR, DLT_STRING("Error while reading timer fd: "), DLT_STRING(strerror(r))); if(config->LogProcesses.Enable) logprocess_fd_handler(config); if(config->LogFile.Enable) logfile_fd_handler(config); } void start_dlt_system_processes(DltSystemConfiguration *config) { DLT_LOG(dltsystem, DLT_LOG_DEBUG, DLT_STRING("dlt-system-process-handling, start threads")); if (config->Shell.Enable) init_shell(); int fdcnt = 0; /* Init FDs for all activated processes*/ struct pollfd pollfd[MAX_FD_NUMBER]; // Holds all FDs and events uint8_t fdType[MAX_FD_NUMBER]; // Holds corresponding enum for process identification for(int cnt = 0 ; cnt < MAX_FD_NUMBER ; cnt++) { pollfd[cnt].fd = 0; pollfd[cnt].events = 0; } //init FD for LogFile and LogProcesses if (config->LogProcesses.Enable || config->LogFile.Enable) { fdType[fdcnt] = fdType_timer; if (register_timer_fd(pollfd, fdcnt) == 0) { if(config->LogProcesses.Enable) logprocess_init(config); if(config->LogFile.Enable) logfile_init(config); fdcnt++; } } //init FD for Syslog int syslogSock = 0; if (config->Syslog.Enable) { fdType[fdcnt] = fdType_syslog; syslogSock = register_syslog_fd(pollfd, fdcnt, config); fdcnt++; } //init FD for Journal sd_journal *j = NULL; #if defined(DLT_SYSTEMD_JOURNAL_ENABLE) if (config->Journal.Enable) { register_journal_fd(&j, pollfd, fdcnt, config); fdType[fdcnt] = fdType_journal; fdcnt++; } #endif //init FD for FileTransfer #if defined(DLT_FILETRANSFER_ENABLE) if (config->Filetransfer.Enable) { init_filetransfer_dirs(config); pollfd[fdcnt].fd = ino.handle; pollfd[fdcnt].events = POLLIN; fdType[fdcnt] = fdType_filetransfer; fdcnt++; } #endif //init FD for Watchdog #if defined(DLT_SYSTEMD_WATCHDOG_ENABLE) fdType[fdcnt] = fdType_watchdog; register_watchdog_fd(pollfd, fdcnt); #endif while (quit == 0) { int ready; ready = poll(pollfd, MAX_FD_NUMBER, -1); if (ready == -1 && quit == 0) DLT_LOG(dltsystem, DLT_LOG_ERROR, DLT_STRING("Error while poll. Exit with: "), DLT_STRING(strerror(ready))); for (int i = 0; i < MAX_FD_NUMBER; i++) { if(pollfd[i].revents & POLLIN){ if (fdType[i] == fdType_syslog && syslogSock > 0) { syslog_fd_handler(syslogSock); } else if (fdType[i] == fdType_timer) { timer_fd_handler(pollfd[i].fd, config); } #if defined(DLT_SYSTEMD_JOURNAL_ENABLE) else if((fdType[i] == fdType_journal) && (j != NULL)) { if(sd_journal_process(j) == SD_JOURNAL_APPEND) { journal_fd_handler(j, config); } } #endif #if defined(DLT_FILETRANSFER_ENABLE) else if (fdType[i] == fdType_filetransfer) { filetransfer_fd_handler(config); } #endif #if defined(DLT_SYSTEMD_WATCHDOG_ENABLE) else if (fdType[i] == fdType_watchdog) { watchdog_fd_handler(pollfd[i].fd); } #endif } } } cleanup_processes(pollfd, j, config); } void dlt_system_signal_handler(int sig) { switch (sig) { case SIGHUP: case SIGTERM: case SIGINT: case SIGQUIT: quit = 1; break; default: break; } }