blob: d99d7de70156e19bf48d381c3576960e1c2045bb [file] [log] [blame]
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
static void err_exit(char *op, int errn)
{
fprintf(stderr, "%s: %s\n", op, strerror(errn));
exit(errn);
}
void *thread_fn(void *arg)
{
/* execve will release threads */
while(1) sleep(1);
return NULL;
}
struct flock fl = {
.l_type = F_WRLCK,
.l_whence = SEEK_SET,
.l_start = 0,
.l_len = 1,
};
static void checklock(int fd)
{
pid_t pid;
pid = fork();
if (pid < 0)
err_exit("fork", errno);
if (!pid) {
if (fcntl(fd, F_GETLK, &fl) < 0)
err_exit("getlk", errno);
if (fl.l_type == F_UNLCK) {
printf("record lock is not preserved across execve(2)\n");
exit(1);
}
exit(0);
}
waitpid(pid, NULL, 0);
exit(0);
}
int main(int argc, char **argv)
{
int fd, flags;
char fdstr[10];
char *newargv[] = { argv[0], argv[1], fdstr, NULL };
pthread_t th;
/* passing fd in argv[2] in execve */
if (argc == 3) {
fd = atoi(argv[2]);
checklock(fd);
}
fd = open(argv[1], O_WRONLY|O_CREAT, 0755);
if (fd < 0)
err_exit("open", errno);
if (fcntl(fd, F_SETLK, &fl) < 0)
err_exit("setlk", errno);
/* require multithread process to reproduce the issue */
pthread_create(&th, NULL, thread_fn, &fd);
if ((flags = fcntl(fd, F_GETFD)) < 0)
err_exit("getfd", errno);
flags &= ~FD_CLOEXEC;
if (fcntl(fd, F_SETFD, flags) < 0)
err_exit("setfd", errno);
snprintf(fdstr, sizeof(fdstr), "%d", fd);
execve(argv[0], newargv, NULL);
return 0;
}