2012-05-04 13:38:00 +04:00
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <utime.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <limits.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/inotify.h>
|
|
|
|
#include <sys/vfs.h>
|
|
|
|
#include <sys/wait.h>
|
|
|
|
#include <sys/poll.h>
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <aio.h>
|
|
|
|
|
|
|
|
#include "compiler.h"
|
2013-01-09 17:02:47 +04:00
|
|
|
#include "asm/types.h"
|
2012-05-04 13:38:00 +04:00
|
|
|
#include "inotify.h"
|
2012-07-11 09:35:36 +04:00
|
|
|
#include "proc_parse.h"
|
2012-05-04 13:38:00 +04:00
|
|
|
#include "syscall.h"
|
|
|
|
#include "crtools.h"
|
|
|
|
#include "mount.h"
|
|
|
|
#include "image.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "files.h"
|
2012-12-06 11:11:19 +04:00
|
|
|
#include "files-reg.h"
|
2012-05-04 13:38:00 +04:00
|
|
|
#include "file-ids.h"
|
|
|
|
#include "log.h"
|
|
|
|
#include "list.h"
|
|
|
|
#include "lock.h"
|
|
|
|
|
2012-07-17 07:25:42 +04:00
|
|
|
#include "protobuf.h"
|
|
|
|
#include "protobuf/inotify.pb-c.h"
|
|
|
|
|
2012-08-20 15:14:57 +04:00
|
|
|
#undef LOG_PREFIX
|
|
|
|
#define LOG_PREFIX "fsnotify: "
|
|
|
|
|
2012-05-04 13:38:00 +04:00
|
|
|
struct inotify_wd_info {
|
|
|
|
struct list_head list;
|
2012-07-17 07:25:42 +04:00
|
|
|
InotifyWdEntry *iwe;
|
2012-12-06 11:11:19 +04:00
|
|
|
struct file_remap *remap;
|
2012-05-04 13:38:00 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
struct inotify_file_info {
|
|
|
|
struct list_head list;
|
2012-07-17 07:25:42 +04:00
|
|
|
InotifyFileEntry *ife;
|
2012-05-04 13:38:00 +04:00
|
|
|
struct list_head marks;
|
|
|
|
struct file_desc d;
|
|
|
|
};
|
|
|
|
|
|
|
|
static LIST_HEAD(info_head);
|
|
|
|
|
|
|
|
/* Checks if file desciptor @lfd is inotify */
|
|
|
|
int is_inotify_link(int lfd)
|
|
|
|
{
|
2012-05-04 14:22:18 +04:00
|
|
|
return is_anon_link_type(lfd, "inotify");
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void show_inotify_wd(int fd_inotify_wd, struct cr_options *o)
|
|
|
|
{
|
2012-08-07 02:51:34 +04:00
|
|
|
pb_show_plain(fd_inotify_wd, PB_INOTIFY_WD);
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void show_inotify(int fd_inotify, struct cr_options *o)
|
|
|
|
{
|
2012-08-07 02:51:34 +04:00
|
|
|
pb_show_plain(fd_inotify, PB_INOTIFY);
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
|
2012-07-11 09:35:36 +04:00
|
|
|
static int dump_inotify_entry(union fdinfo_entries *e, void *arg)
|
2012-05-04 13:38:00 +04:00
|
|
|
{
|
2012-07-17 07:25:42 +04:00
|
|
|
InotifyWdEntry *we = &e->ify;
|
2012-07-11 09:35:36 +04:00
|
|
|
|
|
|
|
we->id = *(u32 *)arg;
|
2012-08-20 15:14:57 +04:00
|
|
|
pr_info("wd: wd 0x%08x s_dev 0x%08x i_ino 0x%16lx mask 0x%08x\n",
|
2012-07-11 09:35:36 +04:00
|
|
|
we->wd, we->s_dev, we->i_ino, we->mask);
|
|
|
|
pr_info("\t[fhandle] bytes 0x%08x type 0x%08x __handle 0x%016lx:0x%016lx\n",
|
2012-07-17 07:25:42 +04:00
|
|
|
we->f_handle->bytes, we->f_handle->type,
|
|
|
|
we->f_handle->handle[0], we->f_handle->handle[1]);
|
2012-08-07 02:26:50 +04:00
|
|
|
return pb_write_one(fdset_fd(glob_fdset, CR_FD_INOTIFY_WD), we, PB_INOTIFY_WD);
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
|
2012-05-04 15:34:55 +04:00
|
|
|
static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p)
|
2012-05-04 13:38:00 +04:00
|
|
|
{
|
2012-07-17 07:25:42 +04:00
|
|
|
InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT;
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-07-11 09:35:36 +04:00
|
|
|
ie.id = id;
|
|
|
|
ie.flags = p->flags;
|
2012-07-19 09:39:00 +04:00
|
|
|
ie.fown = (FownEntry *)&p->fown;
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-08-20 15:14:57 +04:00
|
|
|
pr_info("id 0x%08x flags 0x%08x\n", ie.id, ie.flags);
|
2012-08-07 02:26:50 +04:00
|
|
|
if (pb_write_one(fdset_fd(glob_fdset, CR_FD_INOTIFY), &ie, PB_INOTIFY))
|
2012-05-04 13:38:00 +04:00
|
|
|
return -1;
|
|
|
|
|
2012-07-19 10:18:37 +04:00
|
|
|
return parse_fdinfo(lfd, FD_TYPES__INOTIFY, dump_inotify_entry, &id);
|
2012-05-04 13:38:00 +04:00
|
|
|
}
|
|
|
|
|
2012-05-04 15:34:55 +04:00
|
|
|
static const struct fdtype_ops inotify_ops = {
|
2012-07-19 10:18:37 +04:00
|
|
|
.type = FD_TYPES__INOTIFY,
|
2012-05-04 15:34:55 +04:00
|
|
|
.dump = dump_one_inotify,
|
|
|
|
};
|
|
|
|
|
2013-01-11 13:22:41 +04:00
|
|
|
int dump_inotify(struct fd_parms *p, int lfd, const int fdinfo)
|
2012-05-04 15:34:55 +04:00
|
|
|
{
|
2013-01-11 13:22:41 +04:00
|
|
|
return do_dump_gen_file(p, lfd, &inotify_ops, fdinfo);
|
2012-05-04 15:34:55 +04:00
|
|
|
}
|
|
|
|
|
2012-12-06 11:11:19 +04:00
|
|
|
static int restore_one_inotify(int inotify_fd, struct inotify_wd_info *info)
|
2012-05-04 13:38:00 +04:00
|
|
|
{
|
2012-12-06 11:11:19 +04:00
|
|
|
InotifyWdEntry *iwe = info->iwe;
|
|
|
|
char buf[32], *path = buf;
|
2012-11-29 18:12:16 +04:00
|
|
|
int mntfd = -1, ret = -1;
|
|
|
|
int wd, target = -1;
|
2012-07-17 07:25:42 +04:00
|
|
|
fh_t handle = { };
|
|
|
|
|
|
|
|
/* syscall waits for strict structure here */
|
|
|
|
handle.type = iwe->f_handle->type;
|
|
|
|
handle.bytes = iwe->f_handle->bytes;
|
|
|
|
|
|
|
|
memcpy(handle.__handle, iwe->f_handle->handle,
|
|
|
|
min(pb_repeated_size(iwe->f_handle, handle),
|
|
|
|
sizeof(handle.__handle)));
|
2012-05-04 13:38:00 +04:00
|
|
|
|
|
|
|
mntfd = open_mount(iwe->s_dev);
|
|
|
|
if (mntfd < 0) {
|
|
|
|
pr_err("Mount root for 0x%08x not found\n", iwe->s_dev);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-12-06 11:11:19 +04:00
|
|
|
if (!info->remap) {
|
|
|
|
target = sys_open_by_handle_at(mntfd, (void *)&handle, 0);
|
|
|
|
if (target < 0) {
|
|
|
|
pr_perror("Can't open file handle for 0x%08x:0x%016lx",
|
|
|
|
iwe->s_dev, iwe->i_ino);
|
|
|
|
goto err;
|
|
|
|
}
|
|
|
|
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", target);
|
|
|
|
} else
|
|
|
|
path = info->remap->path;
|
2012-05-04 13:38:00 +04:00
|
|
|
|
|
|
|
pr_debug("\t\tRestore watch for 0x%08x:0x%016lx\n", iwe->s_dev, iwe->i_ino);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME The kernel allocates wd-s sequentially,
|
|
|
|
* this is suboptimal, but the kernel doesn't
|
|
|
|
* provide and API for this yet :(
|
|
|
|
*/
|
|
|
|
wd = 1;
|
|
|
|
while (wd >= 0) {
|
|
|
|
wd = inotify_add_watch(inotify_fd, path, iwe->mask);
|
|
|
|
if (wd < 0) {
|
|
|
|
pr_err("Can't add watch for %d with %d\n", inotify_fd, iwe->wd);
|
|
|
|
break;
|
|
|
|
} else if (wd == iwe->wd) {
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
} else if (wd > iwe->wd) {
|
|
|
|
pr_err("Usorted watch found for %d with %d\n", inotify_fd, iwe->wd);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
pr_debug("\t\tWatch got %d but %d expected\n", wd, iwe->wd);
|
|
|
|
inotify_rm_watch(inotify_fd, wd);
|
|
|
|
}
|
|
|
|
|
2012-12-06 11:11:19 +04:00
|
|
|
if (info->remap)
|
|
|
|
remap_put(info->remap);
|
|
|
|
|
2012-11-29 18:12:16 +04:00
|
|
|
err:
|
|
|
|
close_safe(&mntfd);
|
|
|
|
close_safe(&target);
|
2012-05-04 13:38:00 +04:00
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int open_inotify_fd(struct file_desc *d)
|
|
|
|
{
|
|
|
|
struct inotify_file_info *info;
|
|
|
|
struct inotify_wd_info *wd_info;
|
|
|
|
int tmp;
|
|
|
|
|
|
|
|
info = container_of(d, struct inotify_file_info, d);
|
|
|
|
|
2012-07-10 02:50:00 +04:00
|
|
|
tmp = inotify_init1(info->ife->flags);
|
2012-05-04 13:38:00 +04:00
|
|
|
if (tmp < 0) {
|
2012-07-10 02:50:00 +04:00
|
|
|
pr_perror("Can't create inotify for 0x%08x", info->ife->id);
|
2012-05-04 13:38:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
list_for_each_entry(wd_info, &info->marks, list) {
|
2012-07-10 02:50:00 +04:00
|
|
|
pr_info("\tRestore inotify for 0x%08x\n", wd_info->iwe->id);
|
2012-12-06 11:11:19 +04:00
|
|
|
if (restore_one_inotify(tmp, wd_info)) {
|
2012-05-04 13:38:00 +04:00
|
|
|
close_safe(&tmp);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-19 09:39:00 +04:00
|
|
|
if (restore_fown(tmp, info->ife->fown))
|
2012-05-04 13:38:00 +04:00
|
|
|
close_safe(&tmp);
|
|
|
|
|
|
|
|
return tmp;
|
|
|
|
}
|
|
|
|
|
|
|
|
static struct file_desc_ops desc_ops = {
|
2012-07-19 10:18:37 +04:00
|
|
|
.type = FD_TYPES__INOTIFY,
|
2012-05-04 13:38:00 +04:00
|
|
|
.open = open_inotify_fd,
|
|
|
|
};
|
|
|
|
|
|
|
|
static int collect_mark(struct inotify_wd_info *mark)
|
|
|
|
{
|
|
|
|
struct inotify_file_info *p;
|
|
|
|
|
|
|
|
list_for_each_entry(p, &info_head, list) {
|
2012-07-10 02:50:00 +04:00
|
|
|
if (p->ife->id == mark->iwe->id) {
|
2012-05-04 13:38:00 +04:00
|
|
|
list_add(&mark->list, &p->marks);
|
2012-12-06 11:11:19 +04:00
|
|
|
mark->remap = lookup_ghost_remap(mark->iwe->s_dev, mark->iwe->i_ino);
|
2012-05-04 13:38:00 +04:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
pr_err("Can't find inotify with id 0x%08x\n", mark->iwe->id);
|
2012-05-04 13:38:00 +04:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
static int collect_one_ify(void *o, ProtobufCMessage *msg)
|
2012-05-04 13:38:00 +04:00
|
|
|
{
|
2012-08-09 13:16:46 +04:00
|
|
|
struct inotify_file_info *info = o;
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
info->ife = pb_msg(msg, InotifyFileEntry);
|
|
|
|
INIT_LIST_HEAD(&info->marks);
|
|
|
|
list_add(&info->list, &info_head);
|
|
|
|
file_desc_add(&info->d, info->ife->id, &desc_ops);
|
2012-08-20 15:14:57 +04:00
|
|
|
pr_info("Collected id 0x%08x flags 0x%08x\n", info->ife->id, info->ife->flags);
|
2012-07-24 10:22:37 +04:00
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
return 0;
|
|
|
|
}
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
static int collect_one_wd(void *o, ProtobufCMessage *msg)
|
|
|
|
{
|
|
|
|
struct inotify_wd_info *mark = o;
|
2012-07-10 02:50:00 +04:00
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
mark->iwe = pb_msg(msg, InotifyWdEntry);
|
|
|
|
return collect_mark(mark);
|
|
|
|
}
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
int collect_inotify(void)
|
|
|
|
{
|
|
|
|
int ret;
|
2012-05-04 13:38:00 +04:00
|
|
|
|
2012-08-09 13:16:46 +04:00
|
|
|
ret = collect_image(CR_FD_INOTIFY, PB_INOTIFY,
|
|
|
|
sizeof(struct inotify_file_info), collect_one_ify);
|
|
|
|
if (!ret)
|
|
|
|
ret = collect_image(CR_FD_INOTIFY_WD, PB_INOTIFY_WD,
|
|
|
|
sizeof(struct inotify_wd_info), collect_one_wd);
|
2012-05-04 13:38:00 +04:00
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|