fix an error in a prototype
[sahlberg/remote-cache.git] / migrate / remote-cached.c
1 /*
2    Daemon to recall/cache files requested by remote-cache
3   
4    Copyright Ronnie Sahlberg 2009
5   
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 3 of the License, or
9    (at your option) any later version.
10    
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15    
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, see <http://www.gnu.org/licenses/>.
18 */
19 #include <stdio.h>
20 #include <unistd.h>
21 #include <stdlib.h>
22 #include <stdint.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <signal.h>
26 #include <sys/types.h>
27 #include <sys/stat.h>
28 #include <fcntl.h>
29 #include "../lib/tdb/include/tdb.h"
30 #include "../lib/tdb/common/tdb_private.h"
31 #include "../lib/talloc/talloc.h"
32 #include "../lib/events/events.h"
33 #include "../lib/util/debug.h"
34 #include "migrate.h"
35
36
37 int migrate_files(void)
38 {
39         TALLOC_CTX *mem_ctx = NULL;
40         TDB_DATA hdrkey, pathkey, data;
41         struct migrate_header *mh;
42         struct migrate_entry *me;
43         char *old_path;
44         char *new_path;
45         char *path;
46         char *migrate_cmd;
47         int ret = 0;
48         struct stat old_st;
49         struct stat new_st;
50         struct flock lock;
51         int cache_fd = -1;
52
53         /* Open the migrate db database */
54         open_migrate_db();
55
56         mem_ctx = talloc_new(NULL);
57
58         /* get the header */
59         hdrkey.dptr  = (uint8_t *)discard_const(MIGRATE_HEADER_KEY);
60         hdrkey.dsize = strlen(MIGRATE_HEADER_KEY);
61
62         ret = tdb_lockall(migrate_db);
63         if (ret != 0) {
64                 DEBUG(DEBUG_ERR,(__location__ " Failed to lock migration db in migrate daemon\n"));
65                 ret = -1;
66                 goto finished;
67         }
68
69         data = tdb_fetch(migrate_db, hdrkey);
70         if (data.dptr == NULL) {
71                 DEBUG(DEBUG_INFO,(__location__ " No header structure found.\n"));
72                 ret = -1;
73                 goto finished;
74         }
75
76         mh = talloc_memdup(mem_ctx, data.dptr, data.dsize);
77         free(data.dptr);
78         if (mh == NULL) {
79                 DEBUG(DEBUG_ERR,(__location__ " Failed to allocate copy mh structure in migrate daemon.\n"));
80                 ret = -1;
81                 goto finished;
82         }
83
84         if (mh->last == mh->first) {
85                 DEBUG(DEBUG_ERR,(__location__ " No file to migrate in migrate daemon. First:%d last:%d\n", mh->first, mh->last));
86                 ret = -1;
87                 goto finished;
88         }
89
90         DEBUG(DEBUG_DEBUG,("Migrate header first:%u last:%u\n", mh->first, mh->last));
91
92         pathkey.dptr  = (uint8_t *)&mh->last;
93         pathkey.dsize = sizeof(mh->last);
94         data = tdb_fetch(migrate_db, pathkey);
95         if (data.dptr == NULL) {
96                 DEBUG(DEBUG_INFO,(__location__ " No path structure found for key:%u.\n", mh->last));
97                 ret = -1;
98                 goto finished;
99         }
100
101         me = talloc_memdup(mem_ctx, data.dptr, data.dsize);
102         free(data.dptr);
103         if (me == NULL) {
104                 DEBUG(DEBUG_ERR,(__location__ " Failed to allocate copy me structure in migrate daemon.\n"));
105                 ret = -1;
106                 goto finished;
107         }
108
109         if (data.dsize != offsetof(struct migrate_entry, path) + me->pathlen) {
110           DEBUG(DEBUG_ERR,("Wrong size of me structure. Expected %d bytes but found %d bytes.\n", (int)(offsetof(struct migrate_entry, path) + me->pathlen), (int)data.dsize));
111                 ret = -1;
112                 goto finished;
113         }
114
115         if (mh->last == 0) {
116                 mh->last = mh->max - 1;
117         } else {
118                 mh->last--;
119         }
120
121         data.dptr  = (uint8_t *)mh;
122         data.dsize = sizeof(*mh);
123         ret = tdb_store(migrate_db, hdrkey, data, TDB_REPLACE);
124         if (ret != 0 ){
125                 DEBUG(DEBUG_ERR,(__location__ " Failed to store migration header in migrate daemon\n"));
126                 goto finished;
127         }
128
129
130         /* we no longer need a lock on the database */
131         tdb_unlockall(migrate_db);
132
133         path = talloc_size(mem_ctx, me->pathlen + 1);
134         if (path == NULL) {
135                 DEBUG(DEBUG_ERR,("Failed to allocate path of size:%u\n", me->pathlen+1));
136                 ret = -1;
137                 goto finished;
138         }
139         memcpy(path, me->path, me->pathlen);
140         path[me->pathlen]=0;
141
142         old_path = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
143         new_path = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
144
145         bzero(&old_st, sizeof(old_st));
146         ret = lstat(old_path, &old_st);
147         if (ret != 0) {
148                 DEBUG(DEBUG_ERR,(__location__ " Failed to lstat(%s) old path.\n", old_path));
149                 ret = -1;
150                 goto finished;
151         }
152         bzero(&new_st, sizeof(new_st));
153         lstat(new_path, &new_st);
154         if (new_st.st_mtime == old_st.st_mtime) {
155                 DEBUG(DEBUG_INFO,(__location__ " File %s in cache is still valid. No need to migrate it\n", new_path));
156                 ret = 0;
157                 goto finished;
158         }
159
160
161         /* make sure the file exists */
162         cache_fd = open(new_path, O_RDWR|O_CREAT);
163         if (cache_fd == -1) {
164                 DEBUG(DEBUG_ERR,(__location__ " Failed to create cache file %s, errno:%d\n", new_path, errno));
165                 ret = -errno;
166                 goto finished;
167         }
168         lock.l_type = F_WRLCK;
169         lock.l_whence = SEEK_SET;
170         lock.l_start = 0;
171         lock.l_len = 1;
172         lock.l_pid = getpid();
173         if (fcntl(cache_fd, F_SETLK, &lock) != 0) {
174                 /* someone else is already migrating this file */
175                 DEBUG(DEBUG_DEBUG, (__location__ " Failed to get lock on cache file %s.\n", new_path));
176                 ret = 0;
177                 goto finished;
178         }
179
180         migrate_cmd = talloc_asprintf(mem_ctx, "rsync -ptgo \"%s\" \"%s\"", old_path, new_path);
181         DEBUG(DEBUG_DEBUG,("Running migration command %s\n", migrate_cmd));
182         ret = system(migrate_cmd);
183         if (ret != 0) {
184                 DEBUG(DEBUG_ERR, (__location__ " migration %s -> %s failed\n", old_path, new_path));
185                 ret = -1;
186                 goto finished;
187         }
188
189
190 finished:
191         if (cache_fd != -1) {
192                 close(cache_fd);
193         }
194         tdb_unlockall(migrate_db);
195         talloc_free(mem_ctx);
196         return ret;
197 }
198
199 /* The main remote-cache application writes files to be read to a tdb and
200    then sends us a signal to tell us we have files to process
201 */
202 static void migd_sigusr1_handler(struct event_context *ev, struct signal_event *se, int signum, int count, void *dont_care, void *private_data)
203 {
204         int ret = 0;
205
206         DEBUG(DEBUG_DEBUG,("Start migration of files\n"));
207         while (ret == 0) {
208                 ret = migrate_files();
209         }
210         DEBUG(DEBUG_DEBUG,("No more files to migrate, for now\n"));
211 }
212
213 static void migd_sigusr2_handler(struct event_context *ev, struct signal_event *se, int signum, int count, void *dont_care, void *private_data)
214 {
215         TALLOC_CTX *mem_ctx = talloc_new(NULL);
216         char *cmd;
217         int ret;
218
219         cmd = talloc_asprintf(mem_ctx, "fusermount -u %s\n", export);
220         DEBUG(DEBUG_ERR,("Got SIGUSR2, unmounting fuse filesystem %s\n", export));
221         ret = system(cmd);
222
223         talloc_free(mem_ctx);
224         _exit(10);
225 }
226
227 #define MIGD_PID_KEY "migd_pid"
228
229 static int store_migd_pid(pid_t mypid)
230 {
231         TALLOC_CTX *mem_ctx = NULL;
232         TDB_DATA migdkey, data;
233         int ret = 0;
234
235         /* Open the migrate db database */
236         open_migrate_db();
237
238         mem_ctx = talloc_new(NULL);
239
240         migdkey.dptr  = discard_const(MIGD_PID_KEY);
241         migdkey.dsize = strlen(MIGD_PID_KEY);
242
243         data.dptr  = (uint8_t *)&mypid;
244         data.dsize = sizeof(mypid);
245
246         ret = tdb_lockall(migrate_db);
247         if (ret != 0) {
248                 DEBUG(DEBUG_ERR,(__location__ " Failed to lock migration db in migrate daemon\n"));
249                 ret = -1;
250                 goto finished;
251         }
252
253         ret = tdb_store(migrate_db, migdkey, data, TDB_REPLACE);
254         if (ret != 0 ){
255                 DEBUG(DEBUG_ERR,(__location__ " Failed to store migd pid in migrate daemon\n"));
256                 goto finished;
257         }
258
259 finished:
260         tdb_unlockall(migrate_db);
261         talloc_free(mem_ctx);
262         return ret;
263 }
264
265 pid_t fetch_migd_pid(void)
266 {
267         TALLOC_CTX *mem_ctx = NULL;
268         TDB_DATA migdkey, data;
269         int ret = 0;
270         pid_t migdpid = 0;
271
272         /* Open the migrate db database */
273         open_migrate_db();
274
275         mem_ctx = talloc_new(NULL);
276
277         migdkey.dptr  = discard_const(MIGD_PID_KEY);
278         migdkey.dsize = strlen(MIGD_PID_KEY);
279
280         ret = tdb_lockall(migrate_db);
281         if (ret != 0) {
282                 DEBUG(DEBUG_ERR,(__location__ " Failed to lock migration db in migrate daemon\n"));
283                 goto finished;
284         }
285
286         data = tdb_fetch(migrate_db, migdkey);
287         if (data.dptr == NULL ){
288                 DEBUG(DEBUG_ERR,(__location__ " Failed to fetch migd pid from database\n"));
289                 goto finished;
290         }
291         if (data.dsize != sizeof(migdpid)) {
292                 DEBUG(DEBUG_ERR,("Wrong size for migd pid data\n"));
293                 goto finished;
294         }
295         migdpid = *((pid_t *)data.dptr);
296         free(data.dptr);
297
298 finished:
299         tdb_unlockall(migrate_db);
300         talloc_free(mem_ctx);
301         return migdpid;
302 }
303
304 int start_migration_daemon(void)
305 {
306         TALLOC_CTX *migd;
307         struct event_context *ev;
308         struct signal_event *se;
309         pid_t mypid, cpid;
310
311         talloc_enable_null_tracking();
312
313         mypid = getpid();
314         cpid = fork();
315         if (cpid == -1) {
316                 DEBUG(DEBUG_CRIT,("Failed to fork migration process. Aborting\n"));
317                 return -1;
318         }
319         if (cpid == 0) {
320                 return mypid;
321         }
322
323         migd = talloc_new(NULL);
324         if (migd == NULL) {
325                 DEBUG(DEBUG_CRIT,("Failed to allocate migd. Aborting.\n"));
326                 return -1;
327         }
328
329         /* store out pid in the migration database */
330         if (store_migd_pid(mypid) != 0) {
331                 DEBUG(DEBUG_CRIT,("Failed to store migd pid in database\n"));
332                 return -1;
333         }
334
335
336         ev = event_context_init(NULL);
337
338         DEBUG(DEBUG_NOTICE,("Starting remote-cache migrate daemon, pid:%u\n", mypid));
339
340         /* set up a handler to pick up sigusr1 */
341         se = event_add_signal(ev, migd, SIGUSR1, 0, migd_sigusr1_handler, migd);
342         if (se == NULL) {
343                 DEBUG(DEBUG_CRIT,("Failed to set up signal event handler for SIGUSR1. Aborting\n"));
344                 talloc_free(migd);
345                 return -1;
346         }
347
348         /* make sure we unmount the filesystem when the migration dameon exits */
349         /* set up a handler to pick up sigusr2 */
350         se = event_add_signal(ev, migd, SIGUSR2, 0, migd_sigusr2_handler, migd);
351
352         event_loop_wait(ev);
353         DEBUG(DEBUG_CRIT,("Returned from event loop. This can not happen\n"));
354
355         return mypid;
356 }