summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--project/common.mk1
-rw-r--r--project/headers.mk1
-rw-r--r--src/internal/slibtool_tmpfile_impl.c89
-rw-r--r--src/internal/slibtool_tmpfile_impl.h6
4 files changed, 97 insertions, 0 deletions
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 <time.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <inttypes.h>
+
+#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