2012-06-28 03:12:08 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdarg.h>
|
2013-11-14 19:19:49 +04:00
|
|
|
#include <fcntl.h>
|
2013-11-06 17:21:13 +04:00
|
|
|
#include "crtools.h"
|
2013-11-06 17:21:11 +04:00
|
|
|
#include "cr_options.h"
|
2013-11-06 14:34:28 +04:00
|
|
|
#include "fdset.h"
|
2012-06-28 03:12:08 +04:00
|
|
|
#include "image.h"
|
2013-01-17 16:56:24 +04:00
|
|
|
#include "pstree.h"
|
2013-05-08 17:23:56 +04:00
|
|
|
#include "stats.h"
|
2012-07-19 17:37:25 +04:00
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/inventory.pb-c.h"
|
2013-03-12 21:00:05 +04:00
|
|
|
#include "protobuf/pagemap.pb-c.h"
|
2012-07-19 17:37:25 +04:00
|
|
|
|
2013-01-11 18:16:25 +04:00
|
|
|
bool fdinfo_per_id = false;
|
2013-09-30 17:16:51 +04:00
|
|
|
bool ns_per_id = false;
|
2013-01-17 18:10:29 +04:00
|
|
|
TaskKobjIdsEntry *root_ids;
|
2013-01-11 18:16:25 +04:00
|
|
|
|
2012-07-19 17:37:25 +04:00
|
|
|
int check_img_inventory(void)
|
|
|
|
{
|
2013-03-14 19:38:57 +04:00
|
|
|
int fd, ret = -1;
|
2012-07-19 17:37:25 +04:00
|
|
|
InventoryEntry *he;
|
|
|
|
|
2013-04-09 11:13:51 +04:00
|
|
|
fd = open_image(CR_FD_INVENTORY, O_RSTR);
|
2012-07-19 17:37:25 +04:00
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
2013-03-14 19:38:57 +04:00
|
|
|
if (pb_read_one(fd, &he, PB_INVENTORY) < 0)
|
|
|
|
goto out_close;
|
2012-07-19 17:37:25 +04:00
|
|
|
|
2013-01-11 18:16:25 +04:00
|
|
|
fdinfo_per_id = he->has_fdinfo_per_id ? he->fdinfo_per_id : false;
|
2013-09-30 17:16:51 +04:00
|
|
|
ns_per_id = he->has_ns_per_id ? he->ns_per_id : false;
|
2013-01-11 18:16:25 +04:00
|
|
|
|
2013-01-17 18:46:42 +04:00
|
|
|
if (he->root_ids) {
|
|
|
|
root_ids = xmalloc(sizeof(*root_ids));
|
|
|
|
if (!root_ids)
|
2013-03-14 19:38:57 +04:00
|
|
|
goto out_err;
|
2013-01-17 18:46:42 +04:00
|
|
|
|
|
|
|
memcpy(root_ids, he->root_ids, sizeof(*root_ids));
|
|
|
|
}
|
2012-07-19 17:37:25 +04:00
|
|
|
|
2013-03-14 19:38:57 +04:00
|
|
|
if (he->img_version != CRTOOLS_IMAGES_V1) {
|
|
|
|
pr_err("Not supported images version %u\n", he->img_version);
|
|
|
|
goto out_err;
|
2012-07-19 17:37:25 +04:00
|
|
|
}
|
2013-03-14 19:38:57 +04:00
|
|
|
ret = 0;
|
2012-07-19 17:37:25 +04:00
|
|
|
|
2013-03-14 19:38:57 +04:00
|
|
|
out_err:
|
|
|
|
inventory_entry__free_unpacked(he, NULL);
|
|
|
|
out_close:
|
|
|
|
close(fd);
|
|
|
|
return ret;
|
2012-07-19 17:37:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int write_img_inventory(void)
|
|
|
|
{
|
|
|
|
int fd;
|
|
|
|
InventoryEntry he = INVENTORY_ENTRY__INIT;
|
2013-01-17 16:56:24 +04:00
|
|
|
struct pstree_item crt = { };
|
2012-07-19 17:37:25 +04:00
|
|
|
|
|
|
|
pr_info("Writing image inventory (version %u)\n", CRTOOLS_IMAGES_V1);
|
|
|
|
|
|
|
|
fd = open_image(CR_FD_INVENTORY, O_DUMP);
|
|
|
|
if (fd < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
he.img_version = CRTOOLS_IMAGES_V1;
|
2013-01-11 18:16:25 +04:00
|
|
|
he.fdinfo_per_id = true;
|
|
|
|
he.has_fdinfo_per_id = true;
|
2013-09-30 17:16:51 +04:00
|
|
|
he.ns_per_id = true;
|
|
|
|
he.has_ns_per_id = true;
|
2012-07-19 17:37:25 +04:00
|
|
|
|
2013-03-14 20:56:00 +04:00
|
|
|
crt.state = TASK_ALIVE;
|
2013-01-17 16:56:24 +04:00
|
|
|
crt.pid.real = getpid();
|
2013-05-17 15:06:36 +04:00
|
|
|
if (get_task_ids(&crt)){
|
|
|
|
close(fd);
|
2013-01-17 16:56:24 +04:00
|
|
|
return -1;
|
2013-05-17 15:06:36 +04:00
|
|
|
}
|
2013-01-17 16:56:24 +04:00
|
|
|
|
|
|
|
he.root_ids = crt.ids;
|
|
|
|
|
2012-08-07 02:26:50 +04:00
|
|
|
if (pb_write_one(fd, &he, PB_INVENTORY) < 0)
|
2012-07-19 17:37:25 +04:00
|
|
|
return -1;
|
|
|
|
|
2013-01-17 16:56:24 +04:00
|
|
|
xfree(crt.ids);
|
2012-07-19 17:37:25 +04:00
|
|
|
close(fd);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-27 16:16:25 +04:00
|
|
|
void kill_inventory(void)
|
|
|
|
{
|
|
|
|
unlinkat(get_service_fd(IMG_FD_OFF),
|
|
|
|
fdset_template[CR_FD_INVENTORY].fmt, 0);
|
|
|
|
}
|
|
|
|
|
2012-06-28 03:12:08 +04:00
|
|
|
static struct cr_fdset *alloc_cr_fdset(int nr)
|
|
|
|
{
|
|
|
|
struct cr_fdset *cr_fdset;
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
cr_fdset = xmalloc(sizeof(*cr_fdset));
|
|
|
|
if (cr_fdset == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
cr_fdset->_fds = xmalloc(nr * sizeof(int));
|
|
|
|
if (cr_fdset->_fds == NULL) {
|
|
|
|
xfree(cr_fdset);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++)
|
|
|
|
cr_fdset->_fds[i] = -1;
|
|
|
|
cr_fdset->fd_nr = nr;
|
|
|
|
return cr_fdset;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void __close_cr_fdset(struct cr_fdset *cr_fdset)
|
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
if (!cr_fdset)
|
|
|
|
return;
|
|
|
|
|
|
|
|
for (i = 0; i < cr_fdset->fd_nr; i++) {
|
|
|
|
if (cr_fdset->_fds[i] == -1)
|
|
|
|
continue;
|
|
|
|
close_safe(&cr_fdset->_fds[i]);
|
|
|
|
cr_fdset->_fds[i] = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void close_cr_fdset(struct cr_fdset **cr_fdset)
|
|
|
|
{
|
|
|
|
if (!cr_fdset || !*cr_fdset)
|
|
|
|
return;
|
|
|
|
|
|
|
|
__close_cr_fdset(*cr_fdset);
|
|
|
|
|
|
|
|
xfree((*cr_fdset)->_fds);
|
|
|
|
xfree(*cr_fdset);
|
|
|
|
*cr_fdset = NULL;
|
|
|
|
}
|
|
|
|
|
2013-09-28 05:39:52 +04:00
|
|
|
struct cr_fdset *cr_fdset_open_range(int pid, int from, int to,
|
2012-06-28 03:12:08 +04:00
|
|
|
unsigned long flags)
|
|
|
|
{
|
|
|
|
struct cr_fdset *fdset;
|
|
|
|
unsigned int i;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
fdset = alloc_cr_fdset(to - from);
|
|
|
|
if (!fdset)
|
|
|
|
goto err;
|
|
|
|
|
|
|
|
from++;
|
|
|
|
fdset->fd_off = from;
|
|
|
|
for (i = from; i < to; i++) {
|
|
|
|
ret = open_image(i, flags, pid);
|
|
|
|
if (ret < 0) {
|
|
|
|
if (!(flags & O_CREAT))
|
|
|
|
/* caller should check himself */
|
|
|
|
continue;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
fdset->_fds[i - from] = ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
return fdset;
|
|
|
|
|
|
|
|
err:
|
|
|
|
close_cr_fdset(&fdset);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cr_fdset *cr_task_fdset_open(int pid, int mode)
|
|
|
|
{
|
2013-09-28 05:39:52 +04:00
|
|
|
return cr_fdset_open(pid, TASK, mode);
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
struct cr_fdset *cr_glob_fdset_open(int mode)
|
|
|
|
{
|
2013-09-28 05:39:52 +04:00
|
|
|
return cr_fdset_open(-1 /* ignored */, GLOB, mode);
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
2013-04-11 17:49:43 +04:00
|
|
|
int open_image_at(int dfd, int type, unsigned long flags, ...)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
|
|
|
char path[PATH_MAX];
|
|
|
|
va_list args;
|
|
|
|
int ret;
|
|
|
|
|
|
|
|
va_start(args, flags);
|
|
|
|
vsnprintf(path, PATH_MAX, fdset_template[type].fmt, args);
|
|
|
|
va_end(args);
|
|
|
|
|
|
|
|
if (flags & O_EXCL) {
|
2013-01-11 18:16:20 +04:00
|
|
|
ret = unlinkat(dfd, path, 0);
|
2012-06-28 03:12:08 +04:00
|
|
|
if (ret && errno != ENOENT) {
|
|
|
|
pr_perror("Unable to unlink %s", path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-11 18:16:20 +04:00
|
|
|
ret = openat(dfd, path, flags, CR_FD_PERM);
|
2012-06-28 03:12:08 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Unable to open %s", path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-08-02 07:42:41 +04:00
|
|
|
if (fdset_template[type].magic == RAW_IMAGE_MAGIC)
|
|
|
|
goto skip_magic;
|
|
|
|
|
2012-06-28 03:12:08 +04:00
|
|
|
if (flags == O_RDONLY) {
|
|
|
|
u32 magic;
|
|
|
|
|
|
|
|
if (read_img(ret, &magic) < 0)
|
|
|
|
goto err;
|
|
|
|
if (magic != fdset_template[type].magic) {
|
|
|
|
pr_err("Magic doesn't match for %s\n", path);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (write_img(ret, &fdset_template[type].magic))
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2012-08-02 07:42:41 +04:00
|
|
|
skip_magic:
|
2012-06-28 03:12:08 +04:00
|
|
|
return ret;
|
|
|
|
err:
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int open_image_dir(void)
|
|
|
|
{
|
2013-01-11 18:16:20 +04:00
|
|
|
int fd, ret;
|
2012-06-28 03:12:08 +04:00
|
|
|
|
|
|
|
fd = open(".", O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't open cwd");
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-11 18:16:20 +04:00
|
|
|
ret = install_service_fd(IMG_FD_OFF, fd);
|
|
|
|
|
|
|
|
close(fd);
|
2012-06-28 03:12:08 +04:00
|
|
|
|
2013-05-08 15:52:48 +04:00
|
|
|
if (opts.img_parent) {
|
|
|
|
ret = symlink(opts.img_parent, CR_PARENT_LINK);
|
2013-04-11 17:50:42 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
pr_perror("Can't link parent snapshot.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
fd = open(CR_PARENT_LINK, O_RDONLY);
|
|
|
|
if (fd < 0) {
|
|
|
|
pr_perror("Can't open parent snapshot.");
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
|
|
|
ret = install_service_fd(PARENT_FD_OFF, fd);
|
|
|
|
|
|
|
|
close(fd);
|
|
|
|
}
|
|
|
|
|
2013-01-11 18:16:20 +04:00
|
|
|
return ret;
|
2013-04-11 17:50:42 +04:00
|
|
|
|
|
|
|
err:
|
|
|
|
close_image_dir();
|
|
|
|
return -1;
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void close_image_dir(void)
|
|
|
|
{
|
2013-01-11 18:16:20 +04:00
|
|
|
close_service_fd(IMG_FD_OFF);
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
2013-03-12 21:00:05 +04:00
|
|
|
|
|
|
|
static unsigned long page_ids = 1;
|
|
|
|
|
2013-03-14 18:28:38 +04:00
|
|
|
void up_page_ids_base(void)
|
|
|
|
{
|
|
|
|
/*
|
2013-05-09 10:58:04 -07:00
|
|
|
* When page server and criu dump work on
|
2013-03-14 18:28:38 +04:00
|
|
|
* the same dir, the shmem pagemaps and regular
|
|
|
|
* pagemaps may have IDs conflicts. Fix this by
|
|
|
|
* making page server produce page images with
|
|
|
|
* higher IDs.
|
|
|
|
*/
|
|
|
|
|
|
|
|
BUG_ON(page_ids != 1);
|
|
|
|
page_ids += 0x10000;
|
|
|
|
}
|
|
|
|
|
2013-04-11 17:49:43 +04:00
|
|
|
int open_pages_image_at(int dfd, unsigned long flags, int pm_fd)
|
2013-03-12 21:00:05 +04:00
|
|
|
{
|
|
|
|
unsigned id;
|
|
|
|
|
|
|
|
if (flags == O_RDONLY) {
|
|
|
|
PagemapHead *h;
|
|
|
|
if (pb_read_one(pm_fd, &h, PB_PAGEMAP_HEAD) < 0)
|
|
|
|
return -1;
|
|
|
|
id = h->pages_id;
|
|
|
|
pagemap_head__free_unpacked(h, NULL);
|
|
|
|
} else {
|
|
|
|
PagemapHead h = PAGEMAP_HEAD__INIT;
|
|
|
|
id = h.pages_id = page_ids++;
|
|
|
|
if (pb_write_one(pm_fd, &h, PB_PAGEMAP_HEAD) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-04-11 17:49:43 +04:00
|
|
|
return open_image_at(dfd, CR_FD_PAGES, flags, id);
|
|
|
|
}
|
|
|
|
|
|
|
|
int open_pages_image(unsigned long flags, int pm_fd)
|
|
|
|
{
|
|
|
|
return open_pages_image_at(get_service_fd(IMG_FD_OFF), flags, pm_fd);
|
2013-03-12 21:00:05 +04:00
|
|
|
}
|