Branch data Line data Source code
1 : : #include <unistd.h>
2 : : #include <stdio.h>
3 : : #include <stdlib.h>
4 : : #include <errno.h>
5 : : #include <fcntl.h>
6 : : #include <stdlib.h>
7 : : #include <signal.h>
8 : : #include <string.h>
9 : : #include <utime.h>
10 : : #include <dirent.h>
11 : : #include <limits.h>
12 : : #include <sys/stat.h>
13 : : #include <sys/types.h>
14 : : #include <sys/inotify.h>
15 : : #include <sys/vfs.h>
16 : : #include <sys/wait.h>
17 : : #include <sys/poll.h>
18 : : #include <sys/mman.h>
19 : : #include <sys/mount.h>
20 : : #include <aio.h>
21 : :
22 : : #include "compiler.h"
23 : : #include "types.h"
24 : : #include "inotify.h"
25 : : #include "proc_parse.h"
26 : : #include "syscall.h"
27 : : #include "crtools.h"
28 : : #include "mount.h"
29 : : #include "image.h"
30 : : #include "util.h"
31 : : #include "files.h"
32 : : #include "files-reg.h"
33 : : #include "file-ids.h"
34 : : #include "log.h"
35 : : #include "list.h"
36 : : #include "lock.h"
37 : :
38 : : #include "protobuf.h"
39 : : #include "protobuf/inotify.pb-c.h"
40 : :
41 : : #undef LOG_PREFIX
42 : : #define LOG_PREFIX "fsnotify: "
43 : :
44 : : struct inotify_wd_info {
45 : : struct list_head list;
46 : : InotifyWdEntry *iwe;
47 : : struct file_remap *remap;
48 : : };
49 : :
50 : : struct inotify_file_info {
51 : : struct list_head list;
52 : : InotifyFileEntry *ife;
53 : : struct list_head marks;
54 : : struct file_desc d;
55 : : };
56 : :
57 : : static LIST_HEAD(info_head);
58 : :
59 : : /* Checks if file desciptor @lfd is inotify */
60 : 4 : int is_inotify_link(int lfd)
61 : : {
62 : 4 : return is_anon_link_type(lfd, "inotify");
63 : : }
64 : :
65 : 0 : void show_inotify_wd(int fd_inotify_wd, struct cr_options *o)
66 : : {
67 : 0 : pb_show_plain(fd_inotify_wd, PB_INOTIFY_WD);
68 : 0 : }
69 : :
70 : 0 : void show_inotify(int fd_inotify, struct cr_options *o)
71 : : {
72 : 0 : pb_show_plain(fd_inotify, PB_INOTIFY);
73 : 0 : }
74 : :
75 : 4 : static int dump_inotify_entry(union fdinfo_entries *e, void *arg)
76 : : {
77 : 4 : InotifyWdEntry *we = &e->ify;
78 : :
79 : 4 : we->id = *(u32 *)arg;
80 : 4 : pr_info("wd: wd 0x%08x s_dev 0x%08x i_ino 0x%16lx mask 0x%08x\n",
81 : : we->wd, we->s_dev, we->i_ino, we->mask);
82 : 4 : pr_info("\t[fhandle] bytes 0x%08x type 0x%08x __handle 0x%016lx:0x%016lx\n",
83 : : we->f_handle->bytes, we->f_handle->type,
84 : : we->f_handle->handle[0], we->f_handle->handle[1]);
85 : 4 : return pb_write_one(fdset_fd(glob_fdset, CR_FD_INOTIFY_WD), we, PB_INOTIFY_WD);
86 : : }
87 : :
88 : 2 : static int dump_one_inotify(int lfd, u32 id, const struct fd_parms *p)
89 : : {
90 : 2 : InotifyFileEntry ie = INOTIFY_FILE_ENTRY__INIT;
91 : :
92 : 2 : ie.id = id;
93 : 2 : ie.flags = p->flags;
94 : 2 : ie.fown = (FownEntry *)&p->fown;
95 : :
96 : 2 : pr_info("id 0x%08x flags 0x%08x\n", ie.id, ie.flags);
97 [ + - ]: 2 : if (pb_write_one(fdset_fd(glob_fdset, CR_FD_INOTIFY), &ie, PB_INOTIFY))
98 : : return -1;
99 : :
100 : 2 : return parse_fdinfo(lfd, FD_TYPES__INOTIFY, dump_inotify_entry, &id);
101 : : }
102 : :
103 : : static const struct fdtype_ops inotify_ops = {
104 : : .type = FD_TYPES__INOTIFY,
105 : : .dump = dump_one_inotify,
106 : : };
107 : :
108 : 2 : int dump_inotify(struct fd_parms *p, int lfd, const struct cr_fdset *set)
109 : : {
110 : 2 : return do_dump_gen_file(p, lfd, &inotify_ops, set);
111 : : }
112 : :
113 : 4 : static int restore_one_inotify(int inotify_fd, struct inotify_wd_info *info)
114 : : {
115 : 4 : InotifyWdEntry *iwe = info->iwe;
116 : 4 : char buf[32], *path = buf;
117 : 4 : int mntfd = -1, ret = -1;
118 : 4 : int wd, target = -1;
119 : 4 : fh_t handle = { };
120 : :
121 : : /* syscall waits for strict structure here */
122 : 4 : handle.type = iwe->f_handle->type;
123 : 4 : handle.bytes = iwe->f_handle->bytes;
124 : :
125 : 4 : memcpy(handle.__handle, iwe->f_handle->handle,
126 : 4 : min(pb_repeated_size(iwe->f_handle, handle),
127 : : sizeof(handle.__handle)));
128 : :
129 : 4 : mntfd = open_mount(iwe->s_dev);
130 [ - + ]: 4 : if (mntfd < 0) {
131 : 0 : pr_err("Mount root for 0x%08x not found\n", iwe->s_dev);
132 : : return -1;
133 : : }
134 : :
135 [ + + ]: 4 : if (!info->remap) {
136 : 2 : target = sys_open_by_handle_at(mntfd, (void *)&handle, 0);
137 [ - + ]: 2 : if (target < 0) {
138 : 0 : pr_perror("Can't open file handle for 0x%08x:0x%016lx",
139 : : iwe->s_dev, iwe->i_ino);
140 : : goto err;
141 : : }
142 : 2 : snprintf(buf, sizeof(buf), "/proc/self/fd/%d", target);
143 : : } else
144 : 2 : path = info->remap->path;
145 : :
146 : 4 : pr_debug("\t\tRestore watch for 0x%08x:0x%016lx\n", iwe->s_dev, iwe->i_ino);
147 : :
148 : : /*
149 : : * FIXME The kernel allocates wd-s sequentially,
150 : : * this is suboptimal, but the kernel doesn't
151 : : * provide and API for this yet :(
152 : : */
153 : 4 : wd = 1;
154 [ + - ]: 4 : while (wd >= 0) {
155 : 4 : wd = inotify_add_watch(inotify_fd, path, iwe->mask);
156 [ - + ]: 4 : if (wd < 0) {
157 : 0 : pr_err("Can't add watch for %d with %d\n", inotify_fd, iwe->wd);
158 : : break;
159 [ - + ]: 4 : } else if (wd == iwe->wd) {
160 : : ret = 0;
161 : : break;
162 [ # # ]: 0 : } else if (wd > iwe->wd) {
163 : 0 : pr_err("Usorted watch found for %d with %d\n", inotify_fd, iwe->wd);
164 : : break;
165 : : }
166 : :
167 : 0 : pr_debug("\t\tWatch got %d but %d expected\n", wd, iwe->wd);
168 : 0 : inotify_rm_watch(inotify_fd, wd);
169 : : }
170 : :
171 [ + + ]: 4 : if (info->remap)
172 : 2 : remap_put(info->remap);
173 : :
174 : : err:
175 : 4 : close_safe(&mntfd);
176 : 4 : close_safe(&target);
177 : : return ret;
178 : : }
179 : :
180 : 2 : static int open_inotify_fd(struct file_desc *d)
181 : : {
182 : : struct inotify_file_info *info;
183 : : struct inotify_wd_info *wd_info;
184 : : int tmp;
185 : :
186 : 2 : info = container_of(d, struct inotify_file_info, d);
187 : :
188 : 2 : tmp = inotify_init1(info->ife->flags);
189 [ - + ]: 2 : if (tmp < 0) {
190 : 0 : pr_perror("Can't create inotify for 0x%08x", info->ife->id);
191 : : return -1;
192 : : }
193 : :
194 [ + + ]: 6 : list_for_each_entry(wd_info, &info->marks, list) {
195 : 4 : pr_info("\tRestore inotify for 0x%08x\n", wd_info->iwe->id);
196 [ - + ]: 4 : if (restore_one_inotify(tmp, wd_info)) {
197 : 0 : close_safe(&tmp);
198 : 0 : break;
199 : : }
200 : : }
201 : :
202 [ - + ]: 2 : if (restore_fown(tmp, info->ife->fown))
203 : 0 : close_safe(&tmp);
204 : :
205 : 2 : return tmp;
206 : : }
207 : :
208 : : static struct file_desc_ops desc_ops = {
209 : : .type = FD_TYPES__INOTIFY,
210 : : .open = open_inotify_fd,
211 : : };
212 : :
213 : 6 : static int collect_mark(struct inotify_wd_info *mark)
214 : : {
215 : : struct inotify_file_info *p;
216 : :
217 [ + - ]: 6 : list_for_each_entry(p, &info_head, list) {
218 [ + - ]: 6 : if (p->ife->id == mark->iwe->id) {
219 : 6 : list_add(&mark->list, &p->marks);
220 : 6 : mark->remap = lookup_ghost_remap(mark->iwe->s_dev, mark->iwe->i_ino);
221 : 6 : return 0;
222 : : }
223 : : }
224 : :
225 : 0 : pr_err("Can't find inotify with id 0x%08x\n", mark->iwe->id);
226 : 6 : return -1;
227 : : }
228 : :
229 : 3 : static int collect_one_ify(void *o, ProtobufCMessage *msg)
230 : : {
231 : 3 : struct inotify_file_info *info = o;
232 : :
233 : 3 : info->ife = pb_msg(msg, InotifyFileEntry);
234 : 3 : INIT_LIST_HEAD(&info->marks);
235 : 3 : list_add(&info->list, &info_head);
236 : 3 : file_desc_add(&info->d, info->ife->id, &desc_ops);
237 : 3 : pr_info("Collected id 0x%08x flags 0x%08x\n", info->ife->id, info->ife->flags);
238 : :
239 : 3 : return 0;
240 : : }
241 : :
242 : 6 : static int collect_one_wd(void *o, ProtobufCMessage *msg)
243 : : {
244 : 6 : struct inotify_wd_info *mark = o;
245 : :
246 : 6 : mark->iwe = pb_msg(msg, InotifyWdEntry);
247 : 6 : return collect_mark(mark);
248 : : }
249 : :
250 : 355 : int collect_inotify(void)
251 : : {
252 : : int ret;
253 : :
254 : 355 : ret = collect_image(CR_FD_INOTIFY, PB_INOTIFY,
255 : : sizeof(struct inotify_file_info), collect_one_ify);
256 [ + - ]: 355 : if (!ret)
257 : 355 : ret = collect_image(CR_FD_INOTIFY_WD, PB_INOTIFY_WD,
258 : : sizeof(struct inotify_wd_info), collect_one_wd);
259 : :
260 : 355 : return ret;
261 : 8 : }
|