diff --git a/project/common.mk b/project/common.mk index 919d53a..8373b35 100644 --- a/project/common.mk +++ b/project/common.mk @@ -79,6 +79,7 @@ INTERNAL_SRCS = \ src/internal/$(PACKAGE)_realpath_impl.c \ src/internal/$(PACKAGE)_snprintf_impl.c \ src/internal/$(PACKAGE)_symlink_impl.c \ + src/internal/$(PACKAGE)_tmpfile_impl.c \ APP_SRCS = \ src/slibtool.c diff --git a/project/headers.mk b/project/headers.mk index 6546375..8075b4b 100644 --- a/project/headers.mk +++ b/project/headers.mk @@ -26,6 +26,7 @@ INTERNAL_HEADERS = \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_spawn_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_stoolie_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_symlink_impl.h \ + $(PROJECT_DIR)/src/internal/$(PACKAGE)_tmpfile_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_uninstall_impl.h \ $(PROJECT_DIR)/src/internal/$(PACKAGE)_visibility_impl.h \ diff --git a/src/internal/slibtool_tmpfile_impl.c b/src/internal/slibtool_tmpfile_impl.c new file mode 100644 index 0000000..52c7317 --- /dev/null +++ b/src/internal/slibtool_tmpfile_impl.c @@ -0,0 +1,89 @@ +/*******************************************************************/ +/* slibtool: a strong libtool implementation, written in C */ +/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */ +/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */ +/*******************************************************************/ + +#define _GNU_SOURCE +#include +#include +#include +#include +#include +#include +#include +#include + +#include "slibtool_visibility_impl.h" + +#define PPRIX64 "%"PRIx64 + +/* mkostemp might be guarded by non-standard macros */ +/* unless HAVE_NO_MKOSTEMP, assume it is available */ +extern int mkstemp(char *); +extern int mkostemp(char *, int); + +/* __fs_tmpfile() atomically provides a private tmpfile */ +static int slbt_tmpfile_by_framework(void) +{ +#ifdef _MIDIPIX_ABI + extern int __fs_tmpfile(int); + return __fs_tmpfile(O_CLOEXEC); +#else + return (-1); +#endif +} + +/* O_TMPFILE atomically provides a private tmpfile */ +static int slbt_tmpfile_by_kernel(void) +{ +#ifdef O_TMPFILE + return openat(AT_FDCWD,"/tmp",O_RDWR|O_TMPFILE|O_CLOEXEC,0); +#else + return (-1); +#endif +} + +/* mk{o}stemp() provides a non-private tmpfile */ +static int slbt_mkostemp(char * tmplate) +{ + int fd; +#ifdef HAVE_NO_MKOSTEMP + if ((fd = mkstemp(tmplate)) >= 0) + fcntl(fd,F_SETFD,FD_CLOEXEC); +#else + fd = mkostemp(tmplate,O_CLOEXEC); +#endif + return fd; +} + +slbt_hidden int slbt_tmpfile(void) +{ + int fd; + void * addr; + char tmplate[128]; + + /* try with __fs_tmpfile() */ + if ((fd = slbt_tmpfile_by_framework()) >= 0) + return fd; + + /* try with O_TMPFILE */ + if ((fd = slbt_tmpfile_by_kernel()) >= 0) + return fd; + + /* fallback to mk{o}stemp */ + addr = tmplate; + memset(tmplate,0,sizeof(tmplate)); + snprintf(tmplate,sizeof(tmplate), + "/tmp/" + ".slibtool.tmpfile" + ".time."PPRIX64 + ".salt.%p" + ".pid.%d" + ".XXXXXXXXXXXX", + time(0), + addr, + getpid()); + + return slbt_mkostemp(tmplate); +} diff --git a/src/internal/slibtool_tmpfile_impl.h b/src/internal/slibtool_tmpfile_impl.h new file mode 100644 index 0000000..cd6a02b --- /dev/null +++ b/src/internal/slibtool_tmpfile_impl.h @@ -0,0 +1,6 @@ +#ifndef SLIBTOOL_TMPFILE_IMPL_H +#define SLIBTOOL_TMPFILE_IMPL_H + +int slbt_tmpfile(void); + +#endif