]>
Commit | Line | Data |
---|---|---|
e3642c43 DL |
1 | /* |
2 | * lxc: linux Container library | |
3 | * | |
4 | * (C) Copyright IBM Corp. 2007, 2008 | |
5 | * | |
6 | * Authors: | |
7 | * Daniel Lezcano <dlezcano at fr.ibm.com> | |
8 | * | |
9 | * This library is free software; you can redistribute it and/or | |
10 | * modify it under the terms of the GNU Lesser General Public | |
11 | * License as published by the Free Software Foundation; either | |
12 | * version 2.1 of the License, or (at your option) any later version. | |
13 | * | |
14 | * This library is distributed in the hope that it will be useful, | |
15 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
16 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
17 | * Lesser General Public License for more details. | |
18 | * | |
19 | * You should have received a copy of the GNU Lesser General Public | |
20 | * License along with this library; if not, write to the Free Software | |
21 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | |
22 | */ | |
23 | ||
d983b93c | 24 | #define _GNU_SOURCE |
e3642c43 DL |
25 | #include <errno.h> |
26 | #include <unistd.h> | |
d983b93c MN |
27 | #include <stdlib.h> |
28 | #include <stddef.h> | |
e3642c43 DL |
29 | #include <sys/types.h> |
30 | #include <sys/stat.h> | |
31 | #include <sys/mman.h> | |
d983b93c MN |
32 | #include <sys/param.h> |
33 | #include <dirent.h> | |
34 | #include <fcntl.h> | |
e3642c43 | 35 | |
af795875 | 36 | #include "list.h" |
e3642c43 DL |
37 | #include "log.h" |
38 | ||
39 | lxc_log_define(lxc_utils, lxc); | |
40 | ||
41 | int lxc_copy_file(const char *srcfile, const char *dstfile) | |
42 | { | |
43 | void *srcaddr = NULL, *dstaddr; | |
44 | struct stat stat; | |
45 | int srcfd, dstfd, ret = -1; | |
46 | char c = '\0'; | |
47 | ||
48 | dstfd = open(dstfile, O_CREAT | O_EXCL | O_RDWR, 0600); | |
49 | if (dstfd < 0) { | |
50 | SYSERROR("failed to creat '%s'", dstfile); | |
51 | goto out; | |
52 | } | |
53 | ||
54 | srcfd = open(srcfile, O_RDONLY); | |
55 | if (srcfd < 0) { | |
56 | SYSERROR("failed to open '%s'", srcfile); | |
57 | goto err; | |
58 | } | |
59 | ||
60 | if (fstat(srcfd, &stat)) { | |
61 | SYSERROR("failed to stat '%s'", srcfile); | |
62 | goto err; | |
63 | } | |
64 | ||
65 | if (!stat.st_size) { | |
66 | INFO("copy '%s' which is an empty file", srcfile); | |
67 | ret = 0; | |
68 | goto out_close; | |
69 | } | |
70 | ||
71 | if (lseek(dstfd, stat.st_size - 1, SEEK_SET) < 0) { | |
72 | SYSERROR("failed to seek dest file '%s'", dstfile); | |
73 | goto err; | |
74 | } | |
75 | ||
76 | /* fixup length */ | |
77 | if (write(dstfd, &c, 1) < 0) { | |
78 | SYSERROR("failed to write to '%s'", dstfile); | |
79 | goto err; | |
80 | } | |
81 | ||
82 | srcaddr = mmap(NULL, stat.st_size, PROT_READ, MAP_SHARED, srcfd, 0L); | |
83 | if (srcaddr == MAP_FAILED) { | |
84 | SYSERROR("failed to mmap '%s'", srcfile); | |
85 | goto err; | |
86 | } | |
87 | ||
88 | dstaddr = mmap(NULL, stat.st_size, PROT_WRITE, MAP_SHARED, dstfd, 0L); | |
89 | if (dstaddr == MAP_FAILED) { | |
90 | SYSERROR("failed to mmap '%s'", dstfile); | |
91 | goto err; | |
92 | } | |
93 | ||
94 | ret = 0; | |
95 | ||
96 | memcpy(dstaddr, srcaddr, stat.st_size); | |
97 | ||
98 | munmap(dstaddr, stat.st_size); | |
99 | out_mmap: | |
100 | if (srcaddr) | |
101 | munmap(srcaddr, stat.st_size); | |
102 | out_close: | |
103 | close(dstfd); | |
104 | close(srcfd); | |
105 | out: | |
106 | return ret; | |
107 | err: | |
108 | unlink(dstfile); | |
109 | goto out_mmap; | |
110 | } | |
d983b93c MN |
111 | |
112 | struct lxc_fd_entry { | |
113 | int fd; | |
af795875 | 114 | struct lxc_list list; |
d983b93c MN |
115 | }; |
116 | ||
af795875 | 117 | struct lxc_list lxc_fd_list; |
d983b93c MN |
118 | |
119 | static int fd_list_add(int fd) | |
120 | { | |
121 | struct lxc_fd_entry *entry; | |
122 | ||
123 | entry = malloc(sizeof(struct lxc_fd_entry)); | |
124 | if (!entry) { | |
125 | SYSERROR("malloc"); | |
126 | return -1; | |
127 | } | |
128 | ||
129 | entry->fd = fd; | |
af795875 DL |
130 | entry->list.elem = entry; |
131 | lxc_list_add(&lxc_fd_list, &entry->list); | |
d983b93c MN |
132 | |
133 | return 0; | |
134 | } | |
135 | ||
136 | static void fd_list_del(struct lxc_fd_entry *entry) | |
137 | { | |
af795875 DL |
138 | lxc_list_del(&entry->list); |
139 | free(entry); | |
d983b93c MN |
140 | } |
141 | ||
142 | static void __attribute__((constructor)) __lxc_fd_collect_inherited(void) | |
143 | { | |
144 | struct dirent dirent, *direntp; | |
145 | int fd, fddir; | |
146 | DIR *dir; | |
147 | ||
c4ffc8f7 KM |
148 | lxc_list_init(&lxc_fd_list); |
149 | ||
d983b93c MN |
150 | dir = opendir("/proc/self/fd"); |
151 | if (!dir) { | |
152 | WARN("failed to open directory: %s", strerror(errno)); | |
153 | return; | |
154 | } | |
155 | ||
156 | fddir = dirfd(dir); | |
157 | ||
158 | while (!readdir_r(dir, &dirent, &direntp)) { | |
159 | ||
160 | if (!direntp) | |
161 | break; | |
162 | ||
163 | if (!strcmp(direntp->d_name, ".")) | |
164 | continue; | |
165 | ||
166 | if (!strcmp(direntp->d_name, "..")) | |
167 | continue; | |
168 | ||
169 | fd = atoi(direntp->d_name); | |
170 | ||
171 | if (fd == fddir) | |
172 | continue; | |
173 | ||
174 | if (fd_list_add(fd)) | |
175 | WARN("failed to add fd '%d' to the list", fd); | |
176 | } | |
177 | ||
178 | if (closedir(dir)) | |
179 | WARN("failed to close directory"); | |
180 | } | |
181 | ||
af795875 DL |
182 | int lxc_close_inherited_fd(int fd) |
183 | { | |
184 | struct lxc_fd_entry *entry; | |
185 | struct lxc_list *iterator; | |
186 | ||
187 | lxc_list_for_each(iterator, &lxc_fd_list) { | |
188 | ||
189 | entry = iterator->elem; | |
190 | ||
191 | if (entry->fd != fd) | |
192 | continue; | |
193 | ||
194 | fd_list_del(entry); | |
195 | ||
196 | break; | |
197 | } | |
198 | ||
cd54d859 DL |
199 | DEBUG("closing fd '%d'", fd); |
200 | ||
af795875 DL |
201 | return close(fd); |
202 | } | |
203 | ||
204 | int lxc_close_all_inherited_fd(void) | |
d983b93c | 205 | { |
af795875 DL |
206 | struct lxc_fd_entry *entry; |
207 | struct lxc_list *iterator; | |
d983b93c | 208 | |
af795875 DL |
209 | again: |
210 | lxc_list_for_each(iterator, &lxc_fd_list) { | |
211 | ||
212 | entry = iterator->elem; | |
d983b93c MN |
213 | |
214 | /* do not close the stderr fd to keep open default | |
215 | * error reporting path. | |
216 | */ | |
af795875 DL |
217 | if (entry->fd == 2 && isatty(entry->fd)) { |
218 | fd_list_del(entry); | |
219 | continue; | |
220 | } | |
d983b93c | 221 | |
cd54d859 DL |
222 | DEBUG("closing fd '%d'", entry->fd); |
223 | ||
af795875 DL |
224 | if (close(entry->fd)) |
225 | WARN("failed to close fd '%d': %s", entry->fd, | |
d983b93c MN |
226 | strerror(errno)); |
227 | ||
af795875 DL |
228 | fd_list_del(entry); |
229 | goto again; | |
d983b93c MN |
230 | } |
231 | ||
cd54d859 DL |
232 | DEBUG("closed all inherited file descriptors"); |
233 | ||
d983b93c MN |
234 | return 0; |
235 | } |