2 #include "backuppcd-common.h"
3 #include <libbackuppcd.h>
5 /* XXX: include safety */
11 #define BPC_CLIENT_LIST 0
12 #define BPC_CLIENT_GET_INCR 1
13 #define BPC_CLIENT_GET_FULL 2
15 static char *bpc_hashstr(const unsigned char hash[16]) {
19 for (i = 0; i < 16; i++) {
20 sprintf(ret + (i * 2), "%02x", hash[i]);
26 static char *bpc_poolpath(const char *pooldir, const unsigned char hash[16], int collidx) {
27 static char ret[8192];
31 hashstr = bpc_hashstr(hash);
34 snprintf_ret = snprintf(ret, sizeof(ret), "%s/%s", pooldir, hashstr);
36 snprintf_ret = snprintf(ret, sizeof(ret), "%s/%s_%i", pooldir, hashstr, collidx);
39 if (snprintf_ret >= sizeof(ret)) {
46 static char *bpc_mungepath(const char *path) {
47 static char ret[8192];
48 char *path_cp, *path_cp_s;
49 char *retptr, *tmpbuf;
55 path_cp_s = path_cp = strdup(path);
60 strcat(retptr, "f%2f");
64 for (; (tmpbuf = strsep(&path_cp, "/")) != NULL;) {
65 if (tmpbuf[0] == '\0') {
69 *retptr = '/'; retptr++;
70 *retptr = 'f'; retptr++;
72 strcat(retptr, tmpbuf);
73 retptr += strlen(tmpbuf);
86 static int bpc_fileuptodate(const char *pooldir, const char *datadir, struct bpc_fileinfo *finfo) {
90 ino_t localinode, poolinode;
92 int snprintf_ret, stat_ret;
95 snprintf_ret = snprintf(localfile, sizeof(localfile), "%s/%s", datadir, bpc_mungepath(finfo->name));
96 if (snprintf_ret >= sizeof(localfile)) {
102 * If the local file does not exist, do no further checking.
104 stat_ret = stat(localfile, &stbuf);
110 localinode = stbuf.st_ino;
113 * Iterate through all the available pool files to see if one matches
114 * our local file's inode
116 for (i = -1; i < 0xffff; i++) {
117 poolfile = bpc_poolpath(pooldir, finfo->hash_bpc, i);
119 stat_ret = stat(poolfile, &stbuf);
125 poolinode = stbuf.st_ino;
127 if (poolinode == localinode) {
137 static int bpc_updatenewfilelist(FILE *fp, struct bpc_fileinfo *finfo) {
138 if (fp == NULL || finfo == NULL) {
142 /* XXX: Check to make sure finfo->hash_bpc isn't non-sense */
146 * Print out the required data
148 fprintf(fp, "%s %llu %s\n", bpc_hashstr(finfo->hash_bpc), finfo->size, bpc_mungepath(finfo->name));
153 static int bpc_updatexferlog(FILE *fp, struct bpc_fileinfo *finfo, ...) {
157 static int bpc_updateattrib(const char *pathname, struct bpc_fileinfo *finfo) {
159 static char *lastdir = NULL;
161 char pathnameparent[16384], attribfile[16384], *tmp;
165 if (pathname == NULL || finfo == NULL) {
169 pathname_len = strlen(pathname) + 1;
171 if (pathname_len >= sizeof(pathnameparent)) {
175 memcpy(pathnameparent, pathname, pathname_len);
177 tmp = strrchr(pathnameparent, '/');
186 if (strcmp(lastdir, pathnameparent) == 0) {
192 snprintf_ret = snprintf(attribfile, sizeof(attribfile), "%s/attrib", lastdir);
193 if (snprintf_ret >= sizeof(attribfile)) {
204 lastdir = strdup(pathnameparent);
205 fp = fopen(attribfile, "w");
208 /* XXX: Write to attrib file */
213 static int print_help(const char *msg) {
215 fprintf(stderr, "%s\n", msg);
221 int main(int argc, char **argv) {
222 BPC_CONN *conn1, *conn2 = NULL;
223 struct bpc_fileinfo *finfo = NULL;
224 char *host = NULL, *command, *username = "anonymous", *password = NULL;
225 char localfile[16384];
227 int port = BPC_TCP_PORT;
230 char *run_curr = "new", *run_last = NULL;
233 char type_string[][7] = {"dir", "file", "syml", "sock", "fifo", "blk", "chr", "hrdl"};
234 char *pooldir = NULL;
235 char *datadir = NULL;
236 char lastdir[16384], currdir[16384];
237 char newfilelistname[16384], xferfilename[16384];
238 FILE *newfilelistfp = NULL;
240 #ifdef HAVE_LIBCONFIG
241 lc_register_var("Host", LC_VAR_STRING, &host, 'H');
242 lc_register_var("Port", LC_VAR_INT, &port, 'P');
243 lc_register_var("User", LC_VAR_STRING, &username, 'U');
244 lc_register_var("Pass", LC_VAR_STRING, &password, 'p');
245 lc_register_var("Pool", LC_VAR_STRING, &pooldir, 'S');
246 lc_register_var("DataDir", LC_VAR_STRING, &datadir, 'D');
247 lc_register_var("LastRun", LC_VAR_STRING, &run_last, 'r');
248 lc_register_var("CurrRun", LC_VAR_STRING, &run_curr, 'R');
250 lc_ret = lc_process(argc, argv, "backuppcdc", LC_CONF_SPACE, NULL);
255 fprintf(stderr, "Error processing configuration: %s\n", lc_geterrstr());
256 return(EXIT_FAILURE);
260 print_help("Host is required");
261 return(EXIT_FAILURE);
263 if (password == NULL) {
264 print_help("Password is required");
265 return(EXIT_FAILURE);
268 print_help("Port is required");
269 return(EXIT_FAILURE);
271 if (argc == lc_optind) {
272 print_help("Command is required");
273 return(EXIT_FAILURE);
276 command = argv[lc_optind];
279 if (strcasecmp(command, "list") == 0) {
280 mode = BPC_CLIENT_LIST;
281 } else if (strcasecmp(command, "get") == 0) {
282 mode = BPC_CLIENT_GET_INCR;
283 } else if (strcasecmp(command, "getfull") == 0) {
284 mode = BPC_CLIENT_GET_FULL;
286 fprintf(stderr, "Invalid operation: %s\n", command);
287 return(EXIT_FAILURE);
291 case BPC_CLIENT_GET_INCR:
292 if (run_last == NULL) {
293 print_help("Last Run is required");
294 return(EXIT_FAILURE);
296 if (pooldir == NULL) {
297 print_help("PoolDir is required");
298 return(EXIT_FAILURE);
301 case BPC_CLIENT_GET_FULL:
302 if (datadir == NULL) {
303 print_help("DataDir is required");
304 return(EXIT_FAILURE);
307 if (run_last != NULL) {
308 snprintf(lastdir, sizeof(lastdir), "%s/%s", datadir, run_last);
310 snprintf(currdir, sizeof(currdir), "%s/%s", datadir, run_curr);
311 snprintf(newfilelistname, sizeof(newfilelistname), "%s/NewFileList", datadir);
312 snprintf(xferfilename, sizeof(xferfilename), "%s/XferLOG", datadir);
313 newfilelistfp = fopen(newfilelistname, "w");
316 conn1 = bpc_connect(host, port, username, password);
318 fprintf(stderr, "Failed (connect)\n");
319 return(EXIT_FAILURE);
326 case BPC_CLIENT_LIST:
327 ret = bpc_list_open(conn1, "/", 1, BPC_HASH_NONE, NULL, NULL);
329 case BPC_CLIENT_GET_INCR:
330 ret = bpc_list_open(conn1, "/", 1, BPC_HASH_BPC, NULL, NULL);
332 conn2 = bpc_connect(host, port, username, password);
334 fprintf(stderr, "Failed (connect)\n");
335 return(EXIT_FAILURE);
338 case BPC_CLIENT_GET_FULL:
339 ret = bpc_get_open(conn1, "/", 1, BPC_HASH_NONE, NULL, NULL);
344 fprintf(stderr, "Failed (open)\n");
345 return(EXIT_FAILURE);
349 * Process every entry.
353 case BPC_CLIENT_LIST:
354 finfo = bpc_list(conn1);
356 case BPC_CLIENT_GET_INCR:
357 finfo = bpc_list(conn1);
359 case BPC_CLIENT_GET_FULL:
360 finfo = bpc_get_head(conn1);
365 printf("--- end ---\n");
369 printf("[%4s] %06o %6lu %6lu %10llu %12lu (%s) %s",
370 type_string[finfo->type],
371 (unsigned int) finfo->mode,
372 (unsigned long) finfo->uid,
373 (unsigned long) finfo->gid,
374 (unsigned long long) finfo->size,
375 (unsigned long) finfo->mtime,
376 bpc_hashstr(finfo->hash_bpc),
378 if (finfo->type == BPC_FILE_SYMLINK || finfo->type == BPC_FILE_HRDLINK) {
379 printf(" -> %s", finfo->linkdest);
383 if (mode == BPC_CLIENT_LIST) {
387 snprintf_ret = snprintf(localfile, sizeof(localfile), "%s/%s", currdir, bpc_mungepath(finfo->name));
388 if (snprintf_ret < 0 || snprintf_ret >= sizeof(localfile)) {
389 PRINTERR("Filename too long. Something is almost definitely wrong, aborting.");
396 case BPC_CLIENT_GET_INCR:
397 if (finfo->type == BPC_FILE_DIR) {
398 backuppc_mkdir(localfile);
404 bpc_updateattrib(currdir, finfo);
406 if (finfo->type != BPC_FILE_REG) {
411 * Check to see if the file is up-to-date
413 uptodate = bpc_fileuptodate(pooldir, lastdir, finfo);
415 /* If so, don't copy it again. */
422 bpc_updatenewfilelist(newfilelistfp, finfo);
425 SPOTVAR_S(finfo->name);
426 ret = bpc_get_open(conn2, finfo->name, 0, BPC_HASH_NONE, NULL, NULL);
434 finfo = bpc_get_head(conn2);
437 ret = bpc_get_close(conn2);
442 ret = bpc_copyfile(conn2, finfo, localfile, 0);
447 finfo = bpc_get_head(conn2);
453 ret = bpc_get_close(conn2);
456 case BPC_CLIENT_GET_FULL:
457 ret = bpc_copyfile(conn1, finfo, localfile, 0);
464 printf("---- failed during file copy ----\n");
473 case BPC_CLIENT_LIST:
474 ret = bpc_list_close(conn1);
476 case BPC_CLIENT_GET_INCR:
477 ret = bpc_list_close(conn1);
479 case BPC_CLIENT_GET_FULL:
480 ret = bpc_get_close(conn1);
485 fprintf(stderr, "Failed (close).\n");
486 return(EXIT_FAILURE);
489 bpc_disconnect(conn1);
491 bpc_disconnect(conn2);
494 fprintf(stderr, "Done.\n");
495 return(EXIT_SUCCESS);