Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <stdarg.h>
3 : : #include <fcntl.h>
4 : : #include "crtools.h"
5 : : #include "cr_options.h"
6 : : #include "fdset.h"
7 : : #include "image.h"
8 : : #include "pstree.h"
9 : : #include "stats.h"
10 : : #include "protobuf.h"
11 : : #include "protobuf/inventory.pb-c.h"
12 : : #include "protobuf/pagemap.pb-c.h"
13 : :
14 : : bool fdinfo_per_id = false;
15 : : bool ns_per_id = false;
16 : : TaskKobjIdsEntry *root_ids;
17 : :
18 : 1012 : int check_img_inventory(void)
19 : : {
20 : : int fd, ret = -1;
21 : : InventoryEntry *he;
22 : :
23 : 1012 : fd = open_image(CR_FD_INVENTORY, O_RSTR);
24 [ + - ]: 1012 : if (fd < 0)
25 : : return -1;
26 : :
27 [ + - ]: 1012 : if (pb_read_one(fd, &he, PB_INVENTORY) < 0)
28 : : goto out_close;
29 : :
30 [ + - ][ - + ]: 1012 : fdinfo_per_id = he->has_fdinfo_per_id ? he->fdinfo_per_id : false;
31 [ + - ][ - + ]: 1012 : ns_per_id = he->has_ns_per_id ? he->ns_per_id : false;
32 : :
33 [ + - ]: 1012 : if (he->root_ids) {
34 [ - + ]: 1012 : root_ids = xmalloc(sizeof(*root_ids));
35 [ + - ]: 1012 : if (!root_ids)
36 : : goto out_err;
37 : :
38 : 1012 : memcpy(root_ids, he->root_ids, sizeof(*root_ids));
39 : : }
40 : :
41 [ - + ]: 1012 : if (he->img_version != CRTOOLS_IMAGES_V1) {
42 : 0 : pr_err("Not supported images version %u\n", he->img_version);
43 : 0 : goto out_err;
44 : : }
45 : : ret = 0;
46 : :
47 : : out_err:
48 : 1012 : inventory_entry__free_unpacked(he, NULL);
49 : : out_close:
50 : 1012 : close(fd);
51 : 1012 : return ret;
52 : : }
53 : :
54 : 448 : int write_img_inventory(void)
55 : : {
56 : : int fd;
57 : 448 : InventoryEntry he = INVENTORY_ENTRY__INIT;
58 : 448 : struct pstree_item crt = { };
59 : :
60 : 448 : pr_info("Writing image inventory (version %u)\n", CRTOOLS_IMAGES_V1);
61 : :
62 : 448 : fd = open_image(CR_FD_INVENTORY, O_DUMP);
63 [ + - ]: 448 : if (fd < 0)
64 : : return -1;
65 : :
66 : 448 : he.img_version = CRTOOLS_IMAGES_V1;
67 : 448 : he.fdinfo_per_id = true;
68 : 448 : he.has_fdinfo_per_id = true;
69 : 448 : he.ns_per_id = true;
70 : 448 : he.has_ns_per_id = true;
71 : :
72 : 448 : crt.state = TASK_ALIVE;
73 : 448 : crt.pid.real = getpid();
74 [ - + ]: 448 : if (get_task_ids(&crt)) {
75 : 0 : close(fd);
76 : 0 : return -1;
77 : : }
78 : :
79 : 448 : he.root_ids = crt.ids;
80 : :
81 [ + - ]: 448 : if (pb_write_one(fd, &he, PB_INVENTORY) < 0)
82 : : return -1;
83 : :
84 [ + - ]: 448 : xfree(crt.ids);
85 : 448 : close(fd);
86 : 448 : return 0;
87 : : }
88 : :
89 : 0 : void kill_inventory(void)
90 : : {
91 : 0 : unlinkat(get_service_fd(IMG_FD_OFF),
92 : : fdset_template[CR_FD_INVENTORY].fmt, 0);
93 : 0 : }
94 : :
95 : 1801 : static struct cr_fdset *alloc_cr_fdset(int nr)
96 : : {
97 : : struct cr_fdset *cr_fdset;
98 : : unsigned int i;
99 : :
100 [ - + ]: 1801 : cr_fdset = xmalloc(sizeof(*cr_fdset));
101 [ + - ]: 1801 : if (cr_fdset == NULL)
102 : : return NULL;
103 : :
104 [ - + ]: 1801 : cr_fdset->_fds = xmalloc(nr * sizeof(int));
105 [ + - ]: 1801 : if (cr_fdset->_fds == NULL) {
106 [ # # ]: 0 : xfree(cr_fdset);
107 : : return NULL;
108 : : }
109 : :
110 [ + + ]: 23442 : for (i = 0; i < nr; i++)
111 : 21641 : cr_fdset->_fds[i] = -1;
112 : 1801 : cr_fdset->fd_nr = nr;
113 : 1801 : return cr_fdset;
114 : : }
115 : :
116 : 1801 : static void __close_cr_fdset(struct cr_fdset *cr_fdset)
117 : : {
118 : : unsigned int i;
119 : :
120 [ + - ]: 1801 : if (!cr_fdset)
121 : 1801 : return;
122 : :
123 [ + + ]: 23442 : for (i = 0; i < cr_fdset->fd_nr; i++) {
124 [ + + ]: 21641 : if (cr_fdset->_fds[i] == -1)
125 : 1801 : continue;
126 : 19840 : close_safe(&cr_fdset->_fds[i]);
127 : 19840 : cr_fdset->_fds[i] = -1;
128 : : }
129 : : }
130 : :
131 : 1801 : void close_cr_fdset(struct cr_fdset **cr_fdset)
132 : : {
133 [ + - ][ + - ]: 1801 : if (!cr_fdset || !*cr_fdset)
134 : 1801 : return;
135 : :
136 : 1801 : __close_cr_fdset(*cr_fdset);
137 : :
138 [ + - ]: 1801 : xfree((*cr_fdset)->_fds);
139 [ + - ]: 1801 : xfree(*cr_fdset);
140 : 1801 : *cr_fdset = NULL;
141 : : }
142 : :
143 : 1801 : struct cr_fdset *cr_fdset_open_range(int pid, int from, int to,
144 : : unsigned long flags)
145 : : {
146 : : struct cr_fdset *fdset;
147 : : unsigned int i;
148 : : int ret = -1;
149 : :
150 : 1801 : fdset = alloc_cr_fdset(to - from);
151 [ + - ]: 1801 : if (!fdset)
152 : : goto err;
153 : :
154 : 1801 : from++;
155 : 1801 : fdset->fd_off = from;
156 [ + + ]: 21641 : for (i = from; i < to; i++) {
157 : 19840 : ret = open_image(i, flags, pid);
158 [ - + ]: 19840 : if (ret < 0) {
159 [ # # ]: 0 : if (!(flags & O_CREAT))
160 : : /* caller should check himself */
161 : 0 : continue;
162 : : goto err;
163 : : }
164 : :
165 : 19840 : fdset->_fds[i - from] = ret;
166 : : }
167 : :
168 : 1801 : return fdset;
169 : :
170 : : err:
171 : 0 : close_cr_fdset(&fdset);
172 : 0 : return NULL;
173 : : }
174 : :
175 : 919 : struct cr_fdset *cr_task_fdset_open(int pid, int mode)
176 : : {
177 : 919 : return cr_fdset_open(pid, TASK, mode);
178 : : }
179 : :
180 : 448 : struct cr_fdset *cr_glob_fdset_open(int mode)
181 : : {
182 : 448 : return cr_fdset_open(-1 /* ignored */, GLOB, mode);
183 : : }
184 : :
185 : 73611 : int open_image_at(int dfd, int type, unsigned long flags, ...)
186 : : {
187 : 73611 : bool optional = !!(flags & O_OPT);
188 : : char path[PATH_MAX];
189 : : va_list args;
190 : : int ret;
191 : :
192 : 73611 : flags &= ~O_OPT;
193 : :
194 : 73611 : va_start(args, flags);
195 : 73611 : vsnprintf(path, PATH_MAX, fdset_template[type].fmt, args);
196 : 73611 : va_end(args);
197 : :
198 : 73611 : ret = openat(dfd, path, flags, CR_FD_PERM);
199 [ + + ]: 73611 : if (ret < 0) {
200 [ + + ][ - + ]: 1903 : if (optional && errno == ENOENT)
201 : : return -ENOENT;
202 : 81 : pr_perror("Unable to open %s", path);
203 : 81 : goto err;
204 : : }
205 : :
206 [ + + ]: 71708 : if (fdset_template[type].magic == RAW_IMAGE_MAGIC)
207 : : goto skip_magic;
208 : :
209 [ + + ]: 59331 : if (flags == O_RDONLY) {
210 : : u32 magic;
211 : :
212 [ + - ]: 28682 : if (read_img(ret, &magic) < 0)
213 : : goto err;
214 [ - + ]: 28682 : if (magic != fdset_template[type].magic) {
215 : 28682 : pr_err("Magic doesn't match for %s\n", path);
216 : 0 : goto err;
217 : : }
218 : : } else {
219 [ + - ]: 30649 : if (write_img(ret, &fdset_template[type].magic))
220 : : goto err;
221 : : }
222 : :
223 : : skip_magic:
224 : 71708 : return ret;
225 : : err:
226 : : return -1;
227 : : }
228 : :
229 : 3702 : int open_image_dir(char *dir)
230 : : {
231 : : int fd, ret;
232 : :
233 : : fd = open(dir, O_RDONLY);
234 [ - + ]: 3702 : if (fd < 0) {
235 : 0 : pr_perror("Can't open dir %s", dir);
236 : 0 : return -1;
237 : : }
238 : :
239 : 3702 : ret = install_service_fd(IMG_FD_OFF, fd);
240 : 3702 : close(fd);
241 : : fd = ret;
242 : :
243 [ + + ]: 3702 : if (opts.img_parent) {
244 : 1344 : ret = symlinkat(opts.img_parent, fd, CR_PARENT_LINK);
245 [ - + ][ # # ]: 1344 : if (ret < 0 && errno != EEXIST) {
246 : 0 : pr_perror("Can't link parent snapshot");
247 : : goto err;
248 : : }
249 : : }
250 : :
251 : : return 0;
252 : :
253 : : err:
254 : : close_image_dir();
255 : 0 : return -1;
256 : : }
257 : :
258 : 347 : void close_image_dir(void)
259 : : {
260 : 347 : close_service_fd(IMG_FD_OFF);
261 : 347 : }
262 : :
263 : : static unsigned long page_ids = 1;
264 : :
265 : 896 : void up_page_ids_base(void)
266 : : {
267 : : /*
268 : : * When page server and criu dump work on
269 : : * the same dir, the shmem pagemaps and regular
270 : : * pagemaps may have IDs conflicts. Fix this by
271 : : * making page server produce page images with
272 : : * higher IDs.
273 : : */
274 : :
275 [ - + ]: 896 : BUG_ON(page_ids != 1);
276 : 896 : page_ids += 0x10000;
277 : 896 : }
278 : :
279 : 11085 : int open_pages_image_at(int dfd, unsigned long flags, int pm_fd)
280 : : {
281 : : unsigned id;
282 : :
283 [ + + ]: 11085 : if (flags == O_RDONLY || flags == O_RDWR) {
284 : : PagemapHead *h;
285 [ - + ]: 7379 : if (pb_read_one(pm_fd, &h, PB_PAGEMAP_HEAD) < 0)
286 : 0 : return -1;
287 : 7379 : id = h->pages_id;
288 : 7379 : pagemap_head__free_unpacked(h, NULL);
289 : : } else {
290 : 3706 : PagemapHead h = PAGEMAP_HEAD__INIT;
291 : 3706 : id = h.pages_id = page_ids++;
292 [ - + ]: 3706 : if (pb_write_one(pm_fd, &h, PB_PAGEMAP_HEAD) < 0)
293 : 3706 : return -1;
294 : : }
295 : :
296 : 11085 : return open_image_at(dfd, CR_FD_PAGES, flags, id);
297 : : }
298 : :
299 : 3706 : int open_pages_image(unsigned long flags, int pm_fd)
300 : : {
301 : 3706 : return open_pages_image_at(get_service_fd(IMG_FD_OFF), flags, pm_fd);
302 : : }
|