Skip to content

Commit

Permalink
Do not try to delete existing shmem objects on start - that may cause…
Browse files Browse the repository at this point in the history
… running FTL instances to crash when it tries to access them. Instead, new instances should properly fail to start.

Signed-off-by: DL6ER <[email protected]>
  • Loading branch information
DL6ER committed Feb 5, 2021
1 parent 29a4bff commit 49ba60e
Show file tree
Hide file tree
Showing 8 changed files with 177 additions and 30 deletions.
2 changes: 2 additions & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,8 @@ set(sources
main.h
overTime.c
overTime.h
procps.c
procps.h
regex.c
regex_r.h
resolve.c
Expand Down
2 changes: 1 addition & 1 deletion src/gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ void *GC_thread(void *val)
{
timer_start(GC_TIMER);
char timestring[84] = "";
get_timestr(timestring, mintime);
get_timestr(timestring, mintime, false);
logg("GC starting, mintime: %s (%llu)", timestring, (long long)mintime);
}

Expand Down
25 changes: 17 additions & 8 deletions src/log.c
Original file line number Diff line number Diff line change
Expand Up @@ -79,18 +79,27 @@ void open_FTL_log(const bool init)

// The size of 84 bytes has been carefully selected for all possible timestamps
// to always fit into the available space without buffer overflows
void get_timestr(char * const timestring, const time_t timein)
void get_timestr(char * const timestring, const time_t timein, const bool millis)
{
struct tm tm;
localtime_r(&timein, &tm);

struct timeval tv;
gettimeofday(&tv, NULL);
const int millisec = tv.tv_usec/1000;
if(millis)
{
struct timeval tv;
gettimeofday(&tv, NULL);
const int millisec = tv.tv_usec/1000;

sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d.%03i",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, millisec);
sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d.%03i",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec, millisec);
}
else
{
sprintf(timestring,"%d-%02d-%02d %02d:%02d:%02d",
tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
tm.tm_hour, tm.tm_min, tm.tm_sec);
}
}

void _FTL_log(const bool newline, const char *format, ...)
Expand All @@ -104,7 +113,7 @@ void _FTL_log(const bool newline, const char *format, ...)

pthread_mutex_lock(&lock);

get_timestr(timestring, time(NULL));
get_timestr(timestring, time(NULL), true);

// Get and log PID of current process to avoid ambiguities when more than one
// pihole-FTL instance is logging into the same file
Expand Down
2 changes: 1 addition & 1 deletion src/log.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ void format_memory_size(char * const prefix, unsigned long long int bytes,
void format_time(char buffer[42], unsigned long seconds, double milliseconds);
const char *get_FTL_version(void) __attribute__ ((malloc));
void log_FTL_version(bool crashreport);
void get_timestr(char * const timestring, const time_t timein);
void get_timestr(char * const timestring, const time_t timein, const bool millis);
const char *get_ordinal_suffix(unsigned int number) __attribute__ ((const));

// The actual logging routine can take extra options for specialized logging
Expand Down
2 changes: 2 additions & 0 deletions src/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
#include "capabilities.h"
#include "database/gravity-db.h"
#include "timers.h"
#include "procps.h"

char * username;
bool needGC = false;
Expand Down Expand Up @@ -59,6 +60,7 @@ int main (int argc, char* argv[])
if(!init_shmem(true))
{
logg("Initialization of shared memory failed.");
check_running_FTL();
return EXIT_FAILURE;
}

Expand Down
133 changes: 133 additions & 0 deletions src/procps.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
/* Pi-hole: A black hole for Internet advertisements
* (c) 2021 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* FTL Engine
* /proc system subroutines
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */

#include "FTL.h"
#include "procps.h"
#include "log.h"
#include <dirent.h>
// getpid()
#include <unistd.h>

#define PROCESS_NAME "pihole-FTL"

static bool get_process_name(const pid_t pid, char name[128])
{
if(pid == 0)
{
strcpy(name, "init");
return true;
}

// 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);
FILE *f = fopen(filename, "r");
if(f == NULL)
return false;

// Read name from opened file
if(fscanf(f, "%128s", name) != 1)
false;
fclose(f);

return true;
}


static bool get_process_ppid(const pid_t pid, pid_t *ppid)
{
// Try to open status file
char filename[sizeof("/proc/%u/task/%u/comm") + 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;
}

static bool get_process_creation_time(const pid_t pid, char timestr[84])
{
// 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);

return true;
}

void check_running_FTL(void)
{
//pid_t pid;
DIR *dirPos;
struct dirent *entry;

// Open /proc
errno = 0;
if ((dirPos = opendir("/proc")) == NULL)
{
logg("Dailed to access /proc: %s", strerror(errno));
return;
}

// Loop over entries in /proc
// This is much more efficient than iterating over all possible PIDs
while ((entry = readdir(dirPos)) != NULL)
{
// 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
const pid_t pid = strtol(entry->d_name, NULL, 10);

// Skip our own process
if(pid == getpid())
continue;

// Get process name
char name[128] = { 0 };
if(!get_process_name(pid, name))
continue;

// Get parent process ID (PPID)
pid_t ppid;
if(!get_process_ppid(pid, &ppid))
continue;
char ppid_name[128] = { 0 };
if(!get_process_name(ppid, ppid_name))
continue;

char timestr[84] = { 0 };
get_process_creation_time(pid, timestr);

// Log this process if it is a duplicate of us
if(strcasecmp(name, PROCESS_NAME) == 0)
logg("---> %s is already running as PID %d (started %s, child of PID %i (%s))",
PROCESS_NAME, pid, timestr, ppid, ppid_name);
}

closedir(dirPos);
}
15 changes: 15 additions & 0 deletions src/procps.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* Pi-hole: A black hole for Internet advertisements
* (c) 2021 Pi-hole, LLC (https://pi-hole.net)
* Network-wide ad blocking via your own hardware.
*
* FTL Engine
* /proc system prototypes
*
* This file is copyright under the latest version of the EUPL.
* Please see LICENSE file for your rights under this license. */

#ifndef PROCPS_H
#define PROCPS_H
void check_running_FTL(void);

#endif // POCPS_H
26 changes: 6 additions & 20 deletions src/shmem.c
Original file line number Diff line number Diff line change
Expand Up @@ -548,28 +548,14 @@ SharedMemory create_shm(const char *name, const size_t size, bool create_new)
};

// O_RDWR: Open the object for read-write access (we need to be able to modify the locks)
int shm_oflags = O_RDWR;
if(create_new)
{
// Try unlinking the shared memory object before creating a new one.
// If the object is still existing, e.g., due to a past unclean exit
// of FTL, shm_open() would fail with error "File exists"
int ret = shm_unlink(name);
// Check return code. shm_unlink() returns -1 on error and sets errno
// We specifically ignore ENOENT (No such file or directory) as this is not an
// error in our use case (we only want the file to be deleted when existing)
if(ret != 0 && errno != ENOENT)
logg("create_shm(): shm_unlink(\"%s\") failed: %s (%i)", name, strerror(errno), errno);

// Replace shm_oflags
// O_CREAT: Create the shared memory object if it does not exist.
// O_EXCL: Return an error if a shared memory object with the given name already exists.
// O_TRUNC: If the shared memory object already exists, truncate it to zero bytes.
shm_oflags |= O_CREAT | O_EXCL | O_TRUNC;
}
// When creating a new shared memory object, we add to this
// - O_CREAT: Create the shared memory object if it does not exist.
// - O_EXCL: Return an error if a shared memory object with the given name already exists.
const int shm_oflags = create_new ? O_RDWR | O_CREAT | O_EXCL : O_RDWR;

// Create the shared memory file in read/write mode with 600 permissions
int fd = shm_open(sharedMemory.name, shm_oflags, S_IRUSR | S_IWUSR);
errno = 0;
const int fd = shm_open(sharedMemory.name, shm_oflags, S_IRUSR | S_IWUSR);

// Check for `shm_open` error
if(fd == -1)
Expand Down

0 comments on commit 49ba60e

Please sign in to comment.