criu/criu/fsnotify.c
Pavel Tikhomirov 8cfda2748c log: remove all uses of %m specifier in pr_* functions
As our pr_* functions are complex and can call different system calls
inside before actual printing (e.g. gettimeofday for timestamps) actual
errno at the time of printing may be changed.

Let's just use %s + strerror(errno) instead of %m with pr_* functions to
be explicit that errno to string transformation happens before calling
anything else.

Note: tcp_repair_off is called from pie with no pr_perror defined due to
CR_NOGLIBC set and if I use errno variable there I get "Unexpected
undefined symbol: `__errno_location'. External symbol in PIE?", so it
seems there is no way to print errno there, so let's just skip it.

Signed-off-by: Pavel Tikhomirov <ptikhomirov@virtuozzo.com>
2023-04-15 21:17:21 -07:00

908 lines
21 KiB
C

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <signal.h>
#include <string.h>
#include <utime.h>
#include <limits.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/inotify.h>
#include <linux/magic.h>
#include <sys/wait.h>
#include <poll.h>
#include <sys/mman.h>
#include <sys/mount.h>
#include <aio.h>
#include <sys/fanotify.h>
#include "common/compiler.h"
#include "imgset.h"
#include "fsnotify.h"
#include "fdinfo.h"
#include "mount.h"
#include "filesystems.h"
#include "image.h"
#include "util.h"
#include "crtools.h"
#include "files.h"
#include "files-reg.h"
#include "file-ids.h"
#include "criu-log.h"
#include "kerndat.h"
#include "common/list.h"
#include "common/lock.h"
#include "irmap.h"
#include "cr_options.h"
#include "namespaces.h"
#include "pstree.h"
#include "fault-injection.h"
#include <compel/plugins/std/syscall-codes.h>
#include "protobuf.h"
#include "images/fsnotify.pb-c.h"
#include "images/mnt.pb-c.h"
#undef LOG_PREFIX
#define LOG_PREFIX "fsnotify: "
struct fsnotify_mark_info {
struct list_head list;
union {
InotifyWdEntry *iwe;
FanotifyMarkEntry *fme;
};
struct pprep_head prep; /* XXX union with remap */
struct file_remap *remap;
};
struct fsnotify_file_info {
union {
InotifyFileEntry *ife;
FanotifyFileEntry *ffe;
};
struct list_head marks;
struct file_desc d;
};
/* File handle */
typedef struct {
u32 bytes;
u32 type;
u64 __handle[16];
} fh_t;
/* Checks if file descriptor @lfd is inotify */
int is_inotify_link(char *link)
{
return is_anon_link_type(link, "inotify");
}
/* Checks if file descriptor @lfd is fanotify */
int is_fanotify_link(char *link)
{
return is_anon_link_type(link, "[fanotify]");
}
static void decode_handle(fh_t *handle, FhEntry *img)
{
memzero(handle, sizeof(*handle));
handle->type = img->type;
handle->bytes = img->bytes;
memcpy(handle->__handle, img->handle, min(pb_repeated_size(img, handle), sizeof(handle->__handle)));
}
static int open_by_handle(void *arg, int fd, int pid)
{
return syscall(__NR_open_by_handle_at, fd, arg, O_PATH);
}
enum { ERR_NO_MOUNT = -1, ERR_NO_PATH_IN_MOUNT = -2, ERR_GENERIC = -3 };
static char *alloc_openable(unsigned int s_dev, unsigned long i_ino, FhEntry *f_handle)
{
struct mount_info *m;
fh_t handle;
int fd = -1;
char *path;
char suitable_mount_found = 0;
decode_handle(&handle, f_handle);
/*
* We gonna try to open the handle and then
* depending on command line options and type
* of the filesystem (tmpfs/devtmpfs do not
* preserve their inodes between mounts) we
* might need to find out an openable path
* get used on restore as a watch destination.
*/
for (m = mntinfo; m; m = m->next) {
char buf[PATH_MAX], *__path;
int mntfd, openable_fd;
struct stat st;
if (m->s_dev != s_dev)
continue;
if (!mnt_is_dir(m))
continue;
mntfd = __open_mountpoint(m);
pr_debug("\t\tTrying via mntid %d root %s ns_mountpoint @%s (%d)\n", m->mnt_id, m->root,
m->ns_mountpoint, mntfd);
if (mntfd < 0)
continue;
fd = userns_call(open_by_handle, UNS_FDOUT, &handle, sizeof(handle), mntfd);
close(mntfd);
if (fd < 0)
continue;
suitable_mount_found = 1;
if (read_fd_link(fd, buf, sizeof(buf)) < 0) {
close(fd);
goto err;
}
close(fd);
/*
* Convert into a relative path.
*/
__path = (buf[1] != '\0') ? buf + 1 : ".";
pr_debug("\t\t\tlink as %s\n", __path);
mntfd = mntns_get_root_fd(m->nsid);
if (mntfd < 0)
goto err;
openable_fd = openat(mntfd, __path, O_PATH);
if (openable_fd >= 0) {
if (fstat(openable_fd, &st)) {
pr_perror("Can't stat on %s", __path);
close(openable_fd);
goto err;
}
close(openable_fd);
pr_debug("\t\t\topenable (inode %s) as %s\n", st.st_ino == i_ino ? "match" : "don't match",
__path);
if (st.st_ino == i_ino) {
path = xstrdup(buf);
if (path == NULL)
return ERR_PTR(ERR_GENERIC);
if (root_ns_mask & CLONE_NEWNS) {
f_handle->has_mnt_id = true;
f_handle->mnt_id = m->mnt_id;
}
return path;
}
} else
pr_debug("\t\t\tnot openable as %s (%s)\n", __path, strerror(errno));
}
err:
if (suitable_mount_found)
return ERR_PTR(ERR_NO_PATH_IN_MOUNT);
return ERR_PTR(ERR_NO_MOUNT);
}
static int open_handle(unsigned int s_dev, unsigned long i_ino, FhEntry *f_handle)
{
struct mount_info *m;
int mntfd, fd = -1;
fh_t handle;
decode_handle(&handle, f_handle);
pr_debug("Opening fhandle %x:%llx...\n", s_dev, (unsigned long long)handle.__handle[0]);
for (m = mntinfo; m; m = m->next) {
if (m->s_dev != s_dev || !mnt_is_dir(m))
continue;
mntfd = __open_mountpoint(m);
if (mntfd < 0) {
pr_warn("Can't open mount for s_dev %x, continue\n", s_dev);
continue;
}
fd = userns_call(open_by_handle, UNS_FDOUT, &handle, sizeof(handle), mntfd);
if (fd >= 0) {
close(mntfd);
goto out;
}
close(mntfd);
}
out:
return fd;
}
int check_open_handle(unsigned int s_dev, unsigned long i_ino, FhEntry *f_handle)
{
char *path, *irmap_path;
struct mount_info *mi;
if (fault_injected(FI_CHECK_OPEN_HANDLE))
goto fault;
/*
* Always try to fetch watchee path first. There are several reasons:
*
* - tmpfs/devtmps do not save inode numbers between mounts,
* so it is critical to have the complete path under our
* hands for restore purpose;
*
* - in case of migration the inodes might be changed as well
* so the only portable solution is to carry the whole path
* to the watchee inside image.
*/
path = alloc_openable(s_dev, i_ino, f_handle);
if (!IS_ERR_OR_NULL(path)) {
pr_debug("\tHandle 0x%x:0x%lx is openable\n", s_dev, i_ino);
goto out;
} else if (IS_ERR(path) && PTR_ERR(path) == ERR_NO_MOUNT) {
goto fault;
} else if (IS_ERR(path) && PTR_ERR(path) == ERR_GENERIC) {
goto err;
}
mi = lookup_mnt_sdev(s_dev);
if (mi == NULL) {
pr_err("Unable to lookup a mount by dev 0x%x\n", s_dev);
goto err;
}
if ((mi->fstype->code == FSTYPE__TMPFS) || (mi->fstype->code == FSTYPE__DEVTMPFS)) {
pr_err("Can't find suitable path for handle (dev %#x ino %#lx): %d\n", s_dev, i_ino,
(int)PTR_ERR(path));
goto err;
}
if (!opts.force_irmap)
/*
* If we're not forced to do irmap, then
* say we have no path for watch. Otherwise
* do irmap scan even if the handle is
* working.
*
* FIXME -- no need to open-by-handle if
* we are in force-irmap and not on tempfs
*/
goto out_nopath;
fault:
pr_warn("\tHandle 0x%x:0x%lx cannot be opened\n", s_dev, i_ino);
irmap_path = irmap_lookup(s_dev, i_ino);
if (!irmap_path) {
pr_err("\tCan't dump that handle\n");
return -1;
}
path = xstrdup(irmap_path);
if (!path)
goto err;
out:
pr_debug("\tDumping %s as path for handle\n", path);
f_handle->path = path;
out_nopath:
return 0;
err:
return -1;
}
static int check_one_wd(InotifyWdEntry *we)
{
pr_info("wd: wd %#08x s_dev %#08x i_ino %#16" PRIx64 " mask %#08x\n", we->wd, we->s_dev, we->i_ino, we->mask);
pr_info("\t[fhandle] bytes %#08x type %#08x __handle %#016" PRIx64 ":%#016" PRIx64 "\n", we->f_handle->bytes,
we->f_handle->type, we->f_handle->handle[0], we->f_handle->handle[1]);
if (we->mask & KERNEL_FS_EVENT_ON_CHILD)
pr_warn_once("\t\tDetected FS_EVENT_ON_CHILD bit "
"in mask (will be ignored on restore)\n");
if (check_open_handle(we->s_dev, we->i_ino, we->f_handle))
return -1;
return 0;
}
static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p)
{
FileEntry fe = FILE_ENTRY__INIT;
InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT;
int exit_code = -1, i, ret;
ret = fd_has_data(lfd);
if (ret < 0)
return -1;
else if (ret > 0)
pr_warn("The %#08x inotify events will be dropped\n", id);
ie.id = id;
ie.flags = p->flags;
ie.fown = (FownEntry *)&p->fown;
if (parse_fdinfo(lfd, FD_TYPES__INOTIFY, &ie))
goto free;
for (i = 0; i < ie.n_wd; i++)
if (check_one_wd(ie.wd[i]))
goto free;
fe.type = FD_TYPES__INOTIFY;
fe.id = ie.id;
fe.ify = &ie;
pr_info("id %#08x flags %#08x\n", ie.id, ie.flags);
if (pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fe, PB_FILE))
goto free;
exit_code = 0;
free:
for (i = 0; i < ie.n_wd; i++)
xfree(ie.wd[i]);
xfree(ie.wd);
return exit_code;
}
static int pre_dump_one_inotify(int pid, int lfd)
{
InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT;
int i;
if (parse_fdinfo_pid(pid, lfd, FD_TYPES__INOTIFY, &ie))
return -1;
for (i = 0; i < ie.n_wd; i++) {
InotifyWdEntry *we = ie.wd[i];
if (irmap_queue_cache(we->s_dev, we->i_ino, we->f_handle))
return -1;
xfree(we);
}
return 0;
}
const struct fdtype_ops inotify_dump_ops = {
.type = FD_TYPES__INOTIFY,
.dump = dump_one_inotify,
.pre_dump = pre_dump_one_inotify,
};
static int check_one_mark(FanotifyMarkEntry *fme)
{
if (fme->type == MARK_TYPE__INODE) {
BUG_ON(!fme->ie);
pr_info("mark: s_dev %#08x i_ino %#016" PRIx64 " mask %#08x\n", fme->s_dev, fme->ie->i_ino, fme->mask);
pr_info("\t[fhandle] bytes %#08x type %#08x __handle %#016" PRIx64 ":%#016" PRIx64 "\n",
fme->ie->f_handle->bytes, fme->ie->f_handle->type, fme->ie->f_handle->handle[0],
fme->ie->f_handle->handle[1]);
if (check_open_handle(fme->s_dev, fme->ie->i_ino, fme->ie->f_handle))
return -1;
}
if (fme->type == MARK_TYPE__MOUNT) {
struct mount_info *m;
BUG_ON(!fme->me);
m = lookup_mnt_id(fme->me->mnt_id);
if (!m) {
pr_err("Can't find mnt_id 0x%x\n", fme->me->mnt_id);
return -1;
}
if (!(root_ns_mask & CLONE_NEWNS))
fme->me->path = m->ns_mountpoint + 1;
fme->s_dev = m->s_dev;
pr_info("mark: s_dev %#08x mnt_id %#08x mask %#08x\n", fme->s_dev, fme->me->mnt_id, fme->mask);
}
return 0;
}
static int dump_one_fanotify(int lfd, u32 id, const struct fd_parms *p)
{
FileEntry fle = FILE_ENTRY__INIT;
FanotifyFileEntry fe = FANOTIFY_FILE_ENTRY__INIT;
int ret = -1, i;
ret = fd_has_data(lfd);
if (ret < 0)
return -1;
else if (ret > 0)
pr_warn("The %#08x fanotify events will be dropped\n", id);
ret = -1;
fe.id = id;
fe.flags = p->flags;
fe.fown = (FownEntry *)&p->fown;
if (parse_fdinfo(lfd, FD_TYPES__FANOTIFY, &fe) < 0)
goto free;
for (i = 0; i < fe.n_mark; i++)
if (check_one_mark(fe.mark[i]))
goto free;
pr_info("id %#08x flags %#08x\n", fe.id, fe.flags);
fle.type = FD_TYPES__FANOTIFY;
fle.id = fe.id;
fle.ffy = &fe;
ret = pb_write_one(img_from_set(glob_imgset, CR_FD_FILES), &fle, PB_FILE);
free:
for (i = 0; i < fe.n_mark; i++)
xfree(fe.mark[i]);
xfree(fe.mark);
return ret;
}
static int pre_dump_one_fanotify(int pid, int lfd)
{
FanotifyFileEntry fe = FANOTIFY_FILE_ENTRY__INIT;
int i;
if (parse_fdinfo_pid(pid, lfd, FD_TYPES__FANOTIFY, &fe))
return -1;
for (i = 0; i < fe.n_mark; i++) {
FanotifyMarkEntry *me = fe.mark[i];
if (me->type == MARK_TYPE__INODE && irmap_queue_cache(me->s_dev, me->ie->i_ino, me->ie->f_handle))
return -1;
xfree(me);
}
xfree(fe.mark);
return 0;
}
const struct fdtype_ops fanotify_dump_ops = {
.type = FD_TYPES__FANOTIFY,
.dump = dump_one_fanotify,
.pre_dump = pre_dump_one_fanotify,
};
static char *get_mark_path(const char *who, struct file_remap *remap, FhEntry *f_handle, unsigned long i_ino,
unsigned int s_dev, char *buf, int *target)
{
char *path = NULL;
if (remap) {
int mntns_root;
mntns_root = mntns_get_root_by_mnt_id(remap->rmnt_id);
pr_debug("\t\tRestore %s watch for %#08x:%#016lx (via %s)\n", who, s_dev, i_ino, remap->rpath);
*target = openat(mntns_root, remap->rpath, O_PATH);
} else if (f_handle->path) {
int mntns_root;
char *path = ".";
uint32_t mnt_id = f_handle->has_mnt_id ? f_handle->mnt_id : -1;
/* irmap cache is collected in the root namespaces. */
mntns_root = mntns_get_root_by_mnt_id(mnt_id);
/* change "/foo" into "foo" and "/" into "." */
if (f_handle->path[1] != '\0')
path = f_handle->path + 1;
pr_debug("\t\tRestore with path hint %d:%s\n", mnt_id, path);
*target = openat(mntns_root, path, O_PATH);
} else
*target = open_handle(s_dev, i_ino, f_handle);
if (*target < 0) {
pr_perror("Unable to open %s", f_handle->path);
goto err;
}
/*
* fanotify/inotify open syscalls want path to attach
* watch to. But the only thing we have is an FD obtained
* via fhandle. Fortunately, when trying to attach the
* /proc/pid/fd/ link, we will watch the inode the link
* points to, i.e. -- just what we want.
*/
sprintf(buf, "/proc/self/fd/%d", *target);
path = buf;
if (!pr_quelled(LOG_DEBUG)) {
char link[PATH_MAX];
if (read_fd_link(*target, link, sizeof(link)) < 0)
link[0] = '\0';
pr_debug("\t\tRestore %s watch for %#08x:%#016lx (via %s -> %s)\n", who, s_dev, i_ino, path, link);
}
err:
return path;
}
static int restore_one_inotify(int inotify_fd, struct fsnotify_mark_info *info)
{
InotifyWdEntry *iwe = info->iwe;
int ret = -1, target = -1;
char buf[PSFDS], *path;
uint32_t mask;
path = get_mark_path("inotify", info->remap, iwe->f_handle, iwe->i_ino, iwe->s_dev, buf, &target);
if (!path)
goto err;
mask = iwe->mask & IN_ALL_EVENTS;
if (iwe->mask & ~IN_ALL_EVENTS) {
pr_info("\t\tfilter event mask %#x -> %#x\n", iwe->mask, mask);
}
if (kdat.has_inotify_setnextwd) {
if (ioctl(inotify_fd, INOTIFY_IOC_SETNEXTWD, iwe->wd)) {
pr_perror("Can't set next inotify wd");
return -1;
}
}
while (1) {
int wd;
wd = inotify_add_watch(inotify_fd, path, mask);
if (wd < 0) {
pr_perror("Can't add watch for 0x%x with 0x%x", inotify_fd, iwe->wd);
break;
} else if (wd == iwe->wd) {
ret = 0;
break;
} else if (wd > iwe->wd) {
pr_err("Unsorted watch 0x%x found for 0x%x with 0x%x\n", wd, inotify_fd, iwe->wd);
break;
}
if (kdat.has_inotify_setnextwd)
return -1;
inotify_rm_watch(inotify_fd, wd);
}
err:
close_safe(&target);
return ret;
}
static int restore_one_fanotify(int fd, struct fsnotify_mark_info *mark)
{
FanotifyMarkEntry *fme = mark->fme;
unsigned int flags = FAN_MARK_ADD;
int ret = -1, target = -1;
char buf[PSFDS], *path = NULL;
if (fme->type == MARK_TYPE__MOUNT) {
struct mount_info *m;
int mntns_root;
char *p = fme->me->path;
struct ns_id *nsid = NULL;
if (root_ns_mask & CLONE_NEWNS) {
m = lookup_mnt_id(fme->me->mnt_id);
if (!m) {
pr_err("Can't find mount mnt_id 0x%x\n", fme->me->mnt_id);
return -1;
}
nsid = m->nsid;
p = m->ns_mountpoint;
}
mntns_root = mntns_get_root_fd(nsid);
target = openat(mntns_root, p, O_PATH);
if (target == -1) {
pr_perror("Unable to open %s", p);
goto err;
}
flags |= FAN_MARK_MOUNT;
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", target);
path = buf;
} else if (fme->type == MARK_TYPE__INODE) {
path = get_mark_path("fanotify", mark->remap, fme->ie->f_handle, fme->ie->i_ino, fme->s_dev, buf,
&target);
if (!path)
goto err;
} else {
pr_err("Bad fsnotify mark type 0x%x\n", fme->type);
goto err;
}
flags |= fme->mflags;
if (mark->fme->mask) {
ret = fanotify_mark(fd, flags, fme->mask, AT_FDCWD, path);
if (ret) {
pr_err("Adding fanotify mask 0x%x on 0x%x/%s failed (%d)\n", fme->mask, fme->id, path, ret);
goto err;
}
}
if (fme->ignored_mask) {
ret = fanotify_mark(fd, flags | FAN_MARK_IGNORED_MASK, fme->ignored_mask, AT_FDCWD, path);
if (ret) {
pr_err("Adding fanotify ignored-mask 0x%x on 0x%x/%s failed (%d)\n", fme->ignored_mask, fme->id,
path, ret);
goto err;
}
}
err:
close_safe(&target);
return ret;
}
static int open_inotify_fd(struct file_desc *d, int *new_fd)
{
struct fsnotify_file_info *info;
struct fsnotify_mark_info *wd_info;
int tmp;
info = container_of(d, struct fsnotify_file_info, d);
tmp = inotify_init1(info->ife->flags);
if (tmp < 0) {
pr_perror("Can't create inotify for %#08x", info->ife->id);
return -1;
}
list_for_each_entry(wd_info, &info->marks, list) {
pr_info("\tRestore 0x%x wd for %#08x\n", wd_info->iwe->wd, wd_info->iwe->id);
if (restore_one_inotify(tmp, wd_info)) {
close_safe(&tmp);
return -1;
}
pr_info("\t 0x%x wd for %#08x is restored\n", wd_info->iwe->wd, wd_info->iwe->id);
}
if (restore_fown(tmp, info->ife->fown))
close_safe(&tmp);
*new_fd = tmp;
return 0;
}
static int open_fanotify_fd(struct file_desc *d, int *new_fd)
{
struct fsnotify_file_info *info;
struct fsnotify_mark_info *mark;
unsigned int flags = 0;
int ret;
info = container_of(d, struct fsnotify_file_info, d);
flags = info->ffe->faflags;
if (info->ffe->flags & O_CLOEXEC)
flags |= FAN_CLOEXEC;
if (info->ffe->flags & O_NONBLOCK)
flags |= FAN_NONBLOCK;
ret = fanotify_init(flags, info->ffe->evflags);
if (ret < 0) {
pr_perror("Can't init fanotify mark (%d)", ret);
return -1;
}
list_for_each_entry(mark, &info->marks, list) {
pr_info("\tRestore fanotify for %#08x\n", mark->fme->id);
if (restore_one_fanotify(ret, mark)) {
close_safe(&ret);
return -1;
}
}
if (restore_fown(ret, info->ffe->fown))
close_safe(&ret);
*new_fd = ret;
return 0;
}
static struct file_desc_ops inotify_desc_ops = {
.type = FD_TYPES__INOTIFY,
.open = open_inotify_fd,
};
static struct file_desc_ops fanotify_desc_ops = {
.type = FD_TYPES__FANOTIFY,
.open = open_fanotify_fd,
};
static int inotify_resolve_remap(struct pprep_head *ph)
{
struct fsnotify_mark_info *m;
m = container_of(ph, struct fsnotify_mark_info, prep);
m->remap = lookup_ghost_remap(m->iwe->s_dev, m->iwe->i_ino);
return 0;
}
static int fanotify_resolve_remap(struct pprep_head *ph)
{
struct fsnotify_mark_info *m;
m = container_of(ph, struct fsnotify_mark_info, prep);
m->remap = lookup_ghost_remap(m->fme->s_dev, m->fme->ie->i_ino);
return 0;
}
static int __collect_inotify_mark(struct fsnotify_file_info *p, struct fsnotify_mark_info *mark)
{
struct fsnotify_mark_info *m;
/*
* We should put marks in wd ascending order. See comment
* in restore_one_inotify() for explanation.
*/
list_for_each_entry(m, &p->marks, list)
if (m->iwe->wd > mark->iwe->wd)
break;
list_add_tail(&mark->list, &m->list);
mark->prep.actor = inotify_resolve_remap;
add_post_prepare_cb(&mark->prep);
return 0;
}
static int __collect_fanotify_mark(struct fsnotify_file_info *p, struct fsnotify_mark_info *mark)
{
list_add(&mark->list, &p->marks);
if (mark->fme->type == MARK_TYPE__INODE) {
mark->prep.actor = fanotify_resolve_remap;
add_post_prepare_cb(&mark->prep);
}
return 0;
}
static int collect_one_inotify(void *o, ProtobufCMessage *msg, struct cr_img *img)
{
struct fsnotify_file_info *info = o;
int i;
info->ife = pb_msg(msg, InotifyFileEntry);
INIT_LIST_HEAD(&info->marks);
pr_info("Collected id %#08x flags %#08x\n", info->ife->id, info->ife->flags);
for (i = 0; i < info->ife->n_wd; i++) {
struct fsnotify_mark_info *mark;
mark = xmalloc(sizeof(*mark));
if (!mark)
return -1;
mark->iwe = info->ife->wd[i];
INIT_LIST_HEAD(&mark->list);
mark->remap = NULL;
if (__collect_inotify_mark(info, mark))
return -1;
}
return file_desc_add(&info->d, info->ife->id, &inotify_desc_ops);
}
struct collect_image_info inotify_cinfo = {
.fd_type = CR_FD_INOTIFY_FILE,
.pb_type = PB_INOTIFY_FILE,
.priv_size = sizeof(struct fsnotify_file_info),
.collect = collect_one_inotify,
};
static int collect_one_fanotify(void *o, ProtobufCMessage *msg, struct cr_img *img)
{
struct fsnotify_file_info *info = o;
int i;
info->ffe = pb_msg(msg, FanotifyFileEntry);
INIT_LIST_HEAD(&info->marks);
pr_info("Collected id %#08x flags %#08x\n", info->ffe->id, info->ffe->flags);
for (i = 0; i < info->ffe->n_mark; i++) {
struct fsnotify_mark_info *mark;
mark = xmalloc(sizeof(*mark));
if (!mark)
return -1;
mark->fme = info->ffe->mark[i];
INIT_LIST_HEAD(&mark->list);
mark->remap = NULL;
if (__collect_fanotify_mark(info, mark))
return -1;
}
return file_desc_add(&info->d, info->ffe->id, &fanotify_desc_ops);
}
struct collect_image_info fanotify_cinfo = {
.fd_type = CR_FD_FANOTIFY_FILE,
.pb_type = PB_FANOTIFY_FILE,
.priv_size = sizeof(struct fsnotify_file_info),
.collect = collect_one_fanotify,
};
static int collect_one_inotify_mark(void *o, ProtobufCMessage *msg, struct cr_img *i)
{
struct fsnotify_mark_info *mark = o;
struct file_desc *d;
if (!deprecated_ok("separate images for fsnotify marks"))
return -1;
mark->iwe = pb_msg(msg, InotifyWdEntry);
INIT_LIST_HEAD(&mark->list);
mark->remap = NULL;
/*
* The kernel prior 4.3 might export internal event
* mask bits which are not part of user-space API. It
* is fixed in kernel but we have to keep backward
* compatibility with old images. So mask out
* inappropriate bits (in particular fdinfo might
* have FS_EVENT_ON_CHILD bit set).
*/
mark->iwe->mask &= ~KERNEL_FS_EVENT_ON_CHILD;
d = find_file_desc_raw(FD_TYPES__INOTIFY, mark->iwe->id);
if (!d) {
pr_err("Can't find inotify with id %#08x\n", mark->iwe->id);
return -1;
}
return __collect_inotify_mark(container_of(d, struct fsnotify_file_info, d), mark);
}
struct collect_image_info inotify_mark_cinfo = {
.fd_type = CR_FD_INOTIFY_WD,
.pb_type = PB_INOTIFY_WD,
.priv_size = sizeof(struct fsnotify_mark_info),
.collect = collect_one_inotify_mark,
};
static int collect_one_fanotify_mark(void *o, ProtobufCMessage *msg, struct cr_img *i)
{
struct fsnotify_mark_info *mark = o;
struct file_desc *d;
if (!deprecated_ok("separate images for fsnotify marks"))
return -1;
mark->fme = pb_msg(msg, FanotifyMarkEntry);
INIT_LIST_HEAD(&mark->list);
mark->remap = NULL;
d = find_file_desc_raw(FD_TYPES__FANOTIFY, mark->fme->id);
if (!d) {
pr_err("Can't find fanotify with id %#08x\n", mark->fme->id);
return -1;
}
return __collect_fanotify_mark(container_of(d, struct fsnotify_file_info, d), mark);
}
struct collect_image_info fanotify_mark_cinfo = {
.fd_type = CR_FD_FANOTIFY_MARK,
.pb_type = PB_FANOTIFY_MARK,
.priv_size = sizeof(struct fsnotify_mark_info),
.collect = collect_one_fanotify_mark,
};