2 Daemon to recall/cache files requested by remote-cache
4 Copyright Ronnie Sahlberg 2009
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.
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.
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/>.
26 #include <sys/types.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"
37 int migrate_files(void)
39 TALLOC_CTX *mem_ctx = NULL;
40 TDB_DATA hdrkey, pathkey, data;
41 struct migrate_header *mh;
42 struct migrate_entry *me;
53 /* Open the migrate db database */
56 mem_ctx = talloc_new(NULL);
59 hdrkey.dptr = (uint8_t *)discard_const(MIGRATE_HEADER_KEY);
60 hdrkey.dsize = strlen(MIGRATE_HEADER_KEY);
62 ret = tdb_lockall(migrate_db);
64 DEBUG(DEBUG_ERR,(__location__ " Failed to lock migration db in migrate daemon\n"));
69 data = tdb_fetch(migrate_db, hdrkey);
70 if (data.dptr == NULL) {
71 DEBUG(DEBUG_INFO,(__location__ " No header structure found.\n"));
76 mh = talloc_memdup(mem_ctx, data.dptr, data.dsize);
79 DEBUG(DEBUG_ERR,(__location__ " Failed to allocate copy mh structure in migrate daemon.\n"));
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));
90 DEBUG(DEBUG_DEBUG,("Migrate header first:%u last:%u\n", mh->first, mh->last));
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));
101 me = talloc_memdup(mem_ctx, data.dptr, data.dsize);
104 DEBUG(DEBUG_ERR,(__location__ " Failed to allocate copy me structure in migrate daemon.\n"));
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));
116 mh->last = mh->max - 1;
121 data.dptr = (uint8_t *)mh;
122 data.dsize = sizeof(*mh);
123 ret = tdb_store(migrate_db, hdrkey, data, TDB_REPLACE);
125 DEBUG(DEBUG_ERR,(__location__ " Failed to store migration header in migrate daemon\n"));
130 /* we no longer need a lock on the database */
131 tdb_unlockall(migrate_db);
133 path = talloc_size(mem_ctx, me->pathlen + 1);
135 DEBUG(DEBUG_ERR,("Failed to allocate path of size:%u\n", me->pathlen+1));
139 memcpy(path, me->path, me->pathlen);
142 old_path = talloc_asprintf(mem_ctx, "%s/%s", remote, path);
143 new_path = talloc_asprintf(mem_ctx, "%s/%s", cache, path);
145 bzero(&old_st, sizeof(old_st));
146 ret = lstat(old_path, &old_st);
148 DEBUG(DEBUG_ERR,(__location__ " Failed to lstat(%s) old path.\n", old_path));
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));
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));
168 lock.l_type = F_WRLCK;
169 lock.l_whence = SEEK_SET;
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));
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);
184 DEBUG(DEBUG_ERR, (__location__ " migration %s -> %s failed\n", old_path, new_path));
191 if (cache_fd != -1) {
194 tdb_unlockall(migrate_db);
195 talloc_free(mem_ctx);
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
202 static void migd_sigusr1_handler(struct event_context *ev, struct signal_event *se, int signum, int count, void *dont_care, void *private_data)
206 DEBUG(DEBUG_DEBUG,("Start migration of files\n"));
208 ret = migrate_files();
210 DEBUG(DEBUG_DEBUG,("No more files to migrate, for now\n"));
213 static void migd_sigusr2_handler(struct event_context *ev, struct signal_event *se, int signum, int count, void *dont_care, void *private_data)
215 TALLOC_CTX *mem_ctx = talloc_new(NULL);
219 cmd = talloc_asprintf(mem_ctx, "fusermount -u %s\n", export);
220 DEBUG(DEBUG_ERR,("Got SIGUSR2, unmounting fuse filesystem %s\n", export));
223 talloc_free(mem_ctx);
227 #define MIGD_PID_KEY "migd_pid"
229 static int store_migd_pid(pid_t mypid)
231 TALLOC_CTX *mem_ctx = NULL;
232 TDB_DATA migdkey, data;
235 /* Open the migrate db database */
238 mem_ctx = talloc_new(NULL);
240 migdkey.dptr = discard_const(MIGD_PID_KEY);
241 migdkey.dsize = strlen(MIGD_PID_KEY);
243 data.dptr = (uint8_t *)&mypid;
244 data.dsize = sizeof(mypid);
246 ret = tdb_lockall(migrate_db);
248 DEBUG(DEBUG_ERR,(__location__ " Failed to lock migration db in migrate daemon\n"));
253 ret = tdb_store(migrate_db, migdkey, data, TDB_REPLACE);
255 DEBUG(DEBUG_ERR,(__location__ " Failed to store migd pid in migrate daemon\n"));
260 tdb_unlockall(migrate_db);
261 talloc_free(mem_ctx);
265 pid_t fetch_migd_pid(void)
267 TALLOC_CTX *mem_ctx = NULL;
268 TDB_DATA migdkey, data;
272 /* Open the migrate db database */
275 mem_ctx = talloc_new(NULL);
277 migdkey.dptr = discard_const(MIGD_PID_KEY);
278 migdkey.dsize = strlen(MIGD_PID_KEY);
280 ret = tdb_lockall(migrate_db);
282 DEBUG(DEBUG_ERR,(__location__ " Failed to lock migration db in migrate daemon\n"));
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"));
291 if (data.dsize != sizeof(migdpid)) {
292 DEBUG(DEBUG_ERR,("Wrong size for migd pid data\n"));
295 migdpid = *((pid_t *)data.dptr);
299 tdb_unlockall(migrate_db);
300 talloc_free(mem_ctx);
304 int start_migration_daemon(void)
307 struct event_context *ev;
308 struct signal_event *se;
311 talloc_enable_null_tracking();
316 DEBUG(DEBUG_CRIT,("Failed to fork migration process. Aborting\n"));
323 migd = talloc_new(NULL);
325 DEBUG(DEBUG_CRIT,("Failed to allocate migd. Aborting.\n"));
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"));
336 ev = event_context_init(NULL);
338 DEBUG(DEBUG_NOTICE,("Starting remote-cache migrate daemon, pid:%u\n", mypid));
340 /* set up a handler to pick up sigusr1 */
341 se = event_add_signal(ev, migd, SIGUSR1, 0, migd_sigusr1_handler, migd);
343 DEBUG(DEBUG_CRIT,("Failed to set up signal event handler for SIGUSR1. Aborting\n"));
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);
353 DEBUG(DEBUG_CRIT,("Returned from event loop. This can not happen\n"));