mirror of
https://github.com/wolfcw/libfaketime.git
synced 2026-05-17 00:26:16 +03:00
Merge pull request #530 from drolevar/fix_master
Fix several multi-arch-related issues
This commit is contained in:
15
src/Makefile
15
src/Makefile
@@ -168,17 +168,20 @@ all: ${LIBS} ${BINS}
|
||||
|
||||
libfaketimeMT.o: EXTRA_FLAGS := -DPTHREAD_SINGLETHREADED_TIME
|
||||
|
||||
${LIBS_OBJ}: libfaketime.c
|
||||
ft_sem.o: ft_sem.c ft_sem.h
|
||||
${CC} -o $@ -c ${CFLAGS} ${CPPFLAGS} $<
|
||||
|
||||
${LIBS_OBJ}: libfaketime.c ft_sem.h
|
||||
${CC} -o $@ -c ${CFLAGS} ${CPPFLAGS} ${EXTRA_FLAGS} $<
|
||||
|
||||
%.so.${SONAME}: %.o libfaketime.map
|
||||
${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ${LDADD}
|
||||
%.so.${SONAME}: %.o ft_sem.o libfaketime.map
|
||||
${CC} -o $@ -Wl,-soname,$@ ${LDFLAGS} ${LIB_LDFLAGS} $< ft_sem.o ${LDADD}
|
||||
|
||||
${BINS}: faketime.c
|
||||
${CC} -o $@ ${CFLAGS} ${CPPFLAGS} ${EXTRA_FLAGS} $< ${LDFLAGS} ${BIN_LDFLAGS}
|
||||
${BINS}: faketime.c ft_sem.o ft_sem.h
|
||||
${CC} -o $@ ${CFLAGS} ${CPPFLAGS} ${EXTRA_FLAGS} $< ft_sem.o ${LDFLAGS} ${BIN_LDFLAGS}
|
||||
|
||||
clean:
|
||||
@rm -f ${LIBS_OBJ} ${LIBS} ${BINS}
|
||||
@rm -f ${LIBS_OBJ} ${LIBS} ${BINS} ft_sem.o
|
||||
|
||||
distclean: clean
|
||||
@echo
|
||||
|
||||
@@ -44,7 +44,7 @@
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mman.h>
|
||||
#include <semaphore.h>
|
||||
#include "ft_sem.h"
|
||||
|
||||
#include "faketime_common.h"
|
||||
|
||||
@@ -60,6 +60,7 @@ static const char *date_cmd = "date";
|
||||
|
||||
/* semaphore and shared memory names */
|
||||
char sem_name[PATH_BUFSIZE] = {0}, shm_name[PATH_BUFSIZE] = {0};
|
||||
static ft_sem_t wrapper_sem;
|
||||
|
||||
void usage(const char *name)
|
||||
{
|
||||
@@ -98,9 +99,9 @@ void usage(const char *name)
|
||||
/** Clean up shared objects */
|
||||
static void cleanup_shobjs()
|
||||
{
|
||||
if (-1 == sem_unlink(sem_name))
|
||||
if (-1 == ft_sem_unlink(&wrapper_sem))
|
||||
{
|
||||
perror("faketime: sem_unlink");
|
||||
perror("faketime: ft_sem_unlink");
|
||||
}
|
||||
if (-1 == shm_unlink(shm_name))
|
||||
{
|
||||
@@ -255,9 +256,8 @@ int main (int argc, char **argv)
|
||||
curr_opt++;
|
||||
|
||||
{
|
||||
/* create semaphores and shared memory */
|
||||
/* create lock and shared memory */
|
||||
int shm_fd;
|
||||
sem_t *sem;
|
||||
struct ft_shared_s *ft_shared;
|
||||
char shared_objs[PATH_BUFSIZE * 2 + 1];
|
||||
|
||||
@@ -271,10 +271,10 @@ int main (int argc, char **argv)
|
||||
snprintf(sem_name, PATH_BUFSIZE -1 ,"/faketime_sem_%ld", (long)getpid());
|
||||
snprintf(shm_name, PATH_BUFSIZE -1 ,"/faketime_shm_%ld", (long)getpid());
|
||||
|
||||
if (SEM_FAILED == (sem = sem_open(sem_name, O_CREAT|O_EXCL, S_IWUSR|S_IRUSR, 1)))
|
||||
if (-1 == ft_sem_create(sem_name, &wrapper_sem))
|
||||
{
|
||||
perror("faketime: sem_open");
|
||||
fprintf(stderr, "The faketime wrapper only works on platforms that support the sem_open()\nsystem call. However, you may LD_PRELOAD libfaketime without using this wrapper.\n");
|
||||
perror("faketime: ft_sem_create");
|
||||
fprintf(stderr, "The faketime wrapper failed to create its lock.\nHowever, you may LD_PRELOAD libfaketime without using this wrapper.\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@@ -282,15 +282,12 @@ int main (int argc, char **argv)
|
||||
if (-1 == (shm_fd = shm_open(shm_name, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR)))
|
||||
{
|
||||
perror("faketime: shm_open");
|
||||
if (-1 == sem_unlink(argv[2]))
|
||||
{
|
||||
perror("faketime: sem_unlink");
|
||||
}
|
||||
ft_sem_unlink(&wrapper_sem);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
/* set shm size */
|
||||
if (-1 == ftruncate(shm_fd, sizeof(uint64_t)))
|
||||
if (-1 == ftruncate(shm_fd, sizeof(struct ft_shared_s)))
|
||||
{
|
||||
perror("faketime: ftruncate");
|
||||
cleanup_shobjs();
|
||||
@@ -306,9 +303,9 @@ int main (int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sem_wait(sem) == -1)
|
||||
if (ft_sem_lock(&wrapper_sem) == -1)
|
||||
{
|
||||
perror("faketime: sem_wait");
|
||||
perror("faketime: ft_sem_lock");
|
||||
cleanup_shobjs();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
@@ -316,12 +313,16 @@ int main (int argc, char **argv)
|
||||
/* init elapsed time ticks to zero */
|
||||
ft_shared->ticks = 0;
|
||||
ft_shared->file_idx = 0;
|
||||
ft_shared->start_time.real.tv_sec = 0;
|
||||
ft_shared->start_time.real.tv_nsec = -1;
|
||||
ft_shared->start_time.mon.tv_sec = 0;
|
||||
ft_shared->start_time.mon.tv_nsec = -1;
|
||||
ft_shared->start_time.mon_raw.tv_sec = 0;
|
||||
ft_shared->start_time.mon_raw.tv_nsec = -1;
|
||||
ft_shared->start_time_real.sec = 0;
|
||||
ft_shared->start_time_real.nsec = -1;
|
||||
ft_shared->start_time_mon.sec = 0;
|
||||
ft_shared->start_time_mon.nsec = -1;
|
||||
ft_shared->start_time_mon_raw.sec = 0;
|
||||
ft_shared->start_time_mon_raw.nsec = -1;
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
ft_shared->start_time_boot.sec = 0;
|
||||
ft_shared->start_time_boot.nsec = -1;
|
||||
#endif
|
||||
|
||||
if (-1 == munmap(ft_shared, (sizeof(struct ft_shared_s))))
|
||||
{
|
||||
@@ -330,16 +331,16 @@ int main (int argc, char **argv)
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sem_post(sem) == -1)
|
||||
if (ft_sem_unlock(&wrapper_sem) == -1)
|
||||
{
|
||||
perror("faketime: semop");
|
||||
perror("faketime: ft_sem_unlock");
|
||||
cleanup_shobjs();
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
snprintf(shared_objs, sizeof(shared_objs), "%s %s", sem_name, shm_name);
|
||||
setenv("FAKETIME_SHARED", shared_objs, true);
|
||||
sem_close(sem);
|
||||
ft_sem_close(&wrapper_sem);
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -38,6 +38,13 @@ struct system_time_s
|
||||
#endif
|
||||
};
|
||||
|
||||
/* Fixed-width time representation for shared memory (arch-independent) */
|
||||
struct ft_shared_time_s
|
||||
{
|
||||
int64_t sec;
|
||||
int64_t nsec;
|
||||
};
|
||||
|
||||
/* Data shared among faketime-spawned processes */
|
||||
struct ft_shared_s
|
||||
{
|
||||
@@ -47,8 +54,13 @@ struct ft_shared_s
|
||||
uint64_t ticks;
|
||||
/* Index of timestamp to be loaded from file */
|
||||
uint64_t file_idx;
|
||||
/* System time Faketime started at */
|
||||
struct system_time_s start_time;
|
||||
/* System time Faketime started at (fixed-width for cross-arch safety) */
|
||||
struct ft_shared_time_s start_time_real;
|
||||
struct ft_shared_time_s start_time_mon;
|
||||
struct ft_shared_time_s start_time_mon_raw;
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
struct ft_shared_time_s start_time_boot;
|
||||
#endif
|
||||
};
|
||||
|
||||
/* These are all needed in order to properly build on OSX */
|
||||
|
||||
220
src/ft_sem.c
Normal file
220
src/ft_sem.c
Normal file
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* This file is part of libfaketime, version 0.9.12
|
||||
*
|
||||
* libfaketime is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License v2 as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* libfaketime is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License v2 along
|
||||
* with the libfaketime; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
#include "ft_sem.h"
|
||||
|
||||
#if FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
#include <sys/sem.h>
|
||||
#endif
|
||||
|
||||
#if FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
#include <sys/file.h>
|
||||
#endif
|
||||
|
||||
/*
|
||||
* =======================================================================
|
||||
* Semaphore related functions === SEM
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#if FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
int ft_sem_name2key(char *name)
|
||||
{
|
||||
key_t key;
|
||||
char fullname[256];
|
||||
snprintf(fullname, sizeof(fullname), "/tmp%s", name);
|
||||
fullname[sizeof(fullname) - 1] = '\0';
|
||||
int fd = open(fullname, O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("libfaketime: open");
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
if (-1 == (key = ftok(fullname, 'F')))
|
||||
{
|
||||
perror("libfaketime: ftok");
|
||||
return -1;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
static int ft_sem_name_to_path(const char *name, char *path, size_t pathlen)
|
||||
{
|
||||
const char *prefix = "/faketime_sem_";
|
||||
const char *p = strstr(name, prefix);
|
||||
if (p == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
const char *pid_str = p + strlen(prefix);
|
||||
snprintf(path, pathlen, "/dev/shm/faketime_lock_%s", pid_str);
|
||||
path[pathlen - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ft_sem_create(char *name, ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
if (SEM_FAILED == (ft_sem->sem = sem_open(name, O_CREAT|O_EXCL, S_IWUSR|S_IRUSR, 1)))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
key_t key = ft_sem_name2key(name);
|
||||
int nsems = 1;
|
||||
|
||||
ft_sem->semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | S_IWUSR | S_IRUSR);
|
||||
if (ft_sem->semid >= 0) { /* we got here first */
|
||||
struct sembuf sb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = 1, /* number of resources the semaphore has (when decremented down to 0 the semaphore will block) */
|
||||
.sem_flg = 0,
|
||||
};
|
||||
/* the number of semaphore operation structures (struct sembuf) passed to semop */
|
||||
int nsops = 1;
|
||||
|
||||
/* do a semop() to "unlock" the semaphore */
|
||||
if (-1 == semop(ft_sem->semid, &sb, nsops)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (errno == EEXIST) { /* someone else got here before us */
|
||||
return -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
char path[256];
|
||||
if (ft_sem_name_to_path(name, path, sizeof(path)) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
ft_sem->fd = open(path, O_CREAT|O_EXCL|O_RDWR, S_IWUSR|S_IRUSR);
|
||||
if (ft_sem->fd < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
strncpy(ft_sem->name, name, sizeof ft_sem->name - 1);
|
||||
ft_sem->name[sizeof ft_sem->name - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_sem_open(char *name, ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
if (SEM_FAILED == (ft_sem->sem = sem_open(name, 0)))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
key_t key = ft_sem_name2key(name);
|
||||
ft_sem->semid = semget(key, 1, S_IWUSR | S_IRUSR);
|
||||
if (ft_sem->semid < 0) {
|
||||
return -1;
|
||||
}
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
char path[256];
|
||||
if (ft_sem_name_to_path(name, path, sizeof(path)) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
ft_sem->fd = open(path, O_RDWR);
|
||||
if (ft_sem->fd < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
strncpy(ft_sem->name, name, sizeof ft_sem->name - 1);
|
||||
ft_sem->name[sizeof ft_sem->name - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_sem_lock(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_wait(ft_sem->sem);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
struct sembuf sb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = -1, /* allocate resource (lock) */
|
||||
.sem_flg = 0,
|
||||
};
|
||||
return semop(ft_sem->semid, &sb, 1);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
return flock(ft_sem->fd, LOCK_EX);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ft_sem_unlock(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_post(ft_sem->sem);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
struct sembuf sb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = 1, /* free resource (unlock) */
|
||||
.sem_flg = 0,
|
||||
};
|
||||
return semop(ft_sem->semid, &sb, 1);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
return flock(ft_sem->fd, LOCK_UN);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ft_sem_close(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_close(ft_sem->sem);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
/* NOP -- there's no "close" equivalent */
|
||||
(void)ft_sem;
|
||||
return 0;
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
int ret = close(ft_sem->fd);
|
||||
ft_sem->fd = -1;
|
||||
return ret;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ft_sem_unlink(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_unlink(ft_sem->name);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
return semctl(ft_sem->semid, 0, IPC_RMID);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
char path[256];
|
||||
if (ft_sem_name_to_path(ft_sem->name, path, sizeof(path)) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return unlink(path);
|
||||
#endif
|
||||
}
|
||||
62
src/ft_sem.h
Normal file
62
src/ft_sem.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* This file is part of libfaketime, version 0.9.12
|
||||
*
|
||||
* libfaketime is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License v2 as published by the
|
||||
* Free Software Foundation.
|
||||
*
|
||||
* libfaketime is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License v2 along
|
||||
* with the libfaketime; if not, write to the Free Software Foundation,
|
||||
* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef FT_SEM_H
|
||||
#define FT_SEM_H
|
||||
|
||||
/* semaphore backend options */
|
||||
#define FT_POSIX 1
|
||||
#define FT_SYSV 2
|
||||
#define FT_FLOCK 3
|
||||
|
||||
/* set default backend */
|
||||
#ifndef FT_SEMAPHORE_BACKEND
|
||||
#define FT_SEMAPHORE_BACKEND FT_FLOCK
|
||||
#endif
|
||||
|
||||
/* validate selected backend */
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
#else
|
||||
#error "Unknown FT_SEMAPHORE_BACKEND; select between FT_POSIX, FT_SYSV, and FT_FLOCK"
|
||||
#endif
|
||||
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
#include <semaphore.h>
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char name[256];
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
sem_t *sem;
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
int semid;
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_FLOCK
|
||||
int fd;
|
||||
#endif
|
||||
} ft_sem_t;
|
||||
|
||||
int ft_sem_create(char *name, ft_sem_t *ft_sem);
|
||||
int ft_sem_open(char *name, ft_sem_t *ft_sem);
|
||||
int ft_sem_lock(ft_sem_t *ft_sem);
|
||||
int ft_sem_unlock(ft_sem_t *ft_sem);
|
||||
int ft_sem_close(ft_sem_t *ft_sem);
|
||||
int ft_sem_unlink(ft_sem_t *ft_sem);
|
||||
|
||||
#endif /* FT_SEM_H */
|
||||
@@ -51,7 +51,6 @@
|
||||
#include <string.h>
|
||||
#include <semaphore.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/sem.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
@@ -75,6 +74,7 @@
|
||||
|
||||
#include "time_ops.h"
|
||||
#include "faketime_common.h"
|
||||
#include "ft_sem.h"
|
||||
|
||||
#if defined PTHREAD_SINGLETHREADED_TIME && defined FAKE_STATELESS
|
||||
#undef PTHREAD_SINGLETHREADED_TIME
|
||||
@@ -165,20 +165,6 @@ struct utimbuf {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* semaphore backend options */
|
||||
#define FT_POSIX 1
|
||||
#define FT_SYSV 2
|
||||
/* set default backend */
|
||||
#ifndef FT_SEMAPHORE_BACKEND
|
||||
#define FT_SEMAPHORE_BACKEND FT_POSIX
|
||||
#endif
|
||||
/* validate selected backend */
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
#else
|
||||
#error "Unknown FT_SEMAPHORE_BACKEND; select between FT_POSIX and FT_SYSV"
|
||||
#endif
|
||||
|
||||
#ifdef FAKE_RANDOM
|
||||
#include <sys/random.h>
|
||||
#endif
|
||||
@@ -352,15 +338,6 @@ bool str_array_contains(const char *haystack, const char *needle);
|
||||
void *ft_dlvsym(void *handle, const char *symbol, const char *version, const char *full_name, char *ignore_list, bool should_debug_dlsym);
|
||||
|
||||
|
||||
typedef struct {
|
||||
char name[256];
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
sem_t *sem;
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
int semid;
|
||||
#endif
|
||||
} ft_sem_t;
|
||||
|
||||
/** Semaphore protecting shared data */
|
||||
static ft_sem_t shared_sem;
|
||||
static bool shared_sem_initialized = false;
|
||||
@@ -450,144 +427,42 @@ static bool parse_config_file = true;
|
||||
static void ft_cleanup (void) __attribute__ ((destructor));
|
||||
static void ftpl_init (void) __attribute__ ((constructor));
|
||||
|
||||
/*
|
||||
* =======================================================================
|
||||
* Semaphore related functions === SEM
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
#if FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
int ft_sem_name2key(char *name)
|
||||
{
|
||||
key_t key;
|
||||
char fullname[256];
|
||||
snprintf(fullname, sizeof(fullname), "/tmp%s", name);
|
||||
fullname[sizeof(fullname) - 1] = '\0';
|
||||
int fd = open(fullname, O_CREAT, S_IRUSR | S_IWUSR);
|
||||
if (fd < 0)
|
||||
{
|
||||
perror("libfaketime: open");
|
||||
return -1;
|
||||
}
|
||||
close(fd);
|
||||
if (-1 == (key = ftok(fullname, 'F')))
|
||||
{
|
||||
perror("libfaketime: ftok");
|
||||
return -1;
|
||||
}
|
||||
return key;
|
||||
}
|
||||
#endif
|
||||
|
||||
int ft_sem_create(char *name, ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
if (SEM_FAILED == (ft_sem->sem = sem_open(name, O_CREAT|O_EXCL, S_IWUSR|S_IRUSR, 1)))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
key_t key = ft_sem_name2key(name);
|
||||
int nsems = 1;
|
||||
|
||||
ft_sem->semid = semget(key, nsems, IPC_CREAT | IPC_EXCL | S_IWUSR | S_IRUSR);
|
||||
if (ft_sem->semid >= 0) { /* we got here first */
|
||||
struct sembuf sb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = 1, /* number of resources the semaphore has (when decremented down to 0 the semaphore will block) */
|
||||
.sem_flg = 0,
|
||||
};
|
||||
/* the number of semaphore operation structures (struct sembuf) passed to semop */
|
||||
int nsops = 1;
|
||||
|
||||
/* do a semop() to "unlock" the semaphore */
|
||||
if (-1 == semop(ft_sem->semid, &sb, nsops)) {
|
||||
return -1;
|
||||
}
|
||||
} else if (errno == EEXIST) { /* someone else got here before us */
|
||||
return -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
strncpy(ft_sem->name, name, sizeof ft_sem->name - 1);
|
||||
ft_sem->name[sizeof ft_sem->name - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_sem_open(char *name, ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
if (SEM_FAILED == (ft_sem->sem = sem_open(name, 0)))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
key_t key = ft_sem_name2key(name);
|
||||
ft_sem->semid = semget(key, 1, S_IWUSR | S_IRUSR);
|
||||
if (ft_sem->semid < 0) {
|
||||
return -1;
|
||||
}
|
||||
#endif
|
||||
strncpy(ft_sem->name, name, sizeof ft_sem->name - 1);
|
||||
ft_sem->name[sizeof ft_sem->name - 1] = '\0';
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ft_sem_lock(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_wait(ft_sem->sem);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
struct sembuf sb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = -1, /* allocate resource (lock) */
|
||||
.sem_flg = 0,
|
||||
};
|
||||
return semop(ft_sem->semid, &sb, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ft_sem_unlock(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_post(ft_sem->sem);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
struct sembuf sb = {
|
||||
.sem_num = 0,
|
||||
.sem_op = 1, /* free resource (unlock) */
|
||||
.sem_flg = 0,
|
||||
};
|
||||
return semop(ft_sem->semid, &sb, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
int ft_sem_close(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_close(ft_sem->sem);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
/* NOP -- there's no "close" equivalent */
|
||||
(void)ft_sem;
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
int ft_sem_unlink(ft_sem_t *ft_sem)
|
||||
{
|
||||
#if FT_SEMAPHORE_BACKEND == FT_POSIX
|
||||
return sem_unlink(ft_sem->name);
|
||||
#elif FT_SEMAPHORE_BACKEND == FT_SYSV
|
||||
return semctl(ft_sem->semid, 0, IPC_RMID);
|
||||
#endif
|
||||
}
|
||||
|
||||
/*
|
||||
* =======================================================================
|
||||
* Shared memory related functions === SHM
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
static void system_time_to_shared(const struct system_time_s *src,
|
||||
struct ft_shared_s *dst)
|
||||
{
|
||||
dst->start_time_real.sec = (int64_t)src->real.tv_sec;
|
||||
dst->start_time_real.nsec = (int64_t)src->real.tv_nsec;
|
||||
dst->start_time_mon.sec = (int64_t)src->mon.tv_sec;
|
||||
dst->start_time_mon.nsec = (int64_t)src->mon.tv_nsec;
|
||||
dst->start_time_mon_raw.sec = (int64_t)src->mon_raw.tv_sec;
|
||||
dst->start_time_mon_raw.nsec = (int64_t)src->mon_raw.tv_nsec;
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
dst->start_time_boot.sec = (int64_t)src->boot.tv_sec;
|
||||
dst->start_time_boot.nsec = (int64_t)src->boot.tv_nsec;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void shared_to_system_time(const struct ft_shared_s *src,
|
||||
struct system_time_s *dst)
|
||||
{
|
||||
dst->real.tv_sec = (time_t)src->start_time_real.sec;
|
||||
dst->real.tv_nsec = (long)src->start_time_real.nsec;
|
||||
dst->mon.tv_sec = (time_t)src->start_time_mon.sec;
|
||||
dst->mon.tv_nsec = (long)src->start_time_mon.nsec;
|
||||
dst->mon_raw.tv_sec = (time_t)src->start_time_mon_raw.sec;
|
||||
dst->mon_raw.tv_nsec = (long)src->start_time_mon_raw.nsec;
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
dst->boot.tv_sec = (time_t)src->start_time_boot.sec;
|
||||
dst->boot.tv_nsec = (long)src->start_time_boot.nsec;
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool shmCreator = false;
|
||||
|
||||
static void ft_shm_create(void) {
|
||||
@@ -617,7 +492,7 @@ static void ft_shm_create(void) {
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
/* set shm size */
|
||||
if (-1 == ftruncate(shm_fdN, sizeof(uint64_t)))
|
||||
if (-1 == ftruncate(shm_fdN, sizeof(struct ft_shared_s)))
|
||||
{
|
||||
perror("libfaketime: In ft_shm_create(), ftruncate failed");
|
||||
exit(EXIT_FAILURE);
|
||||
@@ -637,12 +512,16 @@ static void ft_shm_create(void) {
|
||||
/* init elapsed time ticks to zero */
|
||||
ft_sharedN->ticks = 0;
|
||||
ft_sharedN->file_idx = 0;
|
||||
ft_sharedN->start_time.real.tv_sec = 0;
|
||||
ft_sharedN->start_time.real.tv_nsec = -1;
|
||||
ft_sharedN->start_time.mon.tv_sec = 0;
|
||||
ft_sharedN->start_time.mon.tv_nsec = -1;
|
||||
ft_sharedN->start_time.mon_raw.tv_sec = 0;
|
||||
ft_sharedN->start_time.mon_raw.tv_nsec = -1;
|
||||
ft_sharedN->start_time_real.sec = 0;
|
||||
ft_sharedN->start_time_real.nsec = -1;
|
||||
ft_sharedN->start_time_mon.sec = 0;
|
||||
ft_sharedN->start_time_mon.nsec = -1;
|
||||
ft_sharedN->start_time_mon_raw.sec = 0;
|
||||
ft_sharedN->start_time_mon_raw.nsec = -1;
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
ft_sharedN->start_time_boot.sec = 0;
|
||||
ft_sharedN->start_time_boot.nsec = -1;
|
||||
#endif
|
||||
|
||||
if (-1 == munmap(ft_sharedN, (sizeof(struct ft_shared_s))))
|
||||
{
|
||||
@@ -864,7 +743,7 @@ static void ft_cleanup (void)
|
||||
/* detach from shared memory */
|
||||
if (ft_shared != NULL)
|
||||
{
|
||||
munmap(ft_shared, sizeof(uint64_t));
|
||||
munmap(ft_shared, sizeof(struct ft_shared_s));
|
||||
}
|
||||
if (stss != NULL)
|
||||
{
|
||||
@@ -989,7 +868,7 @@ static void reset_time()
|
||||
perror("libfaketime: In reset_time(), ft_sem_lock failed");
|
||||
exit(1);
|
||||
}
|
||||
ft_shared->start_time = ftpl_starttime;
|
||||
system_time_to_shared(&ftpl_starttime, ft_shared);
|
||||
if (ft_sem_unlock(&shared_sem) == -1)
|
||||
{
|
||||
perror("libfaketime: In reset_time(), ft_sem_unlock failed");
|
||||
@@ -1087,11 +966,11 @@ static bool load_time(struct timespec *tp)
|
||||
/* we set shared memory to stop using infile */
|
||||
ft_shared->ticks = 1;
|
||||
system_time_from_system(&ftpl_starttime);
|
||||
ft_shared->start_time = ftpl_starttime;
|
||||
system_time_to_shared(&ftpl_starttime, ft_shared);
|
||||
}
|
||||
else
|
||||
{
|
||||
ftpl_starttime = ft_shared->start_time;
|
||||
shared_to_system_time(ft_shared, &ftpl_starttime);
|
||||
}
|
||||
|
||||
munmap(stss, infile_size);
|
||||
@@ -3269,16 +3148,16 @@ static void ftpl_really_init(void)
|
||||
perror("libfaketime: In ftpl_init(), ft_sem_lock failed");
|
||||
exit(1);
|
||||
}
|
||||
if (ft_shared->start_time.real.tv_nsec == -1)
|
||||
if (ft_shared->start_time_real.nsec == -1)
|
||||
{
|
||||
/* set up global start time */
|
||||
system_time_from_system(&ftpl_starttime);
|
||||
ft_shared->start_time = ftpl_starttime;
|
||||
system_time_to_shared(&ftpl_starttime, ft_shared);
|
||||
}
|
||||
else
|
||||
{
|
||||
/** get preset start time */
|
||||
ftpl_starttime = ft_shared->start_time;
|
||||
shared_to_system_time(ft_shared, &ftpl_starttime);
|
||||
}
|
||||
if (ft_sem_unlock(&shared_sem) == -1)
|
||||
{
|
||||
|
||||
@@ -9,7 +9,7 @@ OBJ = ${SRC:.c=.o}
|
||||
TEST_SNIPPETS = $(notdir $(basename $(wildcard snippets/*.c)))
|
||||
EXPECTATIONS = $(notdir $(basename $(wildcard snippets/*.variable)))
|
||||
|
||||
ALL_TESTS = timetest test
|
||||
ALL_TESTS = timetest test shm_layout_test
|
||||
|
||||
ifneq ($(filter -DINTERCEPT_SYSCALL,${CFLAGS}),)
|
||||
ALL_TESTS += confirm_variadic_promotion
|
||||
@@ -26,6 +26,9 @@ all: $(ALL_TESTS)
|
||||
timetest: ${OBJ}
|
||||
${CC} -o $@ ${OBJ} ${LDFLAGS}
|
||||
|
||||
shm_layout_test: shm_layout_test.c ../src/faketime_common.h
|
||||
${CC} -o $@ ${CFLAGS} $<
|
||||
|
||||
test: timetest functest libmallocintercept.so
|
||||
@echo
|
||||
@./test.sh
|
||||
@@ -76,7 +79,7 @@ use_lib_%: _use_lib_test.c snippets/%.c lib%.so
|
||||
## cleanup and metainformation
|
||||
|
||||
clean:
|
||||
@rm -f ${OBJ} timetest getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o repeat_random libmallocintercept.so
|
||||
@rm -f ${OBJ} timetest shm_layout_test getrandom_test syscall_test $(foreach f,${TEST_SNIPPETS},use_lib_${f} lib${f}.so run_${f}) variadic_promotion variadic/*.o repeat_random libmallocintercept.so
|
||||
|
||||
distclean: clean
|
||||
@echo
|
||||
|
||||
31
test/functests/test_shm_across_processes.sh
Normal file
31
test/functests/test_shm_across_processes.sh
Normal file
@@ -0,0 +1,31 @@
|
||||
# Verify that shared memory works end-to-end across processes.
|
||||
# The faketime wrapper creates SHM with a known FAKETIME value,
|
||||
# and the child process (via LD_PRELOAD) reads it and reports
|
||||
# the faked time.
|
||||
|
||||
init()
|
||||
{
|
||||
typeset testsuite="$1"
|
||||
PLATFORM=$(platform)
|
||||
if [ -z "$PLATFORM" ]; then
|
||||
echo "$testsuite: unknown platform! quitting"
|
||||
return 1
|
||||
fi
|
||||
echo "# PLATFORM=$PLATFORM"
|
||||
return 0
|
||||
}
|
||||
|
||||
run()
|
||||
{
|
||||
init
|
||||
|
||||
run_testcase shm_year_check
|
||||
}
|
||||
|
||||
shm_year_check()
|
||||
{
|
||||
typeset expected="2020"
|
||||
typeset actual
|
||||
actual=$(fakecmd "2020-06-15 12:00:00" date -u +%Y)
|
||||
asserteq "$actual" "$expected" "child process should see faked year via SHM"
|
||||
}
|
||||
65
test/shm_layout_test.c
Normal file
65
test/shm_layout_test.c
Normal file
@@ -0,0 +1,65 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "../src/faketime_common.h"
|
||||
|
||||
static int failures = 0;
|
||||
|
||||
static void check_offset(const char *field, size_t actual, size_t expected)
|
||||
{
|
||||
if (actual != expected)
|
||||
{
|
||||
fprintf(stderr, "FAIL: offsetof(ft_shared_s, %s) = %zu, expected %zu\n",
|
||||
field, actual, expected);
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("OK: offsetof(ft_shared_s, %s) = %zu\n", field, actual);
|
||||
}
|
||||
}
|
||||
|
||||
static void check_size(const char *name, size_t actual, size_t expected)
|
||||
{
|
||||
if (actual != expected)
|
||||
{
|
||||
fprintf(stderr, "FAIL: sizeof(%s) = %zu, expected %zu\n",
|
||||
name, actual, expected);
|
||||
failures++;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("OK: sizeof(%s) = %zu\n", name, actual);
|
||||
}
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
/* ft_shared_time_s must be exactly 16 bytes: two int64_t */
|
||||
check_size("ft_shared_time_s", sizeof(struct ft_shared_time_s), 16);
|
||||
|
||||
/* Field offsets in ft_shared_s */
|
||||
check_offset("ticks", offsetof(struct ft_shared_s, ticks), 0);
|
||||
check_offset("file_idx", offsetof(struct ft_shared_s, file_idx), 8);
|
||||
check_offset("start_time_real", offsetof(struct ft_shared_s, start_time_real), 16);
|
||||
check_offset("start_time_mon", offsetof(struct ft_shared_s, start_time_mon), 32);
|
||||
check_offset("start_time_mon_raw", offsetof(struct ft_shared_s, start_time_mon_raw), 48);
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
check_offset("start_time_boot", offsetof(struct ft_shared_s, start_time_boot), 64);
|
||||
check_size("ft_shared_s", sizeof(struct ft_shared_s), 80);
|
||||
#else
|
||||
check_size("ft_shared_s", sizeof(struct ft_shared_s), 64);
|
||||
#endif
|
||||
|
||||
if (failures > 0)
|
||||
{
|
||||
fprintf(stderr, "%d layout check(s) failed\n", failures);
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
printf("All layout checks passed\n");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
Reference in New Issue
Block a user