diff --git a/src/Makefile b/src/Makefile index d40c90b..f42de7e 100644 --- a/src/Makefile +++ b/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 diff --git a/src/faketime.c b/src/faketime.c index 71a6969..3cf4e0f 100644 --- a/src/faketime.c +++ b/src/faketime.c @@ -44,7 +44,7 @@ #include #include #include -#include +#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,10 +282,7 @@ 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); } @@ -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); } @@ -334,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); } { diff --git a/src/ft_sem.c b/src/ft_sem.c new file mode 100644 index 0000000..f565ae6 --- /dev/null +++ b/src/ft_sem.c @@ -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 +#include +#include +#include +#include +#include +#include +#include + +#include "ft_sem.h" + +#if FT_SEMAPHORE_BACKEND == FT_SYSV +#include +#endif + +#if FT_SEMAPHORE_BACKEND == FT_FLOCK +#include +#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 +} diff --git a/src/ft_sem.h b/src/ft_sem.h new file mode 100644 index 0000000..9307a9c --- /dev/null +++ b/src/ft_sem.h @@ -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 +#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 */ diff --git a/src/libfaketime.c b/src/libfaketime.c index d4ffcda..74caccb 100644 --- a/src/libfaketime.c +++ b/src/libfaketime.c @@ -51,7 +51,6 @@ #include #include #include -#include #include #include #include @@ -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 #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,138 +427,6 @@ 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