From fba81ca350512d10a64289f0998866a739856c1b Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 9 Feb 2025 19:04:41 +0100 Subject: [PATCH 1/3] Remove procps scanning for other running pihole-FTL processes due to possible detection (and startup prevention) of legit long-lived other processes like "pihole-FTL sqlite3", etc. Signed-off-by: DL6ER --- src/daemon.c | 73 +++++++++++++++-- src/daemon.h | 1 + src/procps.c | 226 ++++++--------------------------------------------- 3 files changed, 96 insertions(+), 204 deletions(-) diff --git a/src/daemon.c b/src/daemon.c index 9c0e641a9..933ba8ae9 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -109,12 +109,22 @@ void go_daemon(void) // Closing stdin, stdout and stderr is handled by dnsmasq } +/** + * @brief Save the current process ID (PID) to a file. + * + * This function retrieves the PID of the current process and writes it to a + * specified file. If the file cannot be opened for writing, an error is logged. + * Otherwise, the PID is written to the file and the file is closed. The PID is + * also logged for informational purposes. + * + * @return void + */ void savepid(void) { - FILE *f; // Get PID of the current process const pid_t pid = getpid(); // Open file for writing + FILE *f = NULL; if((f = fopen(config.files.pid.v.s, "w+")) == NULL) { // Log error @@ -129,20 +139,73 @@ void savepid(void) log_info("PID of FTL process: %i", (int)pid); } +/** + * @brief Reads the process ID (PID) from a file. + * + * This function attempts to open a file specified by the configuration + * and read the PID from it. If the file cannot be opened or the PID + * cannot be parsed, appropriate warnings are logged and the function + * returns -1. + * + * @return pid_t The PID read from the file on success, or -1 on failure. + */ +pid_t readpid(void) +{ + pid_t pid = -1; + FILE *f = NULL; + // Open file for reading + if((f = fopen(config.files.pid.v.s, "r")) == NULL) + { + // Log error + log_warn("Unable to read PID from file: %s", strerror(errno)); + return -1; + } + + // Try to read PID from file if it is not empty + if(fscanf(f, "%d", &pid) != 1) + log_debug(DEBUG_SHMEM, "Unable to parse PID in PID file"); + + // Close file + fclose(f); + + return pid; +} + +/** + * @brief Empties the PID file and remove it + * + * This function opens the PID file in write mode, which effectively + * empties its contents. If the file cannot be opened, a warning is logged. + * + * @note This function does not remove the PID file, it only empties it. + */ static void removepid(void) { - // Note that this function is not really removing the PID file but - // rather emptying it - FILE *f; - // Open file for writing (emptying it) + FILE *f = NULL; + // Open file for writing to overwrite/empty it if((f = fopen(config.files.pid.v.s, "w")) == NULL) { log_warn("Unable to empty PID file: %s", strerror(errno)); return; } fclose(f); + + // Remove PID file + if(unlink(config.files.pid.v.s) != 0) + log_warn("Unable to remove PID file: %s", strerror(errno)); } +/** + * @brief Retrieves the username of the effective user ID of the calling process. + * + * This function uses the `geteuid()` function to get the effective user ID (EUID) of the calling process + * and then searches the user database for an entry with a matching UID using the `getpwuid()` function. + * If a matching entry is found, the username is returned. If no matching entry is found, the UID is + * returned as a string. If an error occurs during the lookup, a warning is logged. + * + * @return A dynamically allocated string containing the username or UID. The caller is responsible for + * freeing the allocated memory. Returns NULL if memory allocation fails. + */ char *getUserName(void) { char *name; diff --git a/src/daemon.h b/src/daemon.h index f66747bf7..1c304dec4 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -15,6 +15,7 @@ extern pthread_t threads[THREADS_MAX]; void go_daemon(void); void savepid(void); +pid_t readpid(void); char *getUserName(void); const char *hostname(void); const char *domainname(void); diff --git a/src/procps.c b/src/procps.c index cfa493cd1..8a76e6f88 100644 --- a/src/procps.c +++ b/src/procps.c @@ -17,6 +17,8 @@ #include // config #include "config/config.h" +// readpid() +#include "daemon.h" #define PROCESS_NAME "pihole-FTL" @@ -73,223 +75,49 @@ bool get_process_name(const pid_t pid, char name[PROC_PATH_SIZ]) return true; } -// This function tries to obtain the parent process ID of a given PID -// It returns true on success, false otherwise and stores the parent PID in -// the given pid_t pointer -static bool get_process_ppid(const pid_t pid, pid_t *ppid) -{ - // Try to open status file - char filename[sizeof("/proc/%u/task/%u/status") + sizeof(int)*3 * 2]; - snprintf(filename, sizeof(filename), "/proc/%d/status", pid); - FILE *f = fopen(filename, "r"); - if(f == NULL) - return false; - - // Read comm from opened file - char buffer[128]; - while(fgets(buffer, sizeof(buffer), f) != NULL) - { - if(sscanf(buffer, "PPid: %d\n", ppid) == 1) - break; - } - fclose(f); - - return true; -} - -// This function tries to obtain the process creation time of a given PID -// It returns true on success, false otherwise and stores the creation time in -// the given buffer -static bool get_process_creation_time(const pid_t pid, char timestr[TIMESTR_SIZE]) -{ - // Try to open comm file - char filename[sizeof("/proc/%u/task/%u/comm") + sizeof(int)*3 * 2]; - snprintf(filename, sizeof(filename), "/proc/%d/comm", pid); - struct stat st; - if(stat(filename, &st) < 0) - return false; - get_timestr(timestr, st.st_ctim.tv_sec, false, false); - - return true; -} - -// This function checks if a given PID is running inside a docker container -static bool is_in_docker(const pid_t pid) -{ - char filename[sizeof("/proc/%u/cgroup") + sizeof(int)*3]; - snprintf(filename, sizeof(filename), "/proc/%d/cgroup", pid); - - FILE *f = fopen(filename, "r"); - if(f == NULL) - return false; - - char buffer[128]; - while(fgets(buffer, sizeof(buffer), f) != NULL) - { - if(strstr(buffer, "/docker") != NULL) - { - fclose(f); - return true; - } - } - fclose(f); - - return false; -} - // This function prints an info message about if another FTL process is already // running. It returns true if another FTL process is already running, false // otherwise. bool another_FTL(void) { - DIR *dirPos; - struct dirent *entry; const pid_t ourselves = getpid(); bool already_running = false; - pid_t pid = 0; + pid_t pid = readpid(); - // First we try to read the PID file and compare the PID in there with - // our own PID. If the PID file does not exist or does not contain our - // PID, we try to find another FTL process by looking at the process - // list further down. - if(config.files.pid.v.s != NULL) + if(pid == ourselves) { - FILE *pidFile = fopen(config.files.pid.v.s, "r"); - if(pidFile != NULL) - { - if(fscanf(pidFile, "%d", &pid) == 1) - { - if(pid == ourselves) - { - log_debug(DEBUG_SHMEM, "PID file contains our own PID"); - } - else - { - // Note: kill(pid, 0) does not send a - // signal, but merely checks if the - // process exists. If the process does - // not exist, kill() returns -1 and sets - // errno to ESRCH. However, if the - // process exists, but security - // restrictions tell the system to deny - // its existence, we cannot distinguish - // between the process not existing and - // the process existing but being denied - // to us. In that case, our fallback - // solution below kicks in and iterates - // over /proc instead. - already_running = kill(pid, 0) == 0; - log_debug(DEBUG_SHMEM, "PID file contains PID %d (%s), we are %d", - pid, already_running ? "running" : "dead", ourselves); - } - } - else - { - log_debug(DEBUG_SHMEM, "Failed to parse PID in PID file: %s", - strerror(errno)); - } - fclose(pidFile); - } - else - { - log_debug(DEBUG_SHMEM, "Failed to open PID file \"%s\": %s", - config.files.pid.v.s, strerror(errno)); - } + log_info("PID file contains our own PID"); } - - // If already_running is true, we are done - if(already_running) + else if(pid < 0) { - log_crit("%s is already running (PID %d)!", PROCESS_NAME, pid); - return true; + log_info("PID file does not exist or not readable"); } - - // If the PID file does not contain our own PID, we try to find a running - // process with the same name as our own process - // Open /proc - errno = 0; - if ((dirPos = opendir("/proc")) == NULL) + else { - log_warn("Failed to access /proc: %s", strerror(errno)); - return false; + // Note: kill(pid, 0) does not send a signal, but merely checks + // if the process exists. If the process does not exist, kill() + // returns -1 and sets errno to ESRCH. However, if the process + // exists, but security restrictions tell the system to deny its + // existence, we cannot distinguish between the process not + // existing and the process existing but being denied to us. In + // that case, our fallback solution below kicks in and iterates + // over /proc instead. + already_running = kill(pid, 0) == 0; + log_info("PID file contains PID %d (%s), we are %d", + pid, already_running ? "running" : "dead", ourselves); } - // Loop over entries in /proc - // This is much more efficient than iterating over all possible PIDs - pid_t last_pid = 0; - size_t last_len = 0u; - log_debug(DEBUG_SHMEM, "Reading /proc/[0-9]*"); - while ((entry = readdir(dirPos)) != NULL) + // If already_running is true, we are done + if(already_running) { - // We are only interested in subdirectories of /proc - if(entry->d_type != DT_DIR) - continue; - // We are only interested in PID subdirectories - if(entry->d_name[0] < '0' || entry->d_name[0] > '9') - continue; - - // Extract PID - pid = strtol(entry->d_name, NULL, 10); - - // Get process name - char name[PROC_PATH_SIZ] = { 0 }; - if(!get_process_name(pid, name)) - continue; - - log_debug(DEBUG_SHMEM, "PID: %d -> name: %s%s", pid, name, pid == ourselves ? " (us)" : ""); - - // Skip our own process - if(pid == ourselves) - continue; - - // Only process this if this is our own process - if(strcasecmp(name, PROCESS_NAME) != 0) - continue; - - // Get parent process ID (PPID) - pid_t ppid; - if(!get_process_ppid(pid, &ppid)) - continue; - char ppid_name[PROC_PATH_SIZ] = { 0 }; - if(!get_process_name(ppid, ppid_name)) - continue; - - // Skip if this is an instance running inside a docker container - if(is_in_docker(pid)) - continue; - - log_debug(DEBUG_SHMEM, " └ PPID: %d -> name: %s", ppid, ppid_name); - - char timestr[TIMESTR_SIZE] = { 0 }; - get_process_creation_time(pid, timestr); - - // If this is the first process we log, add a header - if(!already_running) - { - already_running = true; - log_crit("%s is already running!", PROCESS_NAME); - } - - if(last_pid != ppid) - { - // Independent process, may be child of init/systemd - log_info("%s (PID %d) ──> %s (PID %d, started %s)", - ppid_name, ppid, name, pid, timestr); - last_pid = pid; - last_len = snprintf(NULL, 0, "%s (PID %d) ──> ", ppid_name, ppid); - } - else - { - // Process parented by the one we analyzed before, - // highlight their relationship - log_info("%*s └─> %s (PID %d, started %s)", - (int)last_len, "", name, pid, timestr); - } + log_crit("%s is already running (PID %d)!", PROCESS_NAME, pid); + return true; } - log_debug(DEBUG_SHMEM, "Done reading /proc/[0-9]*"); - closedir(dirPos); - return already_running; + // If we did not find another FTL process by looking at the PID file, we assume + // no other FTL process is running. We write our own PID to the file later after + // we have successfully started up (and possibly forked). + return false; } bool getProcessMemory(struct proc_mem *mem, const unsigned long total_memory) From 3414dc1676e595e2e3f11a39f7258f4a75a7c948 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Sun, 9 Feb 2025 19:09:22 +0100 Subject: [PATCH 2/3] Use individual shared memory objects per FTL process so accidentally running duplicates don't interfere with each other. This can be seen as the fallback solution in case the PID file-based duplicate detection did not work due to security restrictions concerning process deetection on the system (see comment in function daemon.c:another_FTL() for further context) Signed-off-by: DL6ER --- src/shmem.c | 49 +++++++++++++++++++++++++++++++------------------ src/shmem.h | 2 +- 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/src/shmem.c b/src/shmem.c index e1569f348..e3b839458 100644 --- a/src/shmem.c +++ b/src/shmem.c @@ -40,21 +40,21 @@ /// The name of the shared memory. Use this when connecting to the shared memory. #define SHMEM_PATH "/dev/shm" -#define SHARED_LOCK_NAME "FTL-lock" -#define SHARED_STRINGS_NAME "FTL-strings" -#define SHARED_COUNTERS_NAME "FTL-counters" -#define SHARED_DOMAINS_NAME "FTL-domains" -#define SHARED_CLIENTS_NAME "FTL-clients" -#define SHARED_QUERIES_NAME "FTL-queries" -#define SHARED_UPSTREAMS_NAME "FTL-upstreams" -#define SHARED_OVERTIME_NAME "FTL-overTime" -#define SHARED_SETTINGS_NAME "FTL-settings" -#define SHARED_DNS_CACHE "FTL-dns-cache" -#define SHARED_PER_CLIENT_REGEX "FTL-per-client-regex" -#define SHARED_CLIENTS_LOOKUP_NAME "FTL-clients-lookup" -#define SHARED_DOMAINS_LOOKUP_NAME "FTL-domains-lookup" -#define SHARED_DNS_CACHE_LOOKUP_NAME "FTL-dns-cache-lookup" -#define SHARED_RECYCLER_NAME "FTL-recycler" +#define SHARED_LOCK_NAME "lock" +#define SHARED_STRINGS_NAME "strings" +#define SHARED_COUNTERS_NAME "counters" +#define SHARED_DOMAINS_NAME "domains" +#define SHARED_CLIENTS_NAME "clients" +#define SHARED_QUERIES_NAME "queries" +#define SHARED_UPSTREAMS_NAME "upstreams" +#define SHARED_OVERTIME_NAME "overTime" +#define SHARED_SETTINGS_NAME "settings" +#define SHARED_DNS_CACHE "dns-cache" +#define SHARED_PER_CLIENT_REGEX "per-client-regex" +#define SHARED_CLIENTS_LOOKUP_NAME "clients-lookup" +#define SHARED_DOMAINS_LOOKUP_NAME "domains-lookup" +#define SHARED_DNS_CACHE_LOOKUP_NAME "dns-cache-lookup" +#define SHARED_RECYCLER_NAME "recycler" // Allocation step for FTL-strings bucket. This is somewhat special as we use // this as a general-purpose storage which should always be large enough. If, @@ -65,7 +65,7 @@ // Global counters struct countersStruct *counters = NULL; -#define SHARED_FIFO_LOG_NAME "/FTL-fifo-log" +#define SHARED_FIFO_LOG_NAME "fifo-log" /// The pointer in shared memory to the shared string buffer static SharedMemory shm_lock = { 0 }; @@ -628,12 +628,22 @@ void destroy_shmem(void) /// Create shared memory /// -/// \param name the name of the shared memory +/// \param suffix the suffix of the shared memory's name /// \param sharedMemory the shared memory object to fill /// \param size the size to allocate /// No return value as the function will exit on failure -static bool create_shm(const char *name, SharedMemory *sharedMemory, const size_t size) +static bool create_shm(const char *suffix, SharedMemory *sharedMemory, const size_t size) { + // Generate an individual shm name for this process by using the PID + const size_t namelen = strlen(suffix) + 24; + char *name = calloc(namelen, sizeof(char)); + if(name == NULL) + { + log_err("create_shm(): Failed to allocate memory for shared memory name"); + exit(EXIT_FAILURE); + } + snprintf(name, namelen, "/FTL-%d-%s", getpid(), suffix); + char df[64] = { 0 }; const unsigned int percentage = get_dev_shm_usage(df); if(config.debug.shmem.v.b || (config.misc.check.shmem.v.ui > 0 && percentage > config.misc.check.shmem.v.ui)) @@ -901,6 +911,9 @@ static void delete_shm(SharedMemory *sharedMemory) if(shm_unlink(sharedMemory->name) != 0) log_warn("delete_shm(): shm_unlink(%s) failed: %s", sharedMemory->name, strerror(errno)); + + // Free the shared memory name + free(sharedMemory->name); } // Euclidean algorithm to return greatest common divisor of the numbers diff --git a/src/shmem.h b/src/shmem.h index 8b2422b7b..f23e84a5c 100644 --- a/src/shmem.h +++ b/src/shmem.h @@ -19,7 +19,7 @@ #include "datastructure.h" typedef struct { - const char *name; + char *name; size_t size; void *ptr; int fd; From d019b04a0bdeb67aec0ae1551fedb62e27d053c2 Mon Sep 17 00:00:00 2001 From: DL6ER Date: Mon, 10 Feb 2025 17:13:32 +0100 Subject: [PATCH 3/3] Use /proc//status instead of a call to kill(, 0) to get the processes's state as the latter may not be allowed if the other process is running as another user and we don't have CAP_KILL (or am root) Signed-off-by: DL6ER --- src/config/toml_writer.c | 3 - src/daemon.c | 46 ++------------- src/daemon.h | 3 +- src/dnsmasq_interface.c | 2 +- src/main.c | 2 +- src/procps.c | 121 ++++++++++++++++++++++++++++++++------- 6 files changed, 110 insertions(+), 67 deletions(-) diff --git a/src/config/toml_writer.c b/src/config/toml_writer.c index 57a2090a3..4eab59847 100644 --- a/src/config/toml_writer.c +++ b/src/config/toml_writer.c @@ -43,10 +43,7 @@ bool writeFTLtoml(const bool verbose) // Try to open a temporary config file for writing FILE *fp; if((fp = openFTLtoml("w", 0)) == NULL) - { - log_warn("Cannot write to FTL config file (%s), content not updated", strerror(errno)); return false; - } // Write header fprintf(fp, "# Pi-hole configuration file (%s)\n", get_FTL_version()); diff --git a/src/daemon.c b/src/daemon.c index 933ba8ae9..e0bce8db2 100644 --- a/src/daemon.c +++ b/src/daemon.c @@ -104,7 +104,7 @@ void go_daemon(void) exit(EXIT_SUCCESS); } - savepid(); + savePID(); // Closing stdin, stdout and stderr is handled by dnsmasq } @@ -119,7 +119,7 @@ void go_daemon(void) * * @return void */ -void savepid(void) +void savePID(void) { // Get PID of the current process const pid_t pid = getpid(); @@ -140,46 +140,14 @@ void savepid(void) } /** - * @brief Reads the process ID (PID) from a file. - * - * This function attempts to open a file specified by the configuration - * and read the PID from it. If the file cannot be opened or the PID - * cannot be parsed, appropriate warnings are logged and the function - * returns -1. - * - * @return pid_t The PID read from the file on success, or -1 on failure. - */ -pid_t readpid(void) -{ - pid_t pid = -1; - FILE *f = NULL; - // Open file for reading - if((f = fopen(config.files.pid.v.s, "r")) == NULL) - { - // Log error - log_warn("Unable to read PID from file: %s", strerror(errno)); - return -1; - } - - // Try to read PID from file if it is not empty - if(fscanf(f, "%d", &pid) != 1) - log_debug(DEBUG_SHMEM, "Unable to parse PID in PID file"); - - // Close file - fclose(f); - - return pid; -} - -/** - * @brief Empties the PID file and remove it + * @brief Empties the PID file * * This function opens the PID file in write mode, which effectively * empties its contents. If the file cannot be opened, a warning is logged. * * @note This function does not remove the PID file, it only empties it. */ -static void removepid(void) +static void removePID(void) { FILE *f = NULL; // Open file for writing to overwrite/empty it @@ -190,9 +158,7 @@ static void removepid(void) } fclose(f); - // Remove PID file - if(unlink(config.files.pid.v.s) != 0) - log_warn("Unable to remove PID file: %s", strerror(errno)); + log_info("PID file emptied"); } /** @@ -439,7 +405,7 @@ void cleanup(const int ret) } // Remove PID file - removepid(); + removePID(); // Free regex filter memory free_regex(); diff --git a/src/daemon.h b/src/daemon.h index 1c304dec4..45f5504d1 100644 --- a/src/daemon.h +++ b/src/daemon.h @@ -14,8 +14,7 @@ extern pthread_t threads[THREADS_MAX]; void go_daemon(void); -void savepid(void); -pid_t readpid(void); +void savePID(void); char *getUserName(void); const char *hostname(void); const char *domainname(void); diff --git a/src/dnsmasq_interface.c b/src/dnsmasq_interface.c index b1fdf3d14..8310e4d98 100644 --- a/src/dnsmasq_interface.c +++ b/src/dnsmasq_interface.c @@ -3175,7 +3175,7 @@ void FTL_fork_and_bind_sockets(struct passwd *ent_pw, bool dnsmasq_start) if(daemonmode) go_daemon(); else - savepid(); + savePID(); // Initialize query database (pihole-FTL.db) db_init(); diff --git a/src/main.c b/src/main.c index f05006e8a..7682aba25 100644 --- a/src/main.c +++ b/src/main.c @@ -93,7 +93,7 @@ int main (int argc, char *argv[]) // Write PID early on so systemd cannot be fooled during DELAY_STARTUP // times. The PID in this file will later be overwritten after forking - savepid(); + savePID(); // Delay startup (if requested) // Do this before reading the database to make this option not only diff --git a/src/procps.c b/src/procps.c index 8a76e6f88..febdc45eb 100644 --- a/src/procps.c +++ b/src/procps.c @@ -17,7 +17,7 @@ #include // config #include "config/config.h" -// readpid() +// readPID() #include "daemon.h" #define PROCESS_NAME "pihole-FTL" @@ -75,41 +75,121 @@ bool get_process_name(const pid_t pid, char name[PROC_PATH_SIZ]) return true; } +/** + * @brief Reads the process ID (PID) from a file. + * + * This function attempts to open a file specified by the configuration + * and read the PID from it. If the file cannot be opened or the PID + * cannot be parsed, appropriate warnings are logged and the function + * returns -1. + * + * @return pid_t The PID read from the file on success, or -1 on failure. + */ +static pid_t readPID(void) +{ + pid_t pid = -1; + FILE *f = NULL; + // Open file for reading + if((f = fopen(config.files.pid.v.s, "r")) == NULL) + { + // Log error + log_warn("Unable to read PID from file: %s", strerror(errno)); + return -1; + } + + // Try to read PID from file if it is not empty + if(fscanf(f, "%d", &pid) != 1) + log_debug(DEBUG_SHMEM, "Unable to parse PID in PID file"); + + // Close file + fclose(f); + + return pid; +} + +/** + * @brief Checks if a process with the given PID is alive. + * + * This function determines if a process is alive by checking the + * /proc//status file. If the file cannot be opened, it is assumed that the + * process is dead. The function reads the status file to check the state of the + * process. If the process is in zombie state, it is considered not running. + * + * @param pid The process ID to check. + * @return true if the process is alive and not a zombie, false otherwise. + */ +static bool process_alive(const pid_t pid) +{ + // Create /proc//status filename + char filename[64] = { 0 }; + snprintf(filename, sizeof(filename), "/proc/%d/status", pid); + + FILE *file = fopen(filename, "r"); + // If we cannot open the file, we assume the process is dead as + // /proc/ does not exist anymore + if(file == NULL) + return false; + + // Parse the entire file + char line[256]; + bool running = true; + while(fgets(line, sizeof(line), file)) + { + // Search for state + if(strncmp(line, "State:", 6) == 0) + { + // Check if process is a zombie + // On Linux operating systems, a zombie process is a + // process that has completed execution (via the exit + // system call) but still has an entry in the process + // table: it is a process in the "Terminated state". + // It typically happens when the parent (calling) + // program properly has not yet fetched the return + // status of the sub-process. + if(strcmp(line, "State:\tZ") == 0) + running = false; + + log_debug(DEBUG_SHMEM, "Process state: \"%s\"", line); + break; + } + } + + // Close file + fclose(file); + + // Process is still alive if the running flag is still true + return running; +} + // This function prints an info message about if another FTL process is already // running. It returns true if another FTL process is already running, false // otherwise. bool another_FTL(void) { + // The PID in the PID file + const pid_t pid = readPID(); + // Our own PID from the current process const pid_t ourselves = getpid(); - bool already_running = false; - pid_t pid = readpid(); if(pid == ourselves) { + // This should not happen, as we store our own PID in the PID + // file only after we have successfully started up (and possibly + // forked). However, if it does happen, we log an info message log_info("PID file contains our own PID"); } else if(pid < 0) { + // If we cannot read the PID file, we assume no other FTL process is + // running. We write our own PID to the file later after we have + // successfully started up (and possibly forked). log_info("PID file does not exist or not readable"); } - else - { - // Note: kill(pid, 0) does not send a signal, but merely checks - // if the process exists. If the process does not exist, kill() - // returns -1 and sets errno to ESRCH. However, if the process - // exists, but security restrictions tell the system to deny its - // existence, we cannot distinguish between the process not - // existing and the process existing but being denied to us. In - // that case, our fallback solution below kicks in and iterates - // over /proc instead. - already_running = kill(pid, 0) == 0; - log_info("PID file contains PID %d (%s), we are %d", - pid, already_running ? "running" : "dead", ourselves); - } - - // If already_running is true, we are done - if(already_running) + else if(process_alive(pid)) { + // If we found another FTL process by looking at the PID file, we + // check if it is still alive. If it is, we log a critical message + // and return true. This will terminate the current process. log_crit("%s is already running (PID %d)!", PROCESS_NAME, pid); return true; } @@ -117,6 +197,7 @@ bool another_FTL(void) // If we did not find another FTL process by looking at the PID file, we assume // no other FTL process is running. We write our own PID to the file later after // we have successfully started up (and possibly forked). + log_info("No other running FTL process found."); return false; }