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"
|
2014-09-29 12:47:37 +04:00
|
|
|
#include "imgset.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"
|
2014-05-08 16:37:00 +04:00
|
|
|
#include "cgroup.h"
|
2015-05-06 16:18:42 -06:00
|
|
|
#include "lsm.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;
|
2015-04-14 22:08:59 +03:00
|
|
|
bool img_common_magic = true;
|
2013-01-17 18:10:29 +04:00
|
|
|
TaskKobjIdsEntry *root_ids;
|
2014-05-08 16:55:53 +04:00
|
|
|
u32 root_cg_set;
|
2015-05-06 16:18:42 -06:00
|
|
|
Lsmtype image_lsm;
|
2013-01-11 18:16:25 +04:00
|
|
|
|
2012-07-19 17:37:25 +04:00
|
|
|
int check_img_inventory(void)
|
|
|
|
{
|
2014-09-29 12:48:53 +04:00
|
|
|
int ret = -1;
|
|
|
|
struct cr_img *img;
|
2012-07-19 17:37:25 +04:00
|
|
|
InventoryEntry *he;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_INVENTORY, O_RSTR);
|
|
|
|
if (!img)
|
2012-07-19 17:37:25 +04:00
|
|
|
return -1;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
if (pb_read_one(img, &he, PB_INVENTORY) < 0)
|
2013-03-14 19:38:57 +04:00
|
|
|
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
|
|
|
|
2014-05-08 16:55:53 +04:00
|
|
|
if (he->has_root_cg_set) {
|
|
|
|
if (he->root_cg_set == 0) {
|
|
|
|
pr_err("Corrupted root cgset\n");
|
|
|
|
goto out_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
root_cg_set = he->root_cg_set;
|
|
|
|
}
|
|
|
|
|
2015-05-06 16:18:42 -06:00
|
|
|
image_lsm = he->lsmtype;
|
|
|
|
|
2015-04-08 16:37:28 +03:00
|
|
|
switch (he->img_version) {
|
|
|
|
case CRTOOLS_IMAGES_V1:
|
|
|
|
/* good old images. OK */
|
2015-04-14 22:08:59 +03:00
|
|
|
img_common_magic = false;
|
2015-04-08 16:37:28 +03:00
|
|
|
break;
|
|
|
|
case CRTOOLS_IMAGES_V1_1:
|
|
|
|
/* newer images with extra magic in the head */
|
|
|
|
break;
|
|
|
|
default:
|
2013-03-14 19:38:57 +04:00
|
|
|
pr_err("Not supported images version %u\n", he->img_version);
|
|
|
|
goto out_err;
|
2012-07-19 17:37:25 +04:00
|
|
|
}
|
2015-04-08 16:37:28 +03: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:
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(img);
|
2013-03-14 19:38:57 +04:00
|
|
|
return ret;
|
2012-07-19 17:37:25 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
int write_img_inventory(void)
|
|
|
|
{
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *img;
|
2012-07-19 17:37:25 +04:00
|
|
|
InventoryEntry he = INVENTORY_ENTRY__INIT;
|
2014-09-29 22:05:17 +04:00
|
|
|
struct {
|
|
|
|
struct pstree_item i;
|
|
|
|
struct dmp_info d;
|
|
|
|
} crt = { };
|
2012-07-19 17:37:25 +04:00
|
|
|
|
|
|
|
pr_info("Writing image inventory (version %u)\n", CRTOOLS_IMAGES_V1);
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = open_image(CR_FD_INVENTORY, O_DUMP);
|
|
|
|
if (!img)
|
2012-07-19 17:37:25 +04:00
|
|
|
return -1;
|
|
|
|
|
2015-04-08 16:37:28 +03:00
|
|
|
he.img_version = CRTOOLS_IMAGES_V1_1;
|
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;
|
2015-05-06 16:18:42 -06:00
|
|
|
he.lsmtype = host_lsm_type();
|
2012-07-19 17:37:25 +04:00
|
|
|
|
2014-09-29 22:05:17 +04:00
|
|
|
crt.i.state = TASK_ALIVE;
|
|
|
|
crt.i.pid.real = getpid();
|
|
|
|
if (get_task_ids(&crt.i)) {
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(img);
|
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
|
|
|
|
2014-05-08 16:42:40 +04:00
|
|
|
he.has_root_cg_set = true;
|
|
|
|
if (dump_task_cgroup(NULL, &he.root_cg_set))
|
|
|
|
return -1;
|
|
|
|
|
2014-09-29 22:05:17 +04:00
|
|
|
he.root_ids = crt.i.ids;
|
2013-01-17 16:56:24 +04:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
if (pb_write_one(img, &he, PB_INVENTORY) < 0)
|
2012-07-19 17:37:25 +04:00
|
|
|
return -1;
|
|
|
|
|
2014-09-29 22:05:17 +04:00
|
|
|
xfree(crt.i.ids);
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(img);
|
2012-07-19 17:37:25 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-03-27 16:16:25 +04:00
|
|
|
void kill_inventory(void)
|
|
|
|
{
|
|
|
|
unlinkat(get_service_fd(IMG_FD_OFF),
|
2014-09-29 12:47:37 +04:00
|
|
|
imgset_template[CR_FD_INVENTORY].fmt, 0);
|
2013-03-27 16:16:25 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
static struct cr_imgset *alloc_cr_imgset(int nr)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
2014-09-29 12:47:37 +04:00
|
|
|
struct cr_imgset *cr_imgset;
|
2012-06-28 03:12:08 +04:00
|
|
|
unsigned int i;
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
cr_imgset = xmalloc(sizeof(*cr_imgset));
|
|
|
|
if (cr_imgset == NULL)
|
2012-06-28 03:12:08 +04:00
|
|
|
return NULL;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
cr_imgset->_imgs = xmalloc(nr * sizeof(struct cr_img *));
|
2014-09-29 12:47:37 +04:00
|
|
|
if (cr_imgset->_imgs == NULL) {
|
|
|
|
xfree(cr_imgset);
|
2012-06-28 03:12:08 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (i = 0; i < nr; i++)
|
2014-09-29 12:48:53 +04:00
|
|
|
cr_imgset->_imgs[i] = NULL;
|
2014-09-29 12:47:37 +04:00
|
|
|
cr_imgset->fd_nr = nr;
|
|
|
|
return cr_imgset;
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
static void __close_cr_imgset(struct cr_imgset *cr_imgset)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
|
|
|
unsigned int i;
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
if (!cr_imgset)
|
2012-06-28 03:12:08 +04:00
|
|
|
return;
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
for (i = 0; i < cr_imgset->fd_nr; i++) {
|
2014-09-29 12:48:53 +04:00
|
|
|
if (!cr_imgset->_imgs[i])
|
2012-06-28 03:12:08 +04:00
|
|
|
continue;
|
2014-09-29 12:48:53 +04:00
|
|
|
close_image(cr_imgset->_imgs[i]);
|
|
|
|
cr_imgset->_imgs[i] = NULL;
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
void close_cr_imgset(struct cr_imgset **cr_imgset)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
2014-09-29 12:47:37 +04:00
|
|
|
if (!cr_imgset || !*cr_imgset)
|
2012-06-28 03:12:08 +04:00
|
|
|
return;
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
__close_cr_imgset(*cr_imgset);
|
2012-06-28 03:12:08 +04:00
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
xfree((*cr_imgset)->_imgs);
|
|
|
|
xfree(*cr_imgset);
|
|
|
|
*cr_imgset = NULL;
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
struct cr_imgset *cr_imgset_open_range(int pid, int from, int to,
|
2012-06-28 03:12:08 +04:00
|
|
|
unsigned long flags)
|
|
|
|
{
|
2014-09-29 12:47:37 +04:00
|
|
|
struct cr_imgset *imgset;
|
2012-06-28 03:12:08 +04:00
|
|
|
unsigned int i;
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
imgset = alloc_cr_imgset(to - from);
|
|
|
|
if (!imgset)
|
2012-06-28 03:12:08 +04:00
|
|
|
goto err;
|
|
|
|
|
|
|
|
from++;
|
2014-09-29 12:47:37 +04:00
|
|
|
imgset->fd_off = from;
|
2012-06-28 03:12:08 +04:00
|
|
|
for (i = from; i < to; i++) {
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *img;
|
|
|
|
|
|
|
|
img = open_image(i, flags, pid);
|
|
|
|
if (!img) {
|
2012-06-28 03:12:08 +04:00
|
|
|
if (!(flags & O_CREAT))
|
|
|
|
/* caller should check himself */
|
|
|
|
continue;
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
imgset->_imgs[i - from] = img;
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
return imgset;
|
2012-06-28 03:12:08 +04:00
|
|
|
|
|
|
|
err:
|
2014-09-29 12:47:37 +04:00
|
|
|
close_cr_imgset(&imgset);
|
2012-06-28 03:12:08 +04:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
struct cr_imgset *cr_task_imgset_open(int pid, int mode)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
2014-09-29 12:47:37 +04:00
|
|
|
return cr_imgset_open(pid, TASK, mode);
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
struct cr_imgset *cr_glob_imgset_open(int mode)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
2014-09-29 12:47:37 +04:00
|
|
|
return cr_imgset_open(-1 /* ignored */, GLOB, mode);
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
2015-05-01 16:03:00 +03:00
|
|
|
static int do_open_image(struct cr_img *img, int dfd, int type, unsigned long flags, char *path);
|
2015-03-10 21:47:27 +03:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *open_image_at(int dfd, int type, unsigned long flags, ...)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *img;
|
2015-03-10 21:47:27 +03:00
|
|
|
unsigned long oflags;
|
2012-06-28 03:12:08 +04:00
|
|
|
char path[PATH_MAX];
|
|
|
|
va_list args;
|
2015-03-10 21:47:27 +03:00
|
|
|
bool lazy = false;
|
2012-06-28 03:12:08 +04:00
|
|
|
|
2015-03-10 21:47:27 +03:00
|
|
|
if (dfd == -1) {
|
2015-03-06 00:00:00 +03:00
|
|
|
dfd = get_service_fd(IMG_FD_OFF);
|
2015-03-10 21:47:27 +03:00
|
|
|
lazy = (flags & O_CREAT);
|
|
|
|
}
|
2015-03-06 00:00:00 +03:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
img = xmalloc(sizeof(*img));
|
|
|
|
if (!img)
|
2015-03-10 21:47:27 +03:00
|
|
|
return NULL;
|
2014-09-29 12:48:53 +04:00
|
|
|
|
2015-03-10 21:47:27 +03:00
|
|
|
oflags = flags | imgset_template[type].oflags;
|
2014-03-13 16:06:37 +04:00
|
|
|
|
2012-06-28 03:12:08 +04:00
|
|
|
va_start(args, flags);
|
2014-09-29 12:47:37 +04:00
|
|
|
vsnprintf(path, PATH_MAX, imgset_template[type].fmt, args);
|
2012-06-28 03:12:08 +04:00
|
|
|
va_end(args);
|
|
|
|
|
2015-03-10 21:47:27 +03:00
|
|
|
if (lazy) {
|
|
|
|
img->fd = LAZY_IMG_FD;
|
|
|
|
img->type = type;
|
|
|
|
img->oflags = oflags;
|
|
|
|
img->path = xstrdup(path);
|
|
|
|
return img;
|
2015-05-01 16:03:00 +03:00
|
|
|
} else
|
|
|
|
img->fd = EMPTY_IMG_FD;
|
|
|
|
|
|
|
|
if (do_open_image(img, dfd, type, oflags, path)) {
|
|
|
|
close_image(img);
|
|
|
|
return NULL;
|
2015-03-10 21:47:27 +03:00
|
|
|
}
|
|
|
|
|
2015-05-01 16:03:00 +03:00
|
|
|
return img;
|
2015-03-10 21:47:27 +03:00
|
|
|
}
|
|
|
|
|
2015-04-08 16:37:28 +03:00
|
|
|
static inline u32 head_magic(int oflags)
|
|
|
|
{
|
|
|
|
return oflags & O_SERVICE ? IMG_SERVICE_MAGIC : IMG_COMMON_MAGIC;
|
|
|
|
}
|
|
|
|
|
2015-04-08 16:36:27 +03:00
|
|
|
static int img_check_magic(struct cr_img *img, int oflags, int type, char *path)
|
|
|
|
{
|
|
|
|
u32 magic;
|
|
|
|
|
|
|
|
if (read_img(img, &magic) < 0)
|
|
|
|
return -1;
|
|
|
|
|
2015-04-08 16:37:28 +03:00
|
|
|
if (img_common_magic && (type != CR_FD_INVENTORY)) {
|
|
|
|
if (magic != head_magic(oflags)) {
|
|
|
|
pr_err("Head magic doesn't match for %s\n", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (read_img(img, &magic) < 0)
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-04-08 16:36:27 +03:00
|
|
|
if (magic != imgset_template[type].magic) {
|
|
|
|
pr_err("Magic doesn't match for %s\n", path);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int img_write_magic(struct cr_img *img, int oflags, int type)
|
|
|
|
{
|
2015-04-08 16:37:28 +03:00
|
|
|
if (img_common_magic && (type != CR_FD_INVENTORY)) {
|
|
|
|
u32 cmagic;
|
|
|
|
|
|
|
|
cmagic = head_magic(oflags);
|
|
|
|
if (write_img(img, &cmagic))
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2015-04-08 16:36:27 +03:00
|
|
|
return write_img(img, &imgset_template[type].magic);
|
|
|
|
}
|
|
|
|
|
2015-05-01 16:03:00 +03:00
|
|
|
static int do_open_image(struct cr_img *img, int dfd, int type, unsigned long oflags, char *path)
|
2015-03-10 21:47:27 +03:00
|
|
|
{
|
|
|
|
int ret, flags;
|
|
|
|
|
2015-04-08 16:37:28 +03:00
|
|
|
flags = oflags & ~(O_NOBUF | O_SERVICE);
|
2015-03-10 21:47:27 +03:00
|
|
|
|
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) {
|
2015-03-06 18:02:43 +03:00
|
|
|
if (!(flags & O_CREAT) && (errno == ENOENT)) {
|
2015-03-06 18:01:54 +03:00
|
|
|
pr_info("No %s image\n", path);
|
2015-03-06 18:02:43 +03:00
|
|
|
img->_x.fd = EMPTY_IMG_FD;
|
|
|
|
goto skip_magic;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_perror("Unable to open %s", path);
|
2012-06-28 03:12:08 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:50:13 +04:00
|
|
|
img->_x.fd = ret;
|
|
|
|
if (oflags & O_NOBUF)
|
|
|
|
bfd_setraw(&img->_x);
|
2015-03-10 21:46:57 +03:00
|
|
|
else {
|
|
|
|
if (flags == O_RDONLY)
|
|
|
|
ret = bfdopenr(&img->_x);
|
|
|
|
else
|
|
|
|
ret = bfdopenw(&img->_x);
|
|
|
|
|
|
|
|
if (ret)
|
2015-05-01 16:03:00 +03:00
|
|
|
goto err;
|
2015-03-10 21:46:57 +03:00
|
|
|
}
|
2014-09-29 12:50:13 +04:00
|
|
|
|
2014-09-29 12:47:37 +04:00
|
|
|
if (imgset_template[type].magic == RAW_IMAGE_MAGIC)
|
2012-08-02 07:42:41 +04:00
|
|
|
goto skip_magic;
|
|
|
|
|
2015-04-08 16:36:27 +03:00
|
|
|
if (flags == O_RDONLY)
|
|
|
|
ret = img_check_magic(img, oflags, type, path);
|
|
|
|
else
|
|
|
|
ret = img_write_magic(img, oflags, type);
|
|
|
|
if (ret)
|
2015-05-01 16:03:00 +03:00
|
|
|
goto err;
|
2012-06-28 03:12:08 +04:00
|
|
|
|
2012-08-02 07:42:41 +04:00
|
|
|
skip_magic:
|
2015-05-01 16:03:00 +03:00
|
|
|
return 0;
|
2014-09-29 12:48:53 +04:00
|
|
|
|
2012-06-28 03:12:08 +04:00
|
|
|
err:
|
2015-05-01 16:03:00 +03:00
|
|
|
return -1;
|
2014-09-29 12:48:53 +04:00
|
|
|
}
|
|
|
|
|
2015-03-10 21:47:27 +03:00
|
|
|
int open_image_lazy(struct cr_img *img)
|
|
|
|
{
|
|
|
|
int dfd;
|
|
|
|
char *path = img->path;
|
|
|
|
|
2015-05-01 16:03:00 +03:00
|
|
|
img->path = NULL;
|
|
|
|
|
2015-03-10 21:47:27 +03:00
|
|
|
dfd = get_service_fd(IMG_FD_OFF);
|
2015-05-01 16:03:00 +03:00
|
|
|
if (do_open_image(img, dfd, img->type, img->oflags, path)) {
|
|
|
|
xfree(path);
|
2015-03-10 21:47:27 +03:00
|
|
|
return -1;
|
2015-05-01 16:03:00 +03:00
|
|
|
}
|
2015-03-10 21:47:27 +03:00
|
|
|
|
|
|
|
xfree(path);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
void close_image(struct cr_img *img)
|
|
|
|
{
|
2015-03-10 21:47:27 +03:00
|
|
|
if (lazy_image(img))
|
|
|
|
xfree(img->path);
|
|
|
|
else if (!empty_image(img))
|
2015-03-06 18:02:43 +03:00
|
|
|
bclose(&img->_x);
|
2015-03-10 21:47:27 +03:00
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
xfree(img);
|
|
|
|
}
|
|
|
|
|
|
|
|
struct cr_img *img_from_fd(int fd)
|
|
|
|
{
|
|
|
|
struct cr_img *img;
|
|
|
|
|
|
|
|
img = xmalloc(sizeof(*img));
|
2014-09-29 12:50:13 +04:00
|
|
|
if (img) {
|
|
|
|
img->_x.fd = fd;
|
|
|
|
bfd_setraw(&img->_x);
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
return img;
|
2012-06-28 03:12:08 +04:00
|
|
|
}
|
|
|
|
|
2013-11-15 23:04:27 +04:00
|
|
|
int open_image_dir(char *dir)
|
2012-06-28 03:12:08 +04:00
|
|
|
{
|
2013-01-11 18:16:20 +04:00
|
|
|
int fd, ret;
|
2012-06-28 03:12:08 +04:00
|
|
|
|
2013-11-15 23:04:27 +04:00
|
|
|
fd = open(dir, O_RDONLY);
|
2012-06-28 03:12:08 +04:00
|
|
|
if (fd < 0) {
|
2013-11-15 23:04:27 +04:00
|
|
|
pr_perror("Can't open dir %s", dir);
|
2012-06-28 03:12:08 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-01-11 18:16:20 +04:00
|
|
|
ret = install_service_fd(IMG_FD_OFF, fd);
|
2013-12-21 01:13:31 +04:00
|
|
|
close(fd);
|
|
|
|
fd = ret;
|
2013-01-11 18:16:20 +04:00
|
|
|
|
2013-05-08 15:52:48 +04:00
|
|
|
if (opts.img_parent) {
|
2013-11-18 13:22:10 +04:00
|
|
|
ret = symlinkat(opts.img_parent, fd, CR_PARENT_LINK);
|
2014-01-14 10:45:38 +04:00
|
|
|
if (ret < 0 && errno != EEXIST) {
|
2013-12-12 22:15:00 +04:00
|
|
|
pr_perror("Can't link parent snapshot");
|
2013-04-11 17:50:42 +04:00
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-01-14 10:45:38 +04:00
|
|
|
return 0;
|
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;
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *open_pages_image_at(int dfd, unsigned long flags, struct cr_img *pmi)
|
2013-03-12 21:00:05 +04:00
|
|
|
{
|
|
|
|
unsigned id;
|
|
|
|
|
2013-12-17 19:27:02 +04:00
|
|
|
if (flags == O_RDONLY || flags == O_RDWR) {
|
2013-03-12 21:00:05 +04:00
|
|
|
PagemapHead *h;
|
2014-09-29 12:48:53 +04:00
|
|
|
if (pb_read_one(pmi, &h, PB_PAGEMAP_HEAD) < 0)
|
|
|
|
return NULL;
|
2013-03-12 21:00:05 +04:00
|
|
|
id = h->pages_id;
|
|
|
|
pagemap_head__free_unpacked(h, NULL);
|
|
|
|
} else {
|
|
|
|
PagemapHead h = PAGEMAP_HEAD__INIT;
|
|
|
|
id = h.pages_id = page_ids++;
|
2014-09-29 12:48:53 +04:00
|
|
|
if (pb_write_one(pmi, &h, PB_PAGEMAP_HEAD) < 0)
|
|
|
|
return NULL;
|
2013-03-12 21:00:05 +04:00
|
|
|
}
|
|
|
|
|
2013-04-11 17:49:43 +04:00
|
|
|
return open_image_at(dfd, CR_FD_PAGES, flags, id);
|
|
|
|
}
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
struct cr_img *open_pages_image(unsigned long flags, struct cr_img *pmi)
|
2013-04-11 17:49:43 +04:00
|
|
|
{
|
2014-09-29 12:48:53 +04:00
|
|
|
return open_pages_image_at(get_service_fd(IMG_FD_OFF), flags, pmi);
|
2013-03-12 21:00:05 +04:00
|
|
|
}
|
2014-09-29 12:47:21 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Write buffer @ptr of @size bytes into @fd file
|
|
|
|
* Returns
|
|
|
|
* 0 on success
|
|
|
|
* -1 on error (error message is printed)
|
|
|
|
*/
|
2014-09-29 12:48:53 +04:00
|
|
|
int write_img_buf(struct cr_img *img, const void *ptr, int size)
|
2014-09-29 12:47:21 +04:00
|
|
|
{
|
|
|
|
int ret;
|
2014-09-29 12:48:53 +04:00
|
|
|
|
2014-09-29 12:50:13 +04:00
|
|
|
ret = bwrite(&img->_x, ptr, size);
|
2014-09-29 12:47:21 +04:00
|
|
|
if (ret == size)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
pr_perror("Can't write img file");
|
|
|
|
else
|
|
|
|
pr_err("Img trimmed %d/%d\n", ret, size);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read buffer @ptr of @size bytes from @fd file
|
|
|
|
* Returns
|
|
|
|
* 1 on success
|
|
|
|
* 0 on EOF (silently)
|
|
|
|
* -1 on error (error message is printed)
|
|
|
|
*/
|
2014-09-29 12:48:53 +04:00
|
|
|
int read_img_buf_eof(struct cr_img *img, void *ptr, int size)
|
2014-09-29 12:47:21 +04:00
|
|
|
{
|
|
|
|
int ret;
|
2014-09-29 12:48:53 +04:00
|
|
|
|
2014-09-29 12:50:13 +04:00
|
|
|
ret = bread(&img->_x, ptr, size);
|
2014-09-29 12:47:21 +04:00
|
|
|
if (ret == size)
|
|
|
|
return 1;
|
|
|
|
if (ret == 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (ret < 0)
|
|
|
|
pr_perror("Can't read img file");
|
|
|
|
else
|
|
|
|
pr_err("Img trimmed %d/%d\n", ret, size);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Read buffer @ptr of @size bytes from @fd file
|
|
|
|
* Returns
|
|
|
|
* 1 on success
|
|
|
|
* -1 on error or EOF (error message is printed)
|
|
|
|
*/
|
2014-09-29 12:48:53 +04:00
|
|
|
int read_img_buf(struct cr_img *img, void *ptr, int size)
|
2014-09-29 12:47:21 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
ret = read_img_buf_eof(img, ptr, size);
|
2014-09-29 12:47:21 +04:00
|
|
|
if (ret == 0) {
|
|
|
|
pr_err("Unexpected EOF\n");
|
|
|
|
ret = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* read_img_str -- same as read_img_buf, but allocates memory for
|
|
|
|
* the buffer and puts the '\0' at the end
|
|
|
|
*/
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
int read_img_str(struct cr_img *img, char **pstr, int size)
|
2014-09-29 12:47:21 +04:00
|
|
|
{
|
|
|
|
int ret;
|
|
|
|
char *str;
|
|
|
|
|
|
|
|
str = xmalloc(size + 1);
|
|
|
|
if (!str)
|
|
|
|
return -1;
|
|
|
|
|
2014-09-29 12:48:53 +04:00
|
|
|
ret = read_img_buf(img, str, size);
|
2014-09-29 12:47:21 +04:00
|
|
|
if (ret < 0) {
|
|
|
|
xfree(str);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
str[size] = '\0';
|
|
|
|
*pstr = str;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|