/**************************************************************/
/* tpax: a topological pax implementation */
/* Copyright (C) 2020--2021 SysDeer Technologies, LLC */
/* Released under GPLv2 and GPLv3; see COPYING.TPAX. */
/**************************************************************/
#define _GNU_SOURCE
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <stdio.h>
/* 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 tpax_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 tpax_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 tpax_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;
}
int tpax_tmpfile(void)
{
int fd;
unsigned seed;
char tmplate[64];
/* try with __fs_tmpfile() */
if ((fd = tpax_tmpfile_by_framework()) >= 0)
return fd;
/* try with O_TMPFILE */
if ((fd = tpax_tmpfile_by_kernel()) >= 0)
return fd;
/* fallback to mk{o}stemp */
seed = getpid();
memset(tmplate,0,sizeof(tmplate));
snprintf(tmplate,sizeof(tmplate),"/tmp/tpax_%d_%d_%d_XXXXXXXXXXXX",
getppid(),getpid(),rand_r(&seed));
return tpax_mkostemp(tmplate);
}