Commit fd9969ec authored by Julius Plenz's avatar Julius Plenz

handle stdout correctly if it's a file

When you invoke "tar cfv <tarball> <files>", then tar will close all active file descriptors it has, forks, then opens the target tarball as fd 1 (stdout). Then, it'll exec "gzip -", which *inherits* a stdout which is a file. Now we duplicate this stdout if it's a regular file so that we can advise it later. (The original will be closed via the _exit() routine, probably, which uses direct syscall that we cannot intercept.)
parent e033127e
......@@ -29,3 +29,8 @@ void sync_if_writable(int fd)
if((r & O_ACCMODE) != O_RDONLY)
fdatasync(fd);
}
int fcntl_dupfd(int fd, int arg)
{
return fcntl(fd, F_DUPFD, arg);
}
......@@ -19,6 +19,7 @@ int (*_original_close)(int fd);
static void init(void) __attribute__((constructor));
static void destroy(void) __attribute__((destructor));
static void init_mutex(void);
static void handle_stdout(void);
int open(const char *pathname, int flags, mode_t mode);
int open64(const char *pathname, int flags, mode_t mode)
......@@ -42,6 +43,7 @@ extern int fadv_dontneed(int fd, off_t offset, off_t len);
extern int fadv_noreuse(int fd, off_t offset, off_t len);
extern int valid_fd(int fd);
extern void sync_if_writable(int fd);
extern int fcntl_dupfd(int fd, int arg);
#define _MAX_FDS 1024
......@@ -71,6 +73,7 @@ static void init(void)
for(i = 0; i < _MAX_FDS; i++)
fds[i].fd = -1;
init_mutex();
handle_stdout();
}
static void init_mutex(void)
......@@ -80,6 +83,23 @@ static void init_mutex(void)
pthread_atfork(NULL, NULL, init_mutex);
}
/* duplicate stdout if it is a regular file. We will use this later to
* fadvise(DONTNEED) on it, although the real stdout was already
* closed. This makes "nocache tar cfz" work properly. */
static void handle_stdout(void)
{
int fd;
struct stat st;
if(fstat(STDOUT_FILENO, &st) == -1 || !S_ISREG(st.st_mode))
return;
fd = fcntl_dupfd(STDOUT_FILENO, 23);
if(fd == -1)
return;
store_pageinfo(fd);
}
/* try to advise fds that were not manually closed */
static void destroy(void)
{
......@@ -88,6 +108,8 @@ static void destroy(void)
for(i = 0; i < _MAX_FDS; i++) {
if(fds[i].fd == -1)
continue; /* slot is empty */
if(!valid_fd(fds[i].fd))
continue;
pthread_mutex_unlock(&lock);
free_unclaimed_pages(fds[i].fd);
pthread_mutex_lock(&lock);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment