mirror of
https://git.proxmox.com/git/mirror_lxc
synced 2025-07-21 20:10:04 +00:00

This patch fix a problem with the commit d983b93c3a
When the lxc daemonize, it closes fd 0, 1 and 2. But these ones are coming from
inherited fd and they are already in the inherited list of fd. When lxc creates
some file descriptors, they have the number of the previous inherited file
descriptor, so they are closed when we close all the inherited file descriptors.
In order to fix that, the lxc_close_inherited_fd function has been implemented
to close an inherited fd and remove it from the list.
Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
230 lines
4.4 KiB
C
230 lines
4.4 KiB
C
/*
|
|
* lxc: linux Container library
|
|
*
|
|
* (C) Copyright IBM Corp. 2007, 2008
|
|
*
|
|
* Authors:
|
|
* Daniel Lezcano <dlezcano at fr.ibm.com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
#define _GNU_SOURCE
|
|
#include <errno.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stddef.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/param.h>
|
|
#include <dirent.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "list.h"
|
|
#include "log.h"
|
|
|
|
lxc_log_define(lxc_utils, lxc);
|
|
|
|
int lxc_copy_file(const char *srcfile, const char *dstfile)
|
|
{
|
|
void *srcaddr = NULL, *dstaddr;
|
|
struct stat stat;
|
|
int srcfd, dstfd, ret = -1;
|
|
char c = '\0';
|
|
|
|
dstfd = open(dstfile, O_CREAT | O_EXCL | O_RDWR, 0600);
|
|
if (dstfd < 0) {
|
|
SYSERROR("failed to creat '%s'", dstfile);
|
|
goto out;
|
|
}
|
|
|
|
srcfd = open(srcfile, O_RDONLY);
|
|
if (srcfd < 0) {
|
|
SYSERROR("failed to open '%s'", srcfile);
|
|
goto err;
|
|
}
|
|
|
|
if (fstat(srcfd, &stat)) {
|
|
SYSERROR("failed to stat '%s'", srcfile);
|
|
goto err;
|
|
}
|
|
|
|
if (!stat.st_size) {
|
|
INFO("copy '%s' which is an empty file", srcfile);
|
|
ret = 0;
|
|
goto out_close;
|
|
}
|
|
|
|
if (lseek(dstfd, stat.st_size - 1, SEEK_SET) < 0) {
|
|
SYSERROR("failed to seek dest file '%s'", dstfile);
|
|
goto err;
|
|
}
|
|
|
|
/* fixup length */
|
|
if (write(dstfd, &c, 1) < 0) {
|
|
SYSERROR("failed to write to '%s'", dstfile);
|
|
goto err;
|
|
}
|
|
|
|
srcaddr = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, srcfd, 0L);
|
|
if (srcaddr == MAP_FAILED) {
|
|
SYSERROR("failed to mmap '%s'", srcfile);
|
|
goto err;
|
|
}
|
|
|
|
dstaddr = mmap(NULL, stat.st_size, PROT_WRITE, MAP_SHARED, dstfd, 0L);
|
|
if (dstaddr == MAP_FAILED) {
|
|
SYSERROR("failed to mmap '%s'", dstfile);
|
|
goto err;
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
memcpy(dstaddr, srcaddr, stat.st_size);
|
|
|
|
munmap(dstaddr, stat.st_size);
|
|
out_mmap:
|
|
if (srcaddr)
|
|
munmap(srcaddr, stat.st_size);
|
|
out_close:
|
|
close(dstfd);
|
|
close(srcfd);
|
|
out:
|
|
return ret;
|
|
err:
|
|
unlink(dstfile);
|
|
goto out_mmap;
|
|
}
|
|
|
|
struct lxc_fd_entry {
|
|
int fd;
|
|
struct lxc_list list;
|
|
};
|
|
|
|
struct lxc_list lxc_fd_list;
|
|
|
|
static int fd_list_add(int fd)
|
|
{
|
|
struct lxc_fd_entry *entry;
|
|
|
|
entry = malloc(sizeof(struct lxc_fd_entry));
|
|
if (!entry) {
|
|
SYSERROR("malloc");
|
|
return -1;
|
|
}
|
|
|
|
entry->fd = fd;
|
|
entry->list.elem = entry;
|
|
lxc_list_add(&lxc_fd_list, &entry->list);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void fd_list_del(struct lxc_fd_entry *entry)
|
|
{
|
|
lxc_list_del(&entry->list);
|
|
free(entry);
|
|
}
|
|
|
|
static void __attribute__((constructor)) __lxc_fd_collect_inherited(void)
|
|
{
|
|
struct dirent dirent, *direntp;
|
|
int fd, fddir;
|
|
DIR *dir;
|
|
|
|
dir = opendir("/proc/self/fd");
|
|
if (!dir) {
|
|
WARN("failed to open directory: %s", strerror(errno));
|
|
return;
|
|
}
|
|
|
|
fddir = dirfd(dir);
|
|
|
|
lxc_list_init(&lxc_fd_list);
|
|
|
|
while (!readdir_r(dir, &dirent, &direntp)) {
|
|
|
|
if (!direntp)
|
|
break;
|
|
|
|
if (!strcmp(direntp->d_name, "."))
|
|
continue;
|
|
|
|
if (!strcmp(direntp->d_name, ".."))
|
|
continue;
|
|
|
|
fd = atoi(direntp->d_name);
|
|
|
|
if (fd == fddir)
|
|
continue;
|
|
|
|
if (fd_list_add(fd))
|
|
WARN("failed to add fd '%d' to the list", fd);
|
|
}
|
|
|
|
if (closedir(dir))
|
|
WARN("failed to close directory");
|
|
}
|
|
|
|
int lxc_close_inherited_fd(int fd)
|
|
{
|
|
struct lxc_fd_entry *entry;
|
|
struct lxc_list *iterator;
|
|
|
|
lxc_list_for_each(iterator, &lxc_fd_list) {
|
|
|
|
entry = iterator->elem;
|
|
|
|
if (entry->fd != fd)
|
|
continue;
|
|
|
|
fd_list_del(entry);
|
|
|
|
break;
|
|
}
|
|
|
|
return close(fd);
|
|
}
|
|
|
|
int lxc_close_all_inherited_fd(void)
|
|
{
|
|
struct lxc_fd_entry *entry;
|
|
struct lxc_list *iterator;
|
|
|
|
again:
|
|
lxc_list_for_each(iterator, &lxc_fd_list) {
|
|
|
|
entry = iterator->elem;
|
|
|
|
/* do not close the stderr fd to keep open default
|
|
* error reporting path.
|
|
*/
|
|
if (entry->fd == 2 && isatty(entry->fd)) {
|
|
fd_list_del(entry);
|
|
continue;
|
|
}
|
|
|
|
if (close(entry->fd))
|
|
WARN("failed to close fd '%d': %s", entry->fd,
|
|
strerror(errno));
|
|
|
|
fd_list_del(entry);
|
|
goto again;
|
|
}
|
|
|
|
return 0;
|
|
}
|