2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-1998 University of Maryland at College Park
6 * Permission to use, copy, modify, distribute, and sell this software and its
7 * documentation for any purpose is hereby granted without fee, provided that
8 * the above copyright notice appear in all copies and that both that
9 * copyright notice and this permission notice appear in supporting
10 * documentation, and that the name of U.M. not be used in advertising or
11 * publicity pertaining to distribution of the software without specific,
12 * written prior permission. U.M. makes no representations about the
13 * suitability of this software for any purpose. It is provided "as is"
14 * without express or implied warranty.
16 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
18 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
19 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
20 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
21 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
23 * Authors: the Amanda Development Team. Its members are listed in a
24 * file named AUTHORS, in the root directory of this distribution.
27 * $Id: client_util.c,v 1.32 2006/03/09 16:51:41 martinea Exp $
31 #include "client_util.h"
35 #define MAXMAXDUMPS 16
37 static char *fixup_relative(name, device)
43 char *dirname = amname_to_dirname(device);
44 newname = vstralloc(dirname, "/", name , NULL);
48 newname = stralloc(name);
54 static char *get_name(diskname, exin, t, n)
55 char *diskname, *exin;
59 char number[NUM_STR_SIZE];
63 ts = construct_timestamp(&t);
67 snprintf(number, sizeof(number), "%03d", n - 1);
69 filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
76 static char *build_name(disk, exin, verbose)
81 char *filename = NULL;
82 char *afilename = NULL;
89 char *test_name = NULL;
90 int match_len, d_name_len;
94 diskname = sanitise_filename(disk);
96 dbgdir = stralloc2(AMANDA_TMPDIR, "/");
97 if((d = opendir(AMANDA_TMPDIR)) == NULL) {
98 error("open debug directory \"%s\": %s",
99 AMANDA_TMPDIR, strerror(errno));
101 test_name = get_name(diskname, exin,
102 curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
103 match_len = strlen(get_pname()) + strlen(diskname) + 2;
104 while((entry = readdir(d)) != NULL) {
105 if(is_dot_or_dotdot(entry->d_name)) {
108 d_name_len = strlen(entry->d_name);
109 if(strncmp(test_name, entry->d_name, match_len) != 0
110 || d_name_len < match_len + 14 + 8
111 || strcmp(entry->d_name+ d_name_len - 7, exin) != 0) {
112 continue; /* not one of our files */
114 if(strcmp(entry->d_name, test_name) < 0) {
115 e = newvstralloc(e, dbgdir, entry->d_name, NULL);
116 (void) unlink(e); /* get rid of old file */
125 filename = get_name(diskname, exin, curtime, n);
126 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
127 if((fd=open(afilename, O_WRONLY|O_CREAT|O_EXCL|O_APPEND, 0600)) < 0){
135 } while(!afilename && n < 1000);
137 if(afilename == NULL) {
138 filename = get_name(diskname, exin, curtime, 0);
139 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
140 dbprintf(("%s: Cannot create '%s'\n", debug_prefix(NULL), afilename));
142 printf("ERROR [cannot create: %s]\n", afilename);
154 static int add_exclude(file_exclude, aexc, verbose)
162 if(aexc[l-1] == '\n') {
166 fprintf(file_exclude, "%s\n", aexc);
170 static int add_include(disk, device, file_include, ainc, verbose)
180 if(ainc[l-1] == '\n') {
185 dbprintf(("%s: include must be at least 3 character long: %s\n",
186 debug_prefix(NULL), ainc));
188 printf("ERROR [include must be at least 3 character long: %s]\n", ainc);
191 else if(ainc[0] != '.' && ainc[0] != '\0' && ainc[1] != '/') {
192 dbprintf(("%s: include must start with './': %s\n",
193 debug_prefix(NULL), ainc));
195 printf("ERROR [include must start with './': %s]\n", ainc);
199 char *incname = ainc+2;
200 if(strchr(incname, '/')) {
201 fprintf(file_include, "./%s\n", incname);
207 struct dirent *entry;
209 regex = glob_to_regex(incname);
210 if((d = opendir(device)) == NULL) {
211 dbprintf(("%s: Can't open disk '%s']\n",
212 debug_prefix(NULL), device));
214 printf("ERROR [Can't open disk '%s']\n", device);
219 while((entry = readdir(d)) != NULL) {
220 if(is_dot_or_dotdot(entry->d_name)) {
223 if(match(regex, entry->d_name)) {
224 fprintf(file_include, "./%s\n", entry->d_name);
236 char *build_exclude(disk, device, options, verbose)
248 if(options->exclude_file) nb_exclude += options->exclude_file->nb_element;
249 if(options->exclude_list) nb_exclude += options->exclude_list->nb_element;
251 if(nb_exclude == 0) return NULL;
253 if((filename = build_name(disk, "exclude", verbose)) != NULL) {
254 if((file_exclude = fopen(filename,"w")) != NULL) {
256 if(options->exclude_file) {
257 for(excl = options->exclude_file->first; excl != NULL;
259 add_exclude(file_exclude, excl->name,
260 verbose && options->exclude_optional == 0);
264 if(options->exclude_list) {
265 for(excl = options->exclude_list->first; excl != NULL;
267 char *exclname = fixup_relative(excl->name, device);
268 if((exclude = fopen(exclname, "r")) != NULL) {
269 while ((aexc = agets(exclude)) != NULL) {
270 add_exclude(file_exclude, aexc,
271 verbose && options->exclude_optional == 0);
277 dbprintf(("%s: Can't open exclude file '%s': %s\n",
279 exclname, strerror(errno)));
280 if(verbose && (options->exclude_optional == 0 ||
282 printf("ERROR [Can't open exclude file '%s': %s]\n",
283 exclname, strerror(errno));
288 fclose(file_exclude);
291 dbprintf(("%s: Can't create exclude file '%s': %s\n",
293 filename, strerror(errno)));
295 printf("ERROR [Can't create exclude file '%s': %s]\n", filename,
303 char *build_include(disk, device, options, verbose)
317 if(options->include_file) nb_include += options->include_file->nb_element;
318 if(options->include_list) nb_include += options->include_list->nb_element;
320 if(nb_include == 0) return NULL;
322 if((filename = build_name(disk, "include", verbose)) != NULL) {
323 if((file_include = fopen(filename,"w")) != NULL) {
325 if(options->include_file) {
326 for(incl = options->include_file->first; incl != NULL;
328 nb_exp += add_include(disk, device, file_include,
330 verbose && options->include_optional == 0);
334 if(options->include_list) {
335 for(incl = options->include_list->first; incl != NULL;
337 char *inclname = fixup_relative(incl->name, device);
338 if((include = fopen(inclname, "r")) != NULL) {
339 while ((ainc = agets(include)) != NULL) {
340 nb_exp += add_include(disk, device,
342 verbose && options->include_optional == 0);
348 dbprintf(("%s: Can't open include file '%s': %s\n",
350 inclname, strerror(errno)));
351 if(verbose && (options->include_optional == 0 ||
353 printf("ERROR [Can't open include file '%s': %s]\n",
354 inclname, strerror(errno));
359 fclose(file_include);
362 dbprintf(("%s: Can't create include file '%s': %s\n",
364 filename, strerror(errno)));
366 printf("ERROR [Can't create include file '%s': %s]\n", filename,
372 dbprintf(("%s: No include for '%s'\n", debug_prefix(NULL), disk));
373 if(verbose && options->include_optional == 0)
374 printf("ERROR [No include for '%s']\n", disk);
381 void init_options(options)
385 options->compress = NO_COMPR;
386 options->srvcompprog = NULL;
387 options->clntcompprog = NULL;
388 options->encrypt = ENCRYPT_NONE;
389 options->srv_encrypt = NULL;
390 options->clnt_encrypt = NULL;
391 options->srv_decrypt_opt = NULL;
392 options->clnt_decrypt_opt = NULL;
393 options->no_record = 0;
394 options->createindex = 0;
395 options->auth = NULL;
396 options->exclude_file = NULL;
397 options->exclude_list = NULL;
398 options->include_file = NULL;
399 options->include_list = NULL;
400 options->exclude_optional = 0;
401 options->include_optional = 0;
405 option_t *parse_options(str, disk, device, fs, verbose)
415 options = alloc(sizeof(option_t));
416 init_options(options);
417 options->str = stralloc(str);
422 while (tok != NULL) {
423 if(am_has_feature(fs, fe_options_auth)
424 && BSTRNCMP(tok,"auth=") == 0) {
425 if(options->auth != NULL) {
426 dbprintf(("%s: multiple auth option \"%s\"\n",
427 debug_prefix(NULL), tok+5));
429 printf("ERROR [multiple auth option \"%s\"\n", tok+5);
432 options->auth = stralloc(&tok[5]);
434 else if(am_has_feature(fs, fe_options_bsd_auth)
435 && BSTRNCMP(tok, "bsd-auth") == 0) {
436 if(options->auth != NULL) {
437 dbprintf(("%s: multiple auth option \n",
438 debug_prefix(NULL)));
440 printf("ERROR [multiple auth option \n");
443 options->auth = stralloc("bsd");
445 else if(am_has_feature(fs, fe_options_krb4_auth)
446 && BSTRNCMP(tok, "krb4-auth") == 0) {
447 if(options->auth != NULL) {
448 dbprintf(("%s: multiple auth option \n",
449 debug_prefix(NULL)));
451 printf("ERROR [multiple auth option \n");
454 options->auth = stralloc("krb4");
456 else if(BSTRNCMP(tok, "compress-fast") == 0) {
457 if(options->compress != NO_COMPR) {
458 dbprintf(("%s: multiple compress option \n",
459 debug_prefix(NULL)));
461 printf("ERROR [multiple compress option \n");
464 options->compress = COMPR_FAST;
466 else if(BSTRNCMP(tok, "compress-best") == 0) {
467 if(options->compress != NO_COMPR) {
468 dbprintf(("%s: multiple compress option \n",
469 debug_prefix(NULL)));
471 printf("ERROR [multiple compress option \n");
474 options->compress = COMPR_BEST;
476 else if(BSTRNCMP(tok, "srvcomp-fast") == 0) {
477 if(options->compress != NO_COMPR) {
478 dbprintf(("%s: multiple compress option \n",
479 debug_prefix(NULL)));
481 printf("ERROR [multiple compress option \n");
484 options->compress = COMPR_SERVER_FAST;
486 else if(BSTRNCMP(tok, "srvcomp-best") == 0) {
487 if(options->compress != NO_COMPR) {
488 dbprintf(("%s: multiple compress option \n",
489 debug_prefix(NULL)));
491 printf("ERROR [multiple compress option \n");
494 options->compress = COMPR_SERVER_BEST;
496 else if(BSTRNCMP(tok, "srvcomp-cust=") == 0) {
497 if(options->compress != NO_COMPR) {
498 dbprintf(("%s: multiple compress option\n",
499 debug_prefix(NULL)));
501 printf("ERROR [multiple compress option]\n");
504 options->srvcompprog = stralloc(tok + sizeof("srvcomp-cust=") -1);
505 options->compress = COMPR_SERVER_CUST;
507 else if(BSTRNCMP(tok, "comp-cust=") == 0) {
508 if(options->compress != NO_COMPR) {
509 dbprintf(("%s: multiple compress option\n",
510 debug_prefix(NULL)));
512 printf("ERROR [multiple compress option]\n");
515 options->clntcompprog = stralloc(tok + sizeof("comp-cust=") -1);
516 options->compress = COMPR_CUST;
517 /* parse encryption options */
519 else if(BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
520 if(options->encrypt != ENCRYPT_NONE) {
521 dbprintf(("%s: multiple encrypt option\n",
522 debug_prefix(NULL)));
524 printf("ERROR [multiple encrypt option]\n");
527 options->srv_encrypt = stralloc(tok + sizeof("encrypt-serv-cust=") -1);
528 options->encrypt = ENCRYPT_SERV_CUST;
530 else if(BSTRNCMP(tok, "encrypt-cust=") == 0) {
531 if(options->encrypt != ENCRYPT_NONE) {
532 dbprintf(("%s: multiple encrypt option\n",
533 debug_prefix(NULL)));
535 printf("ERROR [multiple encrypt option]\n");
538 options->clnt_encrypt= stralloc(tok + sizeof("encrypt-cust=") -1);
539 options->encrypt = ENCRYPT_CUST;
541 else if(BSTRNCMP(tok, "server-decrypt-option=") == 0) {
542 options->srv_decrypt_opt = stralloc(tok + sizeof("server-decrypt-option=") -1);
544 else if(BSTRNCMP(tok, "client-decrypt-option=") == 0) {
545 options->clnt_decrypt_opt = stralloc(tok + sizeof("client-decrypt-option=") -1);
547 else if(BSTRNCMP(tok, "no-record") == 0) {
548 if(options->no_record != 0) {
549 dbprintf(("%s: multiple no-record option \n",
550 debug_prefix(NULL)));
552 printf("ERROR [multiple no-record option \n");
555 options->no_record = 1;
557 else if(BSTRNCMP(tok, "index") == 0) {
558 if(options->createindex != 0) {
559 dbprintf(("%s: multiple index option \n",
560 debug_prefix(NULL)));
562 printf("ERROR [multiple index option \n");
565 options->createindex = 1;
567 else if(BSTRNCMP(tok, "exclude-optional") == 0) {
568 if(options->exclude_optional != 0) {
569 dbprintf(("%s: multiple exclude-optional option \n",
570 debug_prefix(NULL)));
572 printf("ERROR [multiple exclude-optional option \n");
575 options->exclude_optional = 1;
577 else if(strcmp(tok, "include-optional") == 0) {
578 if(options->include_optional != 0) {
579 dbprintf(("%s: multiple include-optional option \n",
580 debug_prefix(NULL)));
582 printf("ERROR [multiple include-optional option \n");
585 options->include_optional = 1;
587 else if(BSTRNCMP(tok,"exclude-file=") == 0) {
589 options->exclude_file = append_sl(options->exclude_file,exc);
591 else if(BSTRNCMP(tok,"exclude-list=") == 0) {
593 options->exclude_list = append_sl(options->exclude_list, exc);
595 else if(BSTRNCMP(tok,"include-file=") == 0) {
597 options->include_file = append_sl(options->include_file,exc);
599 else if(BSTRNCMP(tok,"include-list=") == 0) {
601 options->include_list = append_sl(options->include_list, exc);
603 else if(strcmp(tok,"|") == 0) {
606 dbprintf(("%s: unknown option \"%s\"\n", debug_prefix(NULL), tok));
608 printf("ERROR [unknown option \"%s\"]\n", tok);
611 tok = strtok(NULL, ";");
618 void init_g_options(g_options)
619 g_option_t *g_options;
621 g_options->features = NULL;
622 g_options->hostname = NULL;
623 g_options->maxdumps = 0;
627 g_option_t *parse_g_options(str, verbose)
631 g_option_t *g_options;
635 g_options = alloc(sizeof(g_option_t));
636 init_g_options(g_options);
637 g_options->str = stralloc(str);
642 while (tok != NULL) {
643 if(strncmp(tok,"features=", 9) == 0) {
644 if(g_options->features != NULL) {
645 dbprintf(("%s: multiple features option\n",
646 debug_prefix(NULL)));
648 printf("ERROR [multiple features option]\n");
651 if((g_options->features = am_string_to_feature(tok+9)) == NULL) {
652 dbprintf(("%s: bad features value \"%s\n",
653 debug_prefix(NULL), tok+10));
655 printf("ERROR [bad features value \"%s\"]\n", tok+10);
659 else if(strncmp(tok,"hostname=", 9) == 0) {
660 if(g_options->hostname != NULL) {
661 dbprintf(("%s: multiple hostname option\n",
662 debug_prefix(NULL)));
664 printf("ERROR [multiple hostname option]\n");
667 g_options->hostname = stralloc(tok+9);
669 else if(strncmp(tok,"maxdumps=", 9) == 0) {
670 if(g_options->maxdumps != 0) {
671 dbprintf(("%s: multiple maxdumps option\n",
672 debug_prefix(NULL)));
674 printf("ERROR [multiple maxdumps option]\n");
677 if(sscanf(tok+9, "%d;", &new_maxdumps) == 1) {
678 if (new_maxdumps > MAXMAXDUMPS) {
679 g_options->maxdumps = MAXMAXDUMPS;
681 else if (new_maxdumps > 0) {
682 g_options->maxdumps = new_maxdumps;
685 dbprintf(("%s: bad maxdumps value \"%s\"\n",
686 debug_prefix(NULL), tok+9));
688 printf("ERROR [bad maxdumps value \"%s\"]\n",
694 dbprintf(("%s: bad maxdumps value \"%s\"\n",
695 debug_prefix(NULL), tok+9));
697 printf("ERROR [bad maxdumps value \"%s\"]\n",
703 dbprintf(("%s: unknown option \"%s\"\n",
704 debug_prefix(NULL), tok));
706 printf("ERROR [unknown option \"%s\"]\n", tok);
709 tok = strtok(NULL, ";");
711 if(g_options->features == NULL) {
712 g_options->features = am_set_default_feature_set();
714 if(g_options->maxdumps == 0) /* default */
715 g_options->maxdumps = 1;