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.34 2006/05/25 01:47:11 johnfranks Exp $
33 #include "client_util.h"
36 #include "glib-util.h"
37 #include "timestamp.h"
38 #include "pipespawn.h"
42 #include "amandates.h"
45 #define MAXMAXDUMPS 16
47 static int add_exclude(FILE *file_exclude, char *aexc, int verbose);
48 static int add_include(char *disk, char *device, FILE *file_include, char *ainc, int verbose);
49 static char *build_name(char *disk, char *exin, int verbose);
50 static char *get_name(char *diskname, char *exin, time_t t, int n);
60 char *dirname = amname_to_dirname(device);
61 newname = vstralloc(dirname, "/", name , NULL);
65 newname = stralloc(name);
78 char number[NUM_STR_SIZE];
82 ts = get_timestamp_from_time(t);
86 g_snprintf(number, SIZEOF(number), "%03d", n - 1);
88 filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
103 char *filename = NULL;
104 char *afilename = NULL;
110 struct dirent *entry;
112 size_t match_len, d_name_len;
116 diskname = sanitise_filename(disk);
118 dbgdir = stralloc2(AMANDA_TMPDIR, "/");
119 if((d = opendir(AMANDA_TMPDIR)) == NULL) {
120 error(_("open debug directory \"%s\": %s"),
121 AMANDA_TMPDIR, strerror(errno));
124 test_name = get_name(diskname, exin,
125 curtime - (AMANDA_DEBUG_DAYS * 24 * 60 * 60), 0);
126 match_len = strlen(get_pname()) + strlen(diskname) + 2;
127 while((entry = readdir(d)) != NULL) {
128 if(is_dot_or_dotdot(entry->d_name)) {
131 d_name_len = strlen(entry->d_name);
132 if(strncmp(test_name, entry->d_name, match_len) != 0
133 || d_name_len < match_len + 14 + 8
134 || strcmp(entry->d_name+ d_name_len - 7, exin) != 0) {
135 continue; /* not one of our files */
137 if(strcmp(entry->d_name, test_name) < 0) {
138 e = newvstralloc(e, dbgdir, entry->d_name, NULL);
139 (void) unlink(e); /* get rid of old file */
148 filename = get_name(diskname, exin, curtime, n);
149 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
150 if((fd=open(afilename, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0){
158 } while(!afilename && n < 1000);
160 if(afilename == NULL) {
161 filename = get_name(diskname, exin, curtime, 0);
162 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
163 quoted = quote_string(afilename);
164 dbprintf(_("Cannot create %s (%s)\n"), quoted, strerror(errno));
166 g_printf(_("ERROR [cannot create %s (%s)]\n"),
167 quoted, strerror(errno));
190 (void)verbose; /* Quiet unused parameter warning */
193 if(aexc[l-1] == '\n') {
197 file = quoted = quote_string(aexc);
199 file[strlen(file) - 1] = '\0';
202 g_fprintf(file_exclude, "%s\n", file);
219 (void)disk; /* Quiet unused parameter warning */
220 (void)device; /* Quiet unused parameter warning */
223 if(ainc[l-1] == '\n') {
227 if (strncmp(ainc, "./", 2) != 0) {
228 quoted = quote_string(ainc);
229 dbprintf(_("include must start with './' (%s)\n"), quoted);
231 g_printf(_("ERROR [include must start with './' (%s)]\n"), quoted);
236 char *incname = ainc+2;
239 set_root = set_root_privs(1);
240 /* Take as is if not root && many '/' */
241 if(!set_root && strchr(incname, '/')) {
242 file = quoted = quote_string(ainc);
244 file[strlen(file) - 1] = '\0';
247 g_fprintf(file_include, "%s\n", file);
258 cwd = g_get_current_dir();
259 if (chdir(device) != 0) {
260 error(_("Failed to chdir(%s): %s\n"), device, strerror(errno));
262 glob(incname, 0, NULL, &globbuf);
263 if (chdir(cwd) != 0) {
264 error(_("Failed to chdir(%s): %s\n"), cwd, strerror(errno));
268 nb_exp = globbuf.gl_pathc;
269 for (nb=0; nb < nb_exp; nb++) {
270 file = stralloc2("./", globbuf.gl_pathv[nb]);
271 quoted = quote_string(file);
273 file[strlen(file) - 1] = '\0';
276 g_fprintf(file_include, "%s\n", file);
298 if (dle->exclude_file) nb_exclude += dle->exclude_file->nb_element;
299 if (dle->exclude_list) nb_exclude += dle->exclude_list->nb_element;
301 if (nb_exclude == 0) return NULL;
303 if ((filename = build_name(dle->disk, "exclude", verbose)) != NULL) {
304 if ((file_exclude = fopen(filename,"w")) != NULL) {
306 if (dle->exclude_file) {
307 for(excl = dle->exclude_file->first; excl != NULL;
309 add_exclude(file_exclude, excl->name,
310 verbose && dle->exclude_optional == 0);
314 if (dle->exclude_list) {
315 for(excl = dle->exclude_list->first; excl != NULL;
317 char *exclname = fixup_relative(excl->name, dle->device);
318 if((exclude = fopen(exclname, "r")) != NULL) {
319 while ((aexc = agets(exclude)) != NULL) {
320 if (aexc[0] == '\0') {
324 add_exclude(file_exclude, aexc,
325 verbose && dle->exclude_optional == 0);
331 quoted = quote_string(exclname);
332 dbprintf(_("Can't open exclude file %s (%s)\n"),
333 quoted, strerror(errno));
334 if(verbose && (dle->exclude_optional == 0 ||
336 g_printf(_("ERROR [Can't open exclude file %s (%s)]\n"),
337 quoted, strerror(errno));
344 fclose(file_exclude);
346 quoted = quote_string(filename);
347 dbprintf(_("Can't create exclude file %s (%s)\n"),
348 quoted, strerror(errno));
350 g_printf(_("ERROR [Can't create exclude file %s (%s)]\n"),
351 quoted, strerror(errno));
374 if (dle->include_file) nb_include += dle->include_file->nb_element;
375 if (dle->include_list) nb_include += dle->include_list->nb_element;
377 if (nb_include == 0) return NULL;
379 if ((filename = build_name(dle->disk, "include", verbose)) != NULL) {
380 if ((file_include = fopen(filename,"w")) != NULL) {
382 if (dle->include_file) {
383 for (incl = dle->include_file->first; incl != NULL;
385 nb_exp += add_include(dle->disk, dle->device, file_include,
387 verbose && dle->include_optional == 0);
391 if (dle->include_list) {
392 for (incl = dle->include_list->first; incl != NULL;
394 char *inclname = fixup_relative(incl->name, dle->device);
395 if ((include = fopen(inclname, "r")) != NULL) {
396 while ((ainc = agets(include)) != NULL) {
397 if (ainc[0] == '\0') {
401 nb_exp += add_include(dle->disk, dle->device,
403 verbose && dle->include_optional == 0);
409 quoted = quote_string(inclname);
410 dbprintf(_("Can't open include file %s (%s)\n"),
411 quoted, strerror(errno));
412 if (verbose && (dle->include_optional == 0 ||
414 g_printf(_("ERROR [Can't open include file %s (%s)]\n"),
415 quoted, strerror(errno));
422 fclose(file_include);
424 quoted = quote_string(filename);
425 dbprintf(_("Can't create include file %s (%s)\n"),
426 quoted, strerror(errno));
428 g_printf(_("ERROR [Can't create include file %s (%s)]\n"),
429 quoted, strerror(errno));
436 quoted = quote_string(dle->disk);
437 dbprintf(_("No include for %s\n"), quoted);
438 if (verbose && dle->include_optional == 0) {
439 g_printf(_("ERROR [No include for %s]\n"), quoted);
463 while (tok != NULL) {
464 if(am_has_feature(fs, fe_options_auth)
465 && BSTRNCMP(tok,"auth=") == 0) {
466 if (dle->auth != NULL) {
467 quoted = quote_string(tok + 5);
468 dbprintf(_("multiple auth option %s\n"), quoted);
470 g_printf(_("ERROR [multiple auth option %s]\n"), quoted);
474 dle->auth = stralloc(&tok[5]);
476 else if(am_has_feature(fs, fe_options_bsd_auth)
477 && BSTRNCMP(tok, "bsd-auth") == 0) {
478 if (dle->auth != NULL) {
479 dbprintf(_("multiple auth option\n"));
481 g_printf(_("ERROR [multiple auth option]\n"));
484 dle->auth = stralloc("bsd");
486 else if (am_has_feature(fs, fe_options_krb4_auth)
487 && BSTRNCMP(tok, "krb4-auth") == 0) {
488 if (dle->auth != NULL) {
489 dbprintf(_("multiple auth option\n"));
491 g_printf(_("ERROR [multiple auth option]\n"));
494 dle->auth = stralloc("krb4");
496 else if (BSTRNCMP(tok, "compress-fast") == 0) {
497 if (dle->compress != COMP_NONE) {
498 dbprintf(_("multiple compress option\n"));
500 g_printf(_("ERROR [multiple compress option]\n"));
503 dle->compress = COMP_FAST;
505 else if (BSTRNCMP(tok, "compress-best") == 0) {
506 if (dle->compress != COMP_NONE) {
507 dbprintf(_("multiple compress option\n"));
509 g_printf(_("ERROR [multiple compress option]\n"));
512 dle->compress = COMP_BEST;
514 else if (BSTRNCMP(tok, "srvcomp-fast") == 0) {
515 if (dle->compress != COMP_NONE) {
516 dbprintf(_("multiple compress option\n"));
518 g_printf(_("ERROR [multiple compress option]\n"));
521 dle->compress = COMP_SERVER_FAST;
523 else if (BSTRNCMP(tok, "srvcomp-best") == 0) {
524 if (dle->compress != COMP_NONE) {
525 dbprintf(_("multiple compress option\n"));
527 g_printf(_("ERROR [multiple compress option]\n"));
530 dle->compress = COMP_SERVER_BEST;
532 else if (BSTRNCMP(tok, "srvcomp-cust=") == 0) {
533 if (dle->compress != COMP_NONE) {
534 dbprintf(_("multiple compress option\n"));
536 g_printf(_("ERROR [multiple compress option]\n"));
539 dle->compprog = stralloc(tok + SIZEOF("srvcomp-cust=") -1);
540 dle->compress = COMP_SERVER_CUST;
542 else if (BSTRNCMP(tok, "comp-cust=") == 0) {
543 if (dle->compress != COMP_NONE) {
544 dbprintf(_("multiple compress option\n"));
546 g_printf(_("ERROR [multiple compress option]\n"));
549 dle->compprog = stralloc(tok + SIZEOF("comp-cust=") -1);
550 dle->compress = COMP_CUST;
551 /* parse encryption options */
553 else if (BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
554 if (dle->encrypt != ENCRYPT_NONE) {
555 dbprintf(_("multiple encrypt option\n"));
557 g_printf(_("ERROR [multiple encrypt option]\n"));
560 dle->srv_encrypt = stralloc(tok + SIZEOF("encrypt-serv-cust=") -1);
561 dle->encrypt = ENCRYPT_SERV_CUST;
563 else if (BSTRNCMP(tok, "encrypt-cust=") == 0) {
564 if (dle->encrypt != ENCRYPT_NONE) {
565 dbprintf(_("multiple encrypt option\n"));
567 g_printf(_("ERROR [multiple encrypt option]\n"));
570 dle->clnt_encrypt= stralloc(tok + SIZEOF("encrypt-cust=") -1);
571 dle->encrypt = ENCRYPT_CUST;
573 else if (BSTRNCMP(tok, "server-decrypt-option=") == 0) {
574 dle->srv_decrypt_opt = stralloc(tok + SIZEOF("server-decrypt-option=") -1);
576 else if (BSTRNCMP(tok, "client-decrypt-option=") == 0) {
577 dle->clnt_decrypt_opt = stralloc(tok + SIZEOF("client-decrypt-option=") -1);
579 else if (BSTRNCMP(tok, "no-record") == 0) {
580 if (dle->record != 1) {
581 dbprintf(_("multiple no-record option\n"));
583 g_printf(_("ERROR [multiple no-record option]\n"));
588 else if (BSTRNCMP(tok, "index") == 0) {
589 if (dle->create_index != 0) {
590 dbprintf(_("multiple index option\n"));
592 g_printf(_("ERROR [multiple index option]\n"));
595 dle->create_index = 1;
597 else if (BSTRNCMP(tok, "exclude-optional") == 0) {
598 if (dle->exclude_optional != 0) {
599 dbprintf(_("multiple exclude-optional option\n"));
601 g_printf(_("ERROR [multiple exclude-optional option]\n"));
604 dle->exclude_optional = 1;
606 else if (strcmp(tok, "include-optional") == 0) {
607 if (dle->include_optional != 0) {
608 dbprintf(_("multiple include-optional option\n"));
610 g_printf(_("ERROR [multiple include-optional option]\n"));
613 dle->include_optional = 1;
615 else if (BSTRNCMP(tok,"exclude-file=") == 0) {
616 exc = unquote_string(&tok[13]);
617 dle->exclude_file = append_sl(dle->exclude_file, exc);
620 else if (BSTRNCMP(tok,"exclude-list=") == 0) {
621 exc = unquote_string(&tok[13]);
622 dle->exclude_list = append_sl(dle->exclude_list, exc);
625 else if (BSTRNCMP(tok,"include-file=") == 0) {
626 inc = unquote_string(&tok[13]);
627 dle->include_file = append_sl(dle->include_file, inc);
630 else if (BSTRNCMP(tok,"include-list=") == 0) {
631 inc = unquote_string(&tok[13]);
632 dle->include_list = append_sl(dle->include_list, inc);
635 else if (BSTRNCMP(tok,"kencrypt") == 0) {
638 else if (strcmp(tok,"|") != 0) {
639 quoted = quote_string(tok);
640 dbprintf(_("unknown option %s\n"), quoted);
642 g_printf(_("ERROR [unknown option: %s]\n"), quoted);
646 tok = strtok(NULL, ";");
652 application_property_argv_size(dle_t *dle) {
656 if (dle->include_list)
657 nb += dle->include_list->nb_element;
658 if (dle->include_file)
659 nb += dle->include_file->nb_element;
660 nb++; /* include optional */
661 if (dle->exclude_list)
662 nb += dle->exclude_list->nb_element;
663 if (dle->exclude_file)
664 nb += dle->exclude_file->nb_element;
665 nb++; /* exclude optional */
666 nb *= 2; /*name + value */
667 nb += property_argv_size(dle->application_property);
673 application_property_add_to_argv(
676 backup_support_option_t *bsu)
678 char **argv = argvchild;
682 if (bsu->include_file && dle->include_file) {
683 for (incl = dle->include_file->first; incl != NULL;
685 *argv = stralloc("--include-file");
687 *argv = stralloc(incl->name);
691 if (bsu->include_list && dle->include_list) {
692 for (incl = dle->include_list->first; incl != NULL;
694 *argv = stralloc("--include-list");
696 *argv = stralloc(incl->name);
700 if (bsu->include_optional && dle->include_optional) {
701 *argv = stralloc("--include-optional");
703 *argv = stralloc("yes");
707 if (bsu->exclude_file && dle->exclude_file) {
708 for (excl = dle->exclude_file->first; excl != NULL;
710 *argv = stralloc("--exclude-file");
712 *argv = stralloc(excl->name);
716 if (bsu->exclude_list && dle->exclude_list) {
717 for (excl = dle->exclude_list->first; excl != NULL;
719 *argv = stralloc("--exclude-list");
721 *argv = stralloc(excl->name);
725 if (bsu->exclude_optional && dle->exclude_optional) {
726 *argv = stralloc("--exclude-optional");
728 *argv = stralloc("yes");
733 g_hash_table_foreach(dle->application_property,
734 &proplist_add_to_argv, &argv);
735 return (argv - argvchild);
738 backup_support_option_t *
739 backup_support_option(
741 g_option_t *g_options,
744 GPtrArray **errarray)
747 int supportin, supportout, supporterr;
756 backup_support_option_t *bsu;
758 *errarray = g_ptr_array_new();
759 cmd = vstralloc(APPLICATION_DIR, "/", program, NULL);
760 argvchild = g_new0(char *, 12);
762 argvchild[i++] = program;
763 argvchild[i++] = "support";
764 if (g_options->config) {
765 argvchild[i++] = "--config";
766 argvchild[i++] = g_options->config;
768 if (g_options->hostname) {
769 argvchild[i++] = "--host";
770 argvchild[i++] = g_options->hostname;
773 argvchild[i++] = "--disk";
774 argvchild[i++] = disk;
777 argvchild[i++] = "--device";
778 argvchild[i++] = stralloc(amdevice);
780 argvchild[i++] = NULL;
782 supporterr = fileno(stderr);
783 supportpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
784 &supportin, &supportout, &supporterr, argvchild);
788 bsu = g_new0(backup_support_option_t, 1);
792 streamout = fdopen(supportout, "r");
794 error(_("Error opening pipe to child: %s"), strerror(errno));
797 while((line = agets(streamout)) != NULL) {
798 dbprintf(_("support line: %s\n"), line);
799 if (strncmp(line,"CONFIG ", 7) == 0) {
800 if (strcmp(line+7, "YES") == 0)
802 } else if (strncmp(line,"HOST ", 5) == 0) {
803 if (strcmp(line+5, "YES") == 0)
805 } else if (strncmp(line,"DISK ", 5) == 0) {
806 if (strcmp(line+5, "YES") == 0)
808 } else if (strncmp(line,"INDEX-LINE ", 11) == 0) {
809 if (strcmp(line+11, "YES") == 0)
811 } else if (strncmp(line,"INDEX-XML ", 10) == 0) {
812 if (strcmp(line+10, "YES") == 0)
814 } else if (strncmp(line,"MESSAGE-LINE ", 13) == 0) {
815 if (strcmp(line+13, "YES") == 0)
816 bsu->message_line = 1;
817 } else if (strncmp(line,"MESSAGE-XML ", 12) == 0) {
818 if (strcmp(line+12, "YES") == 0)
819 bsu->message_xml = 1;
820 } else if (strncmp(line,"RECORD ", 7) == 0) {
821 if (strcmp(line+7, "YES") == 0)
823 } else if (strncmp(line,"INCLUDE-FILE ", 13) == 0) {
824 if (strcmp(line+13, "YES") == 0)
825 bsu->include_file = 1;
826 } else if (strncmp(line,"INCLUDE-LIST ", 13) == 0) {
827 if (strcmp(line+13, "YES") == 0)
828 bsu->include_list = 1;
829 } else if (strncmp(line,"INCLUDE-OPTIONAL ", 17) == 0) {
830 if (strcmp(line+17, "YES") == 0)
831 bsu->include_optional = 1;
832 } else if (strncmp(line,"EXCLUDE-FILE ", 13) == 0) {
833 if (strcmp(line+13, "YES") == 0)
834 bsu->exclude_file = 1;
835 } else if (strncmp(line,"EXCLUDE-LIST ", 13) == 0) {
836 if (strcmp(line+13, "YES") == 0)
837 bsu->exclude_list = 1;
838 } else if (strncmp(line,"EXCLUDE-OPTIONAL ", 17) == 0) {
839 if (strcmp(line+17, "YES") == 0)
840 bsu->exclude_optional = 1;
841 } else if (strncmp(line,"COLLECTION ", 11) == 0) {
842 if (strcmp(line+11, "YES") == 0)
844 } else if (strncmp(line,"CALCSIZE ", 9) == 0) {
845 if (strcmp(line+9, "YES") == 0)
847 } else if (strncmp(line,"MULTI-ESTIMATE ", 15) == 0) {
848 if (strcmp(line+15, "YES") == 0)
849 bsu->multi_estimate = 1;
850 } else if (strncmp(line,"MAX-LEVEL ", 10) == 0) {
851 bsu->max_level = atoi(line+10);
852 } else if (strncmp(line,"RECOVER-MODE ", 13) == 0) {
853 if (strcasecmp(line+13, "SMB") == 0)
854 bsu->smb_recover_mode = 1;
856 dbprintf(_("Invalid support line: %s\n"), line);
861 streamerr = fdopen(supporterr, "r");
863 error(_("Error opening pipe to child: %s"), strerror(errno));
866 while((line = agets(streamerr)) != NULL) {
867 if (strlen(line) > 0) {
868 g_ptr_array_add(*errarray, line);
869 dbprintf("Application '%s': %s\n", program, line);
875 if (waitpid(supportpid, &status, 0) < 0) {
876 err = vstrallocf(_("waitpid failed: %s"), strerror(errno));
877 } else if (!WIFEXITED(status)) {
878 err = vstrallocf(_("exited with signal %d"), WTERMSIG(status));
879 } else if (WEXITSTATUS(status) != 0) {
880 err = vstrallocf(_("exited with status %d"), WEXITSTATUS(status));
884 g_ptr_array_add(*errarray, err);
885 dbprintf("Application '%s': %s\n", program, err);
894 execute_on_t execute_on,
895 g_option_t *g_options,
899 int scriptin, scriptout, scripterr;
907 amwait_t wait_status;
909 if ((script->execute_on & execute_on) == 0)
911 if (script->execute_where != ES_CLIENT)
914 cmd = vstralloc(APPLICATION_DIR, "/", script->plugin, NULL);
915 argv_size = 14 + property_argv_size(script->property);
917 argv_size += 2 * g_slist_length(dle->level);
918 argvchild = g_new0(char *, argv_size);
920 argvchild[i++] = script->plugin;
922 switch (execute_on) {
923 case EXECUTE_ON_PRE_DLE_AMCHECK:
924 argvchild[i++] = "PRE-DLE-AMCHECK"; break;
925 case EXECUTE_ON_PRE_HOST_AMCHECK:
926 argvchild[i++] = "PRE-HOST-AMCHECK"; break;
927 case EXECUTE_ON_POST_DLE_AMCHECK:
928 argvchild[i++] = "POST-DLE-AMCHECK"; break;
929 case EXECUTE_ON_POST_HOST_AMCHECK:
930 argvchild[i++] = "POST-HOST-AMCHECK"; break;
931 case EXECUTE_ON_PRE_DLE_ESTIMATE:
932 argvchild[i++] = "PRE-DLE-ESTIMATE"; break;
933 case EXECUTE_ON_PRE_HOST_ESTIMATE:
934 argvchild[i++] = "PRE-HOST-ESTIMATE"; break;
935 case EXECUTE_ON_POST_DLE_ESTIMATE:
936 argvchild[i++] = "POST-DLE-ESTIMATE"; break;
937 case EXECUTE_ON_POST_HOST_ESTIMATE:
938 argvchild[i++] = "POST-HOST-ESTIMATE"; break;
939 case EXECUTE_ON_PRE_DLE_BACKUP:
940 argvchild[i++] = "PRE-DLE-BACKUP"; break;
941 case EXECUTE_ON_PRE_HOST_BACKUP:
942 argvchild[i++] = "PRE-HOST-BACKUP"; break;
943 case EXECUTE_ON_POST_DLE_BACKUP:
944 argvchild[i++] = "POST-DLE-BACKUP"; break;
945 case EXECUTE_ON_POST_HOST_BACKUP:
946 argvchild[i++] = "POST-HOST-BACKUP"; break;
947 case EXECUTE_ON_PRE_RECOVER:
948 argvchild[i++] = "PRE-RECOVER"; break;
949 case EXECUTE_ON_POST_RECOVER:
950 argvchild[i++] = "POST-RECOVER"; break;
951 case EXECUTE_ON_PRE_LEVEL_RECOVER:
952 argvchild[i++] = "PRE-LEVEL-RECOVER"; break;
953 case EXECUTE_ON_POST_LEVEL_RECOVER:
954 argvchild[i++] = "POST-LEVEL-RECOVER"; break;
955 case EXECUTE_ON_INTER_LEVEL_RECOVER:
956 argvchild[i++] = "INTER-LEVEL-RECOVER"; break;
959 argvchild[i++] = "--execute-where";
960 argvchild[i++] = "client";
962 if (g_options->config) {
963 argvchild[i++] = "--config";
964 argvchild[i++] = g_options->config;
966 if (g_options->hostname) {
967 argvchild[i++] = "--host";
968 argvchild[i++] = g_options->hostname;
971 argvchild[i++] = "--disk";
972 argvchild[i++] = dle->disk;
975 argvchild[i++] = "--device";
976 argvchild[i++] = stralloc(dle->device);
980 char number[NUM_STR_SIZE];
981 for (level=dle->level; level; level=level->next) {
982 argvchild[i++] = "--level";
983 g_snprintf(number, SIZEOF(number), "%d",
984 GPOINTER_TO_INT(level->data));
985 argvchild[i++] = stralloc(number);
988 i += property_add_to_argv(&argvchild[i], script->property);
989 argvchild[i++] = NULL;
991 scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
992 &scriptin, &scriptout, &scripterr, argvchild);
996 script->result = g_new0(client_script_result_t, 1);
997 script->result->proplist =
998 g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
999 script->result->output = g_ptr_array_new();
1000 script->result->err = g_ptr_array_new();
1002 streamout = fdopen(scriptout, "r");
1004 while((line = agets(streamout)) != NULL) {
1005 dbprintf("script: %s\n", line);
1006 if (BSTRNCMP(line, "PROPERTY ") == 0) {
1007 char *property_name, *property_value;
1008 property_name = line + 9;
1009 property_value = strchr(property_name,' ');
1010 if (property_value == NULL) {
1011 char *msg = g_strdup_printf(
1012 "ERROR %s: Bad output property: %s",
1013 script->plugin, line);
1014 g_ptr_array_add(script->result->output, msg);
1016 property_t *property;
1018 *property_value++ = '\0';
1019 property_name = stralloc(property_name);
1020 property_value = stralloc(property_value);
1021 property = g_hash_table_lookup(script->result->proplist,
1024 property = g_new0(property_t, 1);
1025 g_hash_table_insert(script->result->proplist,
1026 property_name, property);
1028 property->values = g_slist_append(property->values,
1033 g_ptr_array_add(script->result->output, line);
1039 streamerr = fdopen(scripterr, "r");
1041 while((line = agets(streamerr)) != NULL) {
1042 g_ptr_array_add(script->result->err,
1043 g_strdup_printf(_("Script '%s' command '%s': %s"),
1044 script->plugin, argvchild[1],
1050 waitpid(scriptpid, &wait_status, 0);
1051 if (WIFSIGNALED(wait_status)) {
1052 g_ptr_array_add(script->result->err,
1053 g_strdup_printf(_("Script '%s' command '%s' terminated with signal %d: see %s"),
1054 script->plugin, argvchild[1],
1055 WTERMSIG(wait_status),
1057 } else if (WIFEXITED(wait_status)) {
1058 if (WEXITSTATUS(wait_status) != 0) {
1059 g_ptr_array_add(script->result->err,
1060 g_strdup_printf(_("Script '%s' command '%s' exited with status %d: see %s"),
1061 script->plugin, argvchild[1],
1062 WEXITSTATUS(wait_status),
1071 void run_client_script_output(gpointer data, gpointer user_data);
1072 void run_client_script_err_amcheck(gpointer data, gpointer user_data);
1073 void run_client_script_err_estimate(gpointer data, gpointer user_data);
1074 void run_client_script_err_backup(gpointer data, gpointer user_data);
1075 void run_client_script_err_recover(gpointer data, gpointer user_data);
1077 typedef struct script_output_s {
1083 run_client_script_output(
1088 script_output_t *so = user_data;
1090 if (line && so->stream) {
1091 g_fprintf(so->stream, "%s\n", line);
1096 run_client_script_err_amcheck(
1101 script_output_t *so = user_data;
1103 if (line && so->stream) {
1104 g_fprintf(so->stream, "ERROR %s\n", line);
1109 run_client_script_err_estimate(
1114 script_output_t *so = user_data;
1116 if (line && so->stream) {
1117 char *qdisk = quote_string(so->dle->disk);
1118 g_fprintf(so->stream, "%s 0 WARNING \"%s\"\n", qdisk, line);
1124 run_client_script_err_backup(
1129 script_output_t *so = user_data;
1131 if (line && so->stream) {
1132 g_fprintf(so->stream, "? %s\n", line);
1137 run_client_script_err_recover(
1142 script_output_t *so = user_data;
1144 if (line && so->stream) {
1145 g_fprintf(so->stream, "%s\n", line);
1151 execute_on_t execute_on,
1152 g_option_t *g_options,
1158 GFunc client_script_err = NULL;
1159 script_output_t so = { streamout, dle };
1161 for (scriptlist = dle->scriptlist; scriptlist != NULL;
1162 scriptlist = scriptlist->next) {
1163 script = (script_t *)scriptlist->data;
1164 run_client_script(script, execute_on, g_options, dle);
1165 if (script->result && script->result->output) {
1166 g_ptr_array_foreach(script->result->output,
1167 run_client_script_output,
1169 g_ptr_array_free(script->result->output, TRUE);
1170 script->result->output = NULL;
1172 if (script->result && script->result->err) {
1173 switch (execute_on) {
1174 case EXECUTE_ON_PRE_DLE_AMCHECK:
1175 case EXECUTE_ON_PRE_HOST_AMCHECK:
1176 case EXECUTE_ON_POST_DLE_AMCHECK:
1177 case EXECUTE_ON_POST_HOST_AMCHECK:
1178 client_script_err = run_client_script_err_amcheck;
1180 case EXECUTE_ON_PRE_DLE_ESTIMATE:
1181 case EXECUTE_ON_PRE_HOST_ESTIMATE:
1182 case EXECUTE_ON_POST_DLE_ESTIMATE:
1183 case EXECUTE_ON_POST_HOST_ESTIMATE:
1184 if (am_has_feature(g_options->features,
1185 fe_sendsize_rep_warning)) {
1186 client_script_err = run_client_script_err_estimate;
1189 case EXECUTE_ON_PRE_DLE_BACKUP:
1190 case EXECUTE_ON_PRE_HOST_BACKUP:
1191 case EXECUTE_ON_POST_DLE_BACKUP:
1192 case EXECUTE_ON_POST_HOST_BACKUP:
1193 client_script_err = run_client_script_err_backup;
1195 case EXECUTE_ON_PRE_RECOVER:
1196 case EXECUTE_ON_POST_RECOVER:
1197 case EXECUTE_ON_PRE_LEVEL_RECOVER:
1198 case EXECUTE_ON_POST_LEVEL_RECOVER:
1199 case EXECUTE_ON_INTER_LEVEL_RECOVER:
1200 client_script_err = run_client_script_err_recover;
1202 if (client_script_err != NULL) {
1203 g_ptr_array_foreach(script->result->err,
1207 g_ptr_array_free(script->result->err, TRUE);
1208 script->result->err = NULL;
1224 char *cmd, *cmdline;
1225 char *my_argv[DUMP_LEVELS*2+22];
1227 char tmppath[PATH_MAX];
1228 char number[NUM_STR_SIZE];
1233 int pipefd = -1, nullfd = -1;
1236 FILE *dumpout = NULL;
1238 char *errmsg = NULL;
1239 off_t size = (off_t)1;
1241 amwait_t wait_status;
1245 char *amandates_file;
1247 qdisk = quote_string(disk);
1249 amandates_file = getconf_str(CNF_AMANDATES);
1250 if(!start_amandates(amandates_file, 0)) {
1251 char *errstr = strerror(errno);
1252 char *errmsg = vstrallocf(_("could not open %s: %s"), amandates_file, errstr);
1253 char *qerrmsg = quote_string(errmsg);
1254 g_printf(_("ERROR %s\n"), qerrmsg);
1262 cmd = vstralloc(amlibexecdir, "/", "calcsize", versionsuffix(), NULL);
1266 my_argv[my_argc++] = stralloc("calcsize");
1268 my_argv[my_argc++] = stralloc(config);
1270 my_argv[my_argc++] = stralloc("NOCONFIG");
1272 my_argv[my_argc++] = stralloc(program);
1274 canonicalize_pathname(disk, tmppath);
1275 my_argv[my_argc++] = stralloc(tmppath);
1276 canonicalize_pathname(dirname, tmppath);
1277 my_argv[my_argc++] = stralloc(tmppath);
1280 my_argv[my_argc++] = stralloc("-X");
1281 my_argv[my_argc++] = file_exclude;
1285 my_argv[my_argc++] = stralloc("-I");
1286 my_argv[my_argc++] = file_include;
1289 for (alevel = levels; alevel != NULL; alevel = alevel->next) {
1290 amdp = amandates_lookup(disk);
1291 level = GPOINTER_TO_INT(alevel->data);
1292 dbprintf("level: %d\n", level);
1294 for (i=0; i < level; i++) {
1295 if (dumpsince < amdp->dates[i])
1296 dumpsince = amdp->dates[i];
1298 g_snprintf(number, SIZEOF(number), "%d", level);
1299 my_argv[my_argc++] = stralloc(number);
1300 g_snprintf(number, SIZEOF(number), "%d", dumpsince);
1301 my_argv[my_argc++] = stralloc(number);
1304 my_argv[my_argc] = NULL;
1305 cmdline = stralloc(my_argv[0]);
1306 for(i = 1; i < my_argc; i++)
1307 cmdline = vstrextend(&cmdline, " ", my_argv[i], NULL);
1308 dbprintf(_("running: \"%s\"\n"), cmdline);
1311 start_time = curclock();
1313 fflush(stderr); fflush(stdout);
1315 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1316 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
1318 dbprintf("%s\n", errmsg);
1322 calcpid = pipespawnv(cmd, STDERR_PIPE, 0,
1323 &nullfd, &nullfd, &pipefd, my_argv);
1326 dumpout = fdopen(pipefd,"r");
1328 error(_("Can't fdopen: %s"), strerror(errno));
1332 match_expr = vstralloc(" %d SIZE %lld", NULL);
1333 len = strlen(qdisk);
1334 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1335 long long size_ = (long long)0;
1336 if (line[0] == '\0' || (int)strlen(line) <= len)
1338 /* Don't use sscanf for qdisk because it can have a '%'. */
1339 if (strncmp(line, qdisk, len) == 0 &&
1340 sscanf(line+len, match_expr, &level, &size_) == 2) {
1341 g_printf("%d %lld %d\n", level, size_, 1); /* write to sendsize */
1342 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
1343 qdisk, level, size_);
1345 size = (off_t)size_;
1349 dbprintf(_("waiting for %s %s child (pid=%d)\n"),
1350 my_argv[0], qdisk, (int)calcpid);
1351 waitpid(calcpid, &wait_status, 0);
1352 if (WIFSIGNALED(wait_status)) {
1353 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1354 "calcsize", WTERMSIG(wait_status),
1356 } else if (WIFEXITED(wait_status)) {
1357 if (WEXITSTATUS(wait_status) != 0) {
1358 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1359 "calcsize", WEXITSTATUS(wait_status),
1365 errmsg = vstrallocf(_("%s got bad exit: see %s"),
1366 "calcsize", dbfn());
1369 dbprintf(_("after %s %s wait: child pid=%d status=%d\n"),
1371 (int)calcpid, WEXITSTATUS(wait_status));
1373 dbprintf(_(".....\n"));
1374 dbprintf(_("estimate time for %s: %s\n"),
1376 walltime_str(timessub(curclock(), start_time)));
1379 if (errmsg && errmsg[0] != '\0') {
1380 char *qerrmsg = quote_string(errmsg);
1381 dbprintf(_("errmsg is %s\n"), errmsg);
1382 g_printf("ERROR %s\n", qerrmsg);
1387 for(i = 0; i < my_argc; i++) {
1400 char *noun, *adjective;
1401 char *quoted = quote_string(filename);
1404 noun = "find", adjective = "exists";
1405 else if((mode & X_OK) == X_OK)
1406 noun = "execute", adjective = "executable";
1407 else if((mode & (W_OK|R_OK)) == (W_OK|R_OK))
1408 noun = "read/write", adjective = "read/writable";
1410 noun = "access", adjective = "accessible";
1412 if(access(filename, mode) == -1)
1413 g_printf(_("ERROR [can not %s %s: %s]\n"), noun, quoted, strerror(errno));
1415 g_printf(_("OK %s %s\n"), quoted, adjective);
1424 struct stat stat_buf;
1427 if(!stat(filename, &stat_buf)) {
1428 if(!S_ISREG(stat_buf.st_mode)) {
1429 quoted = quote_string(filename);
1430 g_printf(_("ERROR [%s is not a file]\n"), quoted);
1434 if (getuid() == geteuid()) {
1435 check_access(filename, mode);
1444 struct stat stat_buf;
1448 if(!stat(dirname, &stat_buf)) {
1449 if(!S_ISDIR(stat_buf.st_mode)) {
1450 quoted = quote_string(dirname);
1451 g_printf(_("ERROR [%s is not a directory]\n"), quoted);
1455 quoted = quote_string(dirname);
1456 g_printf(_("ERROR [%s: %s]\n"), quoted, strerror(errno));
1459 if (getuid() == geteuid()) {
1460 dir = stralloc2(dirname, "/.");
1461 check_access(dir, mode);
1470 #ifndef SINGLE_USERID
1471 struct stat stat_buf;
1472 char *quoted = quote_string(filename);
1474 if(!stat(filename, &stat_buf)) {
1475 if(stat_buf.st_uid != 0 ) {
1476 g_printf(_("ERROR [%s is not owned by root]\n"), quoted);
1478 if((stat_buf.st_mode & S_ISUID) != S_ISUID) {
1479 g_printf(_("ERROR [%s is not SUID root]\n"), quoted);
1483 g_printf(_("ERROR [can not stat %s]\n"), quoted);
1487 (void)filename; /* Quiet unused parameter warning */
1492 * Returns the value of the first integer in a string.
1506 while(ch && !isdigit(ch)) ch = *str++;
1507 if (pos == 1) break;
1509 while(ch && (isdigit(ch) || ch == '.')) ch = *str++;
1512 while(isdigit(ch) || ch == '.') ch = *str++;
1521 config_errors_to_error_string(
1525 gboolean multiple_errors = FALSE;
1528 errmsg = (char *)errlist->data;
1530 multiple_errors = TRUE;
1532 errmsg = _("(no error message)");
1535 return vstrallocf("ERROR %s%s", errmsg,
1536 multiple_errors? _(" (additional errors not displayed)"):"");