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"
44 #define MAXMAXDUMPS 16
46 static int add_exclude(FILE *file_exclude, char *aexc, int verbose);
47 static int add_include(char *disk, char *device, FILE *file_include, char *ainc, int verbose);
48 static char *build_name(char *disk, char *exin, int verbose);
49 static char *get_name(char *diskname, char *exin, time_t t, int n);
59 char *dirname = amname_to_dirname(device);
60 newname = vstralloc(dirname, "/", name , NULL);
64 newname = stralloc(name);
77 char number[NUM_STR_SIZE];
81 ts = get_timestamp_from_time(t);
85 g_snprintf(number, SIZEOF(number), "%03d", n - 1);
87 filename = vstralloc(get_pname(), ".", diskname, ".", ts, number, ".",
102 char *filename = NULL;
103 char *afilename = NULL;
109 struct dirent *entry;
111 size_t match_len, d_name_len;
115 diskname = sanitise_filename(disk);
117 dbgdir = stralloc2(AMANDA_TMPDIR, "/");
118 if((d = opendir(AMANDA_TMPDIR)) == NULL) {
119 error(_("open debug directory \"%s\": %s"),
120 AMANDA_TMPDIR, strerror(errno));
123 test_name = get_name(diskname, exin,
124 curtime - (getconf_int(CNF_DEBUG_DAYS) * 24 * 60 * 60), 0);
125 match_len = strlen(get_pname()) + strlen(diskname) + 2;
126 while((entry = readdir(d)) != NULL) {
127 if(is_dot_or_dotdot(entry->d_name)) {
130 d_name_len = strlen(entry->d_name);
131 if(strncmp(test_name, entry->d_name, match_len) != 0
132 || d_name_len < match_len + 14 + 8
133 || strcmp(entry->d_name+ d_name_len - 7, exin) != 0) {
134 continue; /* not one of our files */
136 if(strcmp(entry->d_name, test_name) < 0) {
137 e = newvstralloc(e, dbgdir, entry->d_name, NULL);
138 (void) unlink(e); /* get rid of old file */
147 filename = get_name(diskname, exin, curtime, n);
148 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
149 if((fd=open(afilename, O_WRONLY|O_CREAT|O_APPEND, 0600)) < 0){
157 } while(!afilename && n < 1000);
159 if(afilename == NULL) {
160 filename = get_name(diskname, exin, curtime, 0);
161 afilename = newvstralloc(afilename, dbgdir, filename, NULL);
162 quoted = quote_string(afilename);
163 dbprintf(_("Cannot create %s (%s)\n"), quoted, strerror(errno));
165 g_printf(_("ERROR [cannot create %s (%s)]\n"),
166 quoted, strerror(errno));
189 (void)verbose; /* Quiet unused parameter warning */
192 if(aexc[l-1] == '\n') {
196 file = quoted = quote_string(aexc);
198 file[strlen(file) - 1] = '\0';
201 g_fprintf(file_exclude, "%s\n", file);
218 (void)disk; /* Quiet unused parameter warning */
219 (void)device; /* Quiet unused parameter warning */
222 if(ainc[l-1] == '\n') {
226 if (strncmp(ainc, "./", 2) != 0) {
227 quoted = quote_string(ainc);
228 dbprintf(_("include must start with './' (%s)\n"), quoted);
230 g_printf(_("ERROR [include must start with './' (%s)]\n"), quoted);
235 char *incname = ainc+2;
238 set_root = set_root_privs(1);
239 /* Take as is if not root && many '/' */
240 if(!set_root && strchr(incname, '/')) {
241 file = quoted = quote_string(ainc);
243 file[strlen(file) - 1] = '\0';
246 g_fprintf(file_include, "%s\n", file);
257 cwd = g_get_current_dir();
258 if (chdir(device) != 0) {
259 error(_("Failed to chdir(%s): %s\n"), device, strerror(errno));
261 glob(incname, 0, NULL, &globbuf);
262 if (chdir(cwd) != 0) {
263 error(_("Failed to chdir(%s): %s\n"), cwd, strerror(errno));
267 nb_exp = globbuf.gl_pathc;
268 for (nb=0; nb < nb_exp; nb++) {
269 file = stralloc2("./", globbuf.gl_pathv[nb]);
270 quoted = quote_string(file);
272 file[strlen(file) - 1] = '\0';
275 g_fprintf(file_include, "%s\n", file);
297 if (dle->exclude_file) nb_exclude += dle->exclude_file->nb_element;
298 if (dle->exclude_list) nb_exclude += dle->exclude_list->nb_element;
300 if (nb_exclude == 0) return NULL;
302 if ((filename = build_name(dle->disk, "exclude", verbose)) != NULL) {
303 if ((file_exclude = fopen(filename,"w")) != NULL) {
305 if (dle->exclude_file) {
306 for(excl = dle->exclude_file->first; excl != NULL;
308 add_exclude(file_exclude, excl->name,
309 verbose && dle->exclude_optional == 0);
313 if (dle->exclude_list) {
314 for(excl = dle->exclude_list->first; excl != NULL;
316 char *exclname = fixup_relative(excl->name, dle->device);
317 if((exclude = fopen(exclname, "r")) != NULL) {
318 while ((aexc = agets(exclude)) != NULL) {
319 if (aexc[0] == '\0') {
323 add_exclude(file_exclude, aexc,
324 verbose && dle->exclude_optional == 0);
330 quoted = quote_string(exclname);
331 dbprintf(_("Can't open exclude file %s (%s)\n"),
332 quoted, strerror(errno));
333 if(verbose && (dle->exclude_optional == 0 ||
335 g_printf(_("ERROR [Can't open exclude file %s (%s)]\n"),
336 quoted, strerror(errno));
343 fclose(file_exclude);
345 quoted = quote_string(filename);
346 dbprintf(_("Can't create exclude file %s (%s)\n"),
347 quoted, strerror(errno));
349 g_printf(_("ERROR [Can't create exclude file %s (%s)]\n"),
350 quoted, strerror(errno));
373 if (dle->include_file) nb_include += dle->include_file->nb_element;
374 if (dle->include_list) nb_include += dle->include_list->nb_element;
376 if (nb_include == 0) return NULL;
378 if ((filename = build_name(dle->disk, "include", verbose)) != NULL) {
379 if ((file_include = fopen(filename,"w")) != NULL) {
381 if (dle->include_file) {
382 for (incl = dle->include_file->first; incl != NULL;
384 nb_exp += add_include(dle->disk, dle->device, file_include,
386 verbose && dle->include_optional == 0);
390 if (dle->include_list) {
391 for (incl = dle->include_list->first; incl != NULL;
393 char *inclname = fixup_relative(incl->name, dle->device);
394 if ((include = fopen(inclname, "r")) != NULL) {
395 while ((ainc = agets(include)) != NULL) {
396 if (ainc[0] == '\0') {
400 nb_exp += add_include(dle->disk, dle->device,
402 verbose && dle->include_optional == 0);
408 quoted = quote_string(inclname);
409 dbprintf(_("Can't open include file %s (%s)\n"),
410 quoted, strerror(errno));
411 if (verbose && (dle->include_optional == 0 ||
413 g_printf(_("ERROR [Can't open include file %s (%s)]\n"),
414 quoted, strerror(errno));
421 fclose(file_include);
423 quoted = quote_string(filename);
424 dbprintf(_("Can't create include file %s (%s)\n"),
425 quoted, strerror(errno));
427 g_printf(_("ERROR [Can't create include file %s (%s)]\n"),
428 quoted, strerror(errno));
435 quoted = quote_string(dle->disk);
436 dbprintf(_("No include for %s\n"), quoted);
437 if (verbose && dle->include_optional == 0) {
438 g_printf(_("ERROR [No include for %s]\n"), quoted);
462 while (tok != NULL) {
463 if(am_has_feature(fs, fe_options_auth)
464 && BSTRNCMP(tok,"auth=") == 0) {
465 if (dle->auth != NULL) {
466 quoted = quote_string(tok + 5);
467 dbprintf(_("multiple auth option %s\n"), quoted);
469 g_printf(_("ERROR [multiple auth option %s]\n"), quoted);
473 dle->auth = stralloc(&tok[5]);
475 else if(am_has_feature(fs, fe_options_bsd_auth)
476 && BSTRNCMP(tok, "bsd-auth") == 0) {
477 if (dle->auth != NULL) {
478 dbprintf(_("multiple auth option\n"));
480 g_printf(_("ERROR [multiple auth option]\n"));
483 dle->auth = stralloc("bsd");
485 else if (BSTRNCMP(tok, "compress-fast") == 0) {
486 if (dle->compress != COMP_NONE) {
487 dbprintf(_("multiple compress option\n"));
489 g_printf(_("ERROR [multiple compress option]\n"));
492 dle->compress = COMP_FAST;
494 else if (BSTRNCMP(tok, "compress-best") == 0) {
495 if (dle->compress != COMP_NONE) {
496 dbprintf(_("multiple compress option\n"));
498 g_printf(_("ERROR [multiple compress option]\n"));
501 dle->compress = COMP_BEST;
503 else if (BSTRNCMP(tok, "srvcomp-fast") == 0) {
504 if (dle->compress != COMP_NONE) {
505 dbprintf(_("multiple compress option\n"));
507 g_printf(_("ERROR [multiple compress option]\n"));
510 dle->compress = COMP_SERVER_FAST;
512 else if (BSTRNCMP(tok, "srvcomp-best") == 0) {
513 if (dle->compress != COMP_NONE) {
514 dbprintf(_("multiple compress option\n"));
516 g_printf(_("ERROR [multiple compress option]\n"));
519 dle->compress = COMP_SERVER_BEST;
521 else if (BSTRNCMP(tok, "srvcomp-cust=") == 0) {
522 if (dle->compress != COMP_NONE) {
523 dbprintf(_("multiple compress option\n"));
525 g_printf(_("ERROR [multiple compress option]\n"));
528 dle->compprog = stralloc(tok + SIZEOF("srvcomp-cust=") -1);
529 dle->compress = COMP_SERVER_CUST;
531 else if (BSTRNCMP(tok, "comp-cust=") == 0) {
532 if (dle->compress != COMP_NONE) {
533 dbprintf(_("multiple compress option\n"));
535 g_printf(_("ERROR [multiple compress option]\n"));
538 dle->compprog = stralloc(tok + SIZEOF("comp-cust=") -1);
539 dle->compress = COMP_CUST;
540 /* parse encryption options */
542 else if (BSTRNCMP(tok, "encrypt-serv-cust=") == 0) {
543 if (dle->encrypt != ENCRYPT_NONE) {
544 dbprintf(_("multiple encrypt option\n"));
546 g_printf(_("ERROR [multiple encrypt option]\n"));
549 dle->srv_encrypt = stralloc(tok + SIZEOF("encrypt-serv-cust=") -1);
550 dle->encrypt = ENCRYPT_SERV_CUST;
552 else if (BSTRNCMP(tok, "encrypt-cust=") == 0) {
553 if (dle->encrypt != ENCRYPT_NONE) {
554 dbprintf(_("multiple encrypt option\n"));
556 g_printf(_("ERROR [multiple encrypt option]\n"));
559 dle->clnt_encrypt= stralloc(tok + SIZEOF("encrypt-cust=") -1);
560 dle->encrypt = ENCRYPT_CUST;
562 else if (BSTRNCMP(tok, "server-decrypt-option=") == 0) {
563 dle->srv_decrypt_opt = stralloc(tok + SIZEOF("server-decrypt-option=") -1);
565 else if (BSTRNCMP(tok, "client-decrypt-option=") == 0) {
566 dle->clnt_decrypt_opt = stralloc(tok + SIZEOF("client-decrypt-option=") -1);
568 else if (BSTRNCMP(tok, "no-record") == 0) {
569 if (dle->record != 1) {
570 dbprintf(_("multiple no-record option\n"));
572 g_printf(_("ERROR [multiple no-record option]\n"));
577 else if (BSTRNCMP(tok, "index") == 0) {
578 if (dle->create_index != 0) {
579 dbprintf(_("multiple index option\n"));
581 g_printf(_("ERROR [multiple index option]\n"));
584 dle->create_index = 1;
586 else if (BSTRNCMP(tok, "exclude-optional") == 0) {
587 if (dle->exclude_optional != 0) {
588 dbprintf(_("multiple exclude-optional option\n"));
590 g_printf(_("ERROR [multiple exclude-optional option]\n"));
593 dle->exclude_optional = 1;
595 else if (strcmp(tok, "include-optional") == 0) {
596 if (dle->include_optional != 0) {
597 dbprintf(_("multiple include-optional option\n"));
599 g_printf(_("ERROR [multiple include-optional option]\n"));
602 dle->include_optional = 1;
604 else if (BSTRNCMP(tok,"exclude-file=") == 0) {
605 exc = unquote_string(&tok[13]);
606 dle->exclude_file = append_sl(dle->exclude_file, exc);
609 else if (BSTRNCMP(tok,"exclude-list=") == 0) {
610 exc = unquote_string(&tok[13]);
611 dle->exclude_list = append_sl(dle->exclude_list, exc);
614 else if (BSTRNCMP(tok,"include-file=") == 0) {
615 inc = unquote_string(&tok[13]);
616 dle->include_file = append_sl(dle->include_file, inc);
619 else if (BSTRNCMP(tok,"include-list=") == 0) {
620 inc = unquote_string(&tok[13]);
621 dle->include_list = append_sl(dle->include_list, inc);
624 else if (BSTRNCMP(tok,"kencrypt") == 0) {
627 else if (strcmp(tok,"|") != 0) {
628 quoted = quote_string(tok);
629 dbprintf(_("unknown option %s\n"), quoted);
631 g_printf(_("ERROR [unknown option: %s]\n"), quoted);
635 tok = strtok(NULL, ";");
641 application_property_add_to_argv(
644 backup_support_option_t *bsu,
645 am_feature_t *amfeatures)
650 if (bsu->include_file && dle->include_file) {
651 for (incl = dle->include_file->first; incl != NULL;
653 g_ptr_array_add(argv_ptr, stralloc("--include-file"));
654 g_ptr_array_add(argv_ptr, stralloc(incl->name));
657 if (bsu->include_list && dle->include_list) {
658 for (incl = dle->include_list->first; incl != NULL;
660 g_ptr_array_add(argv_ptr, stralloc("--include-list"));
661 g_ptr_array_add(argv_ptr, stralloc(incl->name));
664 if (bsu->include_optional && dle->include_optional) {
665 g_ptr_array_add(argv_ptr, stralloc("--include-optional"));
666 g_ptr_array_add(argv_ptr, stralloc("yes"));
669 if (bsu->exclude_file && dle->exclude_file) {
670 for (excl = dle->exclude_file->first; excl != NULL;
672 g_ptr_array_add(argv_ptr, stralloc("--exclude-file"));
673 g_ptr_array_add(argv_ptr, stralloc(excl->name));
676 if (bsu->exclude_list && dle->exclude_list) {
677 for (excl = dle->exclude_list->first; excl != NULL;
679 g_ptr_array_add(argv_ptr, stralloc("--exclude-list"));
680 g_ptr_array_add(argv_ptr, stralloc(excl->name));
683 if (bsu->exclude_optional && dle->exclude_optional) {
684 g_ptr_array_add(argv_ptr, stralloc("--exclude-optional"));
685 g_ptr_array_add(argv_ptr, stralloc("yes"));
688 if (bsu->features && amfeatures) {
689 char *feature_string = am_feature_to_string(amfeatures);
690 g_ptr_array_add(argv_ptr, stralloc("--amfeatures"));
691 g_ptr_array_add(argv_ptr, feature_string);
694 if (dle->data_path == DATA_PATH_DIRECTTCP &&
695 bsu->data_path_set & DATA_PATH_DIRECTTCP) {
698 g_ptr_array_add(argv_ptr, stralloc("--data-path"));
699 g_ptr_array_add(argv_ptr, stralloc("directtcp"));
700 for (directtcp = dle->directtcp_list; directtcp != NULL;
701 directtcp = directtcp->next) {
702 g_ptr_array_add(argv_ptr, stralloc("--direct-tcp"));
703 g_ptr_array_add(argv_ptr, stralloc(directtcp->data));
704 break; /* XXX temporary; apps only support one ip:port pair */
709 g_hash_table_foreach(dle->application_property,
710 &proplist_add_to_argv, argv_ptr);
714 backup_support_option_t *
715 backup_support_option(
717 g_option_t *g_options,
720 GPtrArray **errarray)
723 int supportin, supportout, supporterr;
725 GPtrArray *argv_ptr = g_ptr_array_new();
731 backup_support_option_t *bsu;
733 *errarray = g_ptr_array_new();
734 cmd = vstralloc(APPLICATION_DIR, "/", program, NULL);
735 g_ptr_array_add(argv_ptr, stralloc(program));
736 g_ptr_array_add(argv_ptr, stralloc("support"));
737 if (g_options->config) {
738 g_ptr_array_add(argv_ptr, stralloc("--config"));
739 g_ptr_array_add(argv_ptr, stralloc(g_options->config));
741 if (g_options->hostname) {
742 g_ptr_array_add(argv_ptr, stralloc("--host"));
743 g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
746 g_ptr_array_add(argv_ptr, stralloc("--disk"));
747 g_ptr_array_add(argv_ptr, stralloc(disk));
750 g_ptr_array_add(argv_ptr, stralloc("--device"));
751 g_ptr_array_add(argv_ptr, stralloc(amdevice));
753 g_ptr_array_add(argv_ptr, NULL);
755 supporterr = fileno(stderr);
756 supportpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
757 &supportin, &supportout, &supporterr,
758 (char **)argv_ptr->pdata);
762 bsu = g_new0(backup_support_option_t, 1);
766 streamout = fdopen(supportout, "r");
768 error(_("Error opening pipe to child: %s"), strerror(errno));
771 while((line = agets(streamout)) != NULL) {
772 dbprintf(_("support line: %s\n"), line);
773 if (strncmp(line,"CONFIG ", 7) == 0) {
774 if (strcmp(line+7, "YES") == 0)
776 } else if (strncmp(line,"HOST ", 5) == 0) {
777 if (strcmp(line+5, "YES") == 0)
779 } else if (strncmp(line,"DISK ", 5) == 0) {
780 if (strcmp(line+5, "YES") == 0)
782 } else if (strncmp(line,"INDEX-LINE ", 11) == 0) {
783 if (strcmp(line+11, "YES") == 0)
785 } else if (strncmp(line,"INDEX-XML ", 10) == 0) {
786 if (strcmp(line+10, "YES") == 0)
788 } else if (strncmp(line,"MESSAGE-LINE ", 13) == 0) {
789 if (strcmp(line+13, "YES") == 0)
790 bsu->message_line = 1;
791 } else if (strncmp(line,"MESSAGE-XML ", 12) == 0) {
792 if (strcmp(line+12, "YES") == 0)
793 bsu->message_xml = 1;
794 } else if (strncmp(line,"RECORD ", 7) == 0) {
795 if (strcmp(line+7, "YES") == 0)
797 } else if (strncmp(line,"INCLUDE-FILE ", 13) == 0) {
798 if (strcmp(line+13, "YES") == 0)
799 bsu->include_file = 1;
800 } else if (strncmp(line,"INCLUDE-LIST ", 13) == 0) {
801 if (strcmp(line+13, "YES") == 0)
802 bsu->include_list = 1;
803 } else if (strncmp(line,"INCLUDE-LIST-GLOB ", 17) == 0) {
804 if (strcmp(line+17, "YES") == 0)
805 bsu->include_list_glob = 1;
806 } else if (strncmp(line,"INCLUDE-OPTIONAL ", 17) == 0) {
807 if (strcmp(line+17, "YES") == 0)
808 bsu->include_optional = 1;
809 } else if (strncmp(line,"EXCLUDE-FILE ", 13) == 0) {
810 if (strcmp(line+13, "YES") == 0)
811 bsu->exclude_file = 1;
812 } else if (strncmp(line,"EXCLUDE-LIST ", 13) == 0) {
813 if (strcmp(line+13, "YES") == 0)
814 bsu->exclude_list = 1;
815 } else if (strncmp(line,"EXCLUDE-LIST-GLOB ", 17) == 0) {
816 if (strcmp(line+17, "YES") == 0)
817 bsu->exclude_list_glob = 1;
818 } else if (strncmp(line,"EXCLUDE-OPTIONAL ", 17) == 0) {
819 if (strcmp(line+17, "YES") == 0)
820 bsu->exclude_optional = 1;
821 } else if (strncmp(line,"COLLECTION ", 11) == 0) {
822 if (strcmp(line+11, "YES") == 0)
824 } else if (strncmp(line,"CALCSIZE ", 9) == 0) {
825 if (strcmp(line+9, "YES") == 0)
827 } else if (strncmp(line,"CLIENT-ESTIMATE ", 16) == 0) {
828 if (strcmp(line+16, "YES") == 0)
829 bsu->client_estimate = 1;
830 } else if (strncmp(line,"MULTI-ESTIMATE ", 15) == 0) {
831 if (strcmp(line+15, "YES") == 0)
832 bsu->multi_estimate = 1;
833 } else if (strncmp(line,"MAX-LEVEL ", 10) == 0) {
834 bsu->max_level = atoi(line+10);
835 } else if (strncmp(line,"RECOVER-MODE ", 13) == 0) {
836 if (strcasecmp(line+13, "SMB") == 0)
837 bsu->smb_recover_mode = 1;
838 } else if (strncmp(line,"DATA-PATH ", 10) == 0) {
839 if (strcasecmp(line+10, "AMANDA") == 0)
840 bsu->data_path_set |= DATA_PATH_AMANDA;
841 else if (strcasecmp(line+10, "DIRECTTCP") == 0)
842 bsu->data_path_set |= DATA_PATH_DIRECTTCP;
843 } else if (strncmp(line,"RECOVER-PATH ", 13) == 0) {
844 if (strcasecmp(line+13, "CWD") == 0)
845 bsu->recover_path = RECOVER_PATH_CWD;
846 else if (strcasecmp(line+13, "REMOTE") == 0)
847 bsu->recover_path = RECOVER_PATH_REMOTE;
848 } else if (strncmp(line,"AMFEATURES ", 11) == 0) {
849 if (strcmp(line+11, "YES") == 0)
852 dbprintf(_("Invalid support line: %s\n"), line);
858 if (bsu->data_path_set == 0)
859 bsu->data_path_set = DATA_PATH_AMANDA;
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);
888 g_ptr_array_free_full(argv_ptr);
896 execute_on_t execute_on,
897 g_option_t *g_options,
901 int scriptin, scriptout, scripterr;
903 GPtrArray *argv_ptr = g_ptr_array_new();
907 amwait_t wait_status;
908 char *command = NULL;
910 if ((script->execute_on & execute_on) == 0)
912 if (script->execute_where != ES_CLIENT)
915 cmd = vstralloc(APPLICATION_DIR, "/", script->plugin, NULL);
916 g_ptr_array_add(argv_ptr, stralloc(script->plugin));
918 switch (execute_on) {
919 case EXECUTE_ON_PRE_DLE_AMCHECK:
920 command = "PRE-DLE-AMCHECK";
922 case EXECUTE_ON_PRE_HOST_AMCHECK:
923 command = "PRE-HOST-AMCHECK";
925 case EXECUTE_ON_POST_DLE_AMCHECK:
926 command = "POST-DLE-AMCHECK";
928 case EXECUTE_ON_POST_HOST_AMCHECK:
929 command = "POST-HOST-AMCHECK";
931 case EXECUTE_ON_PRE_DLE_ESTIMATE:
932 command = "PRE-DLE-ESTIMATE";
934 case EXECUTE_ON_PRE_HOST_ESTIMATE:
935 command = "PRE-HOST-ESTIMATE";
937 case EXECUTE_ON_POST_DLE_ESTIMATE:
938 command = "POST-DLE-ESTIMATE";
940 case EXECUTE_ON_POST_HOST_ESTIMATE:
941 command = "POST-HOST-ESTIMATE";
943 case EXECUTE_ON_PRE_DLE_BACKUP:
944 command = "PRE-DLE-BACKUP";
946 case EXECUTE_ON_PRE_HOST_BACKUP:
947 command = "PRE-HOST-BACKUP";
949 case EXECUTE_ON_POST_DLE_BACKUP:
950 command = "POST-DLE-BACKUP";
952 case EXECUTE_ON_POST_HOST_BACKUP:
953 command = "POST-HOST-BACKUP";
955 case EXECUTE_ON_PRE_RECOVER:
956 command = "PRE-RECOVER";
958 case EXECUTE_ON_POST_RECOVER:
959 command = "POST-RECOVER";
961 case EXECUTE_ON_PRE_LEVEL_RECOVER:
962 command = "PRE-LEVEL-RECOVER";
964 case EXECUTE_ON_POST_LEVEL_RECOVER:
965 command = "POST-LEVEL-RECOVER";
967 case EXECUTE_ON_INTER_LEVEL_RECOVER:
968 command = "INTER-LEVEL-RECOVER";
971 g_ptr_array_add(argv_ptr, stralloc(command));
972 g_ptr_array_add(argv_ptr, stralloc("--execute-where"));
973 g_ptr_array_add(argv_ptr, stralloc("client"));
975 if (g_options->config) {
976 g_ptr_array_add(argv_ptr, stralloc("--config"));
977 g_ptr_array_add(argv_ptr, stralloc(g_options->config));
979 if (g_options->hostname) {
980 g_ptr_array_add(argv_ptr, stralloc("--host"));
981 g_ptr_array_add(argv_ptr, stralloc(g_options->hostname));
984 g_ptr_array_add(argv_ptr, stralloc("--disk"));
985 g_ptr_array_add(argv_ptr, stralloc(dle->disk));
988 g_ptr_array_add(argv_ptr, stralloc("--device"));
989 g_ptr_array_add(argv_ptr, stralloc(dle->device));
991 if (dle->levellist) {
992 levellist_t levellist;
993 char number[NUM_STR_SIZE];
994 for (levellist=dle->levellist; levellist; levellist=levellist->next) {
995 level_t *alevel = (level_t *)levellist->data;
996 g_ptr_array_add(argv_ptr, stralloc("--level"));
997 g_snprintf(number, SIZEOF(number), "%d", alevel->level);
998 g_ptr_array_add(argv_ptr, stralloc(number));
1001 property_add_to_argv(argv_ptr, script->property);
1002 g_ptr_array_add(argv_ptr, NULL);
1004 scriptpid = pipespawnv(cmd, STDIN_PIPE|STDOUT_PIPE|STDERR_PIPE, 0,
1005 &scriptin, &scriptout, &scripterr,
1006 (char **)argv_ptr->pdata);
1010 script->result = g_new0(client_script_result_t, 1);
1011 script->result->proplist =
1012 g_hash_table_new_full(g_str_hash, g_str_equal, NULL, NULL);
1013 script->result->output = g_ptr_array_new();
1014 script->result->err = g_ptr_array_new();
1016 streamout = fdopen(scriptout, "r");
1018 while((line = agets(streamout)) != NULL) {
1019 dbprintf("script: %s\n", line);
1020 if (BSTRNCMP(line, "PROPERTY ") == 0) {
1021 char *property_name, *property_value;
1022 property_name = line + 9;
1023 property_value = strchr(property_name,' ');
1024 if (property_value == NULL) {
1025 char *msg = g_strdup_printf(
1026 "ERROR %s: Bad output property: %s",
1027 script->plugin, line);
1028 g_ptr_array_add(script->result->output, msg);
1030 property_t *property;
1032 *property_value++ = '\0';
1033 property_name = stralloc(property_name);
1034 property_value = stralloc(property_value);
1035 property = g_hash_table_lookup(script->result->proplist,
1038 property = g_new0(property_t, 1);
1039 g_hash_table_insert(script->result->proplist,
1040 property_name, property);
1042 property->values = g_slist_append(property->values,
1047 g_ptr_array_add(script->result->output, line);
1053 streamerr = fdopen(scripterr, "r");
1055 while((line = agets(streamerr)) != NULL) {
1056 g_ptr_array_add(script->result->err,
1057 g_strdup_printf(_("Script '%s' command '%s': %s"),
1058 script->plugin, command, line));
1063 waitpid(scriptpid, &wait_status, 0);
1064 if (WIFSIGNALED(wait_status)) {
1065 g_ptr_array_add(script->result->err,
1066 g_strdup_printf(_("Script '%s' command '%s' terminated with signal %d: see %s"),
1067 script->plugin, command,
1068 WTERMSIG(wait_status),
1070 } else if (WIFEXITED(wait_status)) {
1071 if (WEXITSTATUS(wait_status) != 0) {
1072 g_ptr_array_add(script->result->err,
1073 g_strdup_printf(_("Script '%s' command '%s' exited with status %d: see %s"),
1074 script->plugin, command,
1075 WEXITSTATUS(wait_status),
1082 g_ptr_array_free_full(argv_ptr);
1085 void run_client_script_output(gpointer data, gpointer user_data);
1086 void run_client_script_err_amcheck(gpointer data, gpointer user_data);
1087 void run_client_script_err_estimate(gpointer data, gpointer user_data);
1088 void run_client_script_err_backup(gpointer data, gpointer user_data);
1089 void run_client_script_err_recover(gpointer data, gpointer user_data);
1091 typedef struct script_output_s {
1097 run_client_script_output(
1102 script_output_t *so = user_data;
1104 if (line && so->stream) {
1105 g_fprintf(so->stream, "%s\n", line);
1110 run_client_script_err_amcheck(
1115 script_output_t *so = user_data;
1117 if (line && so->stream) {
1118 g_fprintf(so->stream, "ERROR %s\n", line);
1123 run_client_script_err_estimate(
1128 script_output_t *so = user_data;
1130 if (line && so->stream) {
1131 char *qdisk = quote_string(so->dle->disk);
1132 g_fprintf(so->stream, "%s 0 WARNING \"%s\"\n", qdisk, line);
1138 run_client_script_err_backup(
1143 script_output_t *so = user_data;
1145 if (line && so->stream) {
1146 g_fprintf(so->stream, "? %s\n", line);
1151 run_client_script_err_recover(
1156 script_output_t *so = user_data;
1158 if (line && so->stream) {
1159 g_fprintf(so->stream, "%s\n", line);
1165 execute_on_t execute_on,
1166 g_option_t *g_options,
1172 GFunc client_script_err = NULL;
1173 script_output_t so = { streamout, dle };
1175 for (scriptlist = dle->scriptlist; scriptlist != NULL;
1176 scriptlist = scriptlist->next) {
1177 script = (script_t *)scriptlist->data;
1178 run_client_script(script, execute_on, g_options, dle);
1179 if (script->result && script->result->output) {
1180 g_ptr_array_foreach(script->result->output,
1181 run_client_script_output,
1183 g_ptr_array_free(script->result->output, TRUE);
1184 script->result->output = NULL;
1186 if (script->result && script->result->err) {
1187 switch (execute_on) {
1188 case EXECUTE_ON_PRE_DLE_AMCHECK:
1189 case EXECUTE_ON_PRE_HOST_AMCHECK:
1190 case EXECUTE_ON_POST_DLE_AMCHECK:
1191 case EXECUTE_ON_POST_HOST_AMCHECK:
1192 client_script_err = run_client_script_err_amcheck;
1194 case EXECUTE_ON_PRE_DLE_ESTIMATE:
1195 case EXECUTE_ON_PRE_HOST_ESTIMATE:
1196 case EXECUTE_ON_POST_DLE_ESTIMATE:
1197 case EXECUTE_ON_POST_HOST_ESTIMATE:
1198 if (am_has_feature(g_options->features,
1199 fe_sendsize_rep_warning)) {
1200 client_script_err = run_client_script_err_estimate;
1203 case EXECUTE_ON_PRE_DLE_BACKUP:
1204 case EXECUTE_ON_PRE_HOST_BACKUP:
1205 case EXECUTE_ON_POST_DLE_BACKUP:
1206 case EXECUTE_ON_POST_HOST_BACKUP:
1207 client_script_err = run_client_script_err_backup;
1209 case EXECUTE_ON_PRE_RECOVER:
1210 case EXECUTE_ON_POST_RECOVER:
1211 case EXECUTE_ON_PRE_LEVEL_RECOVER:
1212 case EXECUTE_ON_POST_LEVEL_RECOVER:
1213 case EXECUTE_ON_INTER_LEVEL_RECOVER:
1214 client_script_err = run_client_script_err_recover;
1216 if (client_script_err != NULL) {
1217 g_ptr_array_foreach(script->result->err,
1221 g_ptr_array_free(script->result->err, TRUE);
1222 script->result->err = NULL;
1238 char *cmd, *cmdline;
1240 GPtrArray *argv_ptr = g_ptr_array_new();
1241 char tmppath[PATH_MAX];
1242 char number[NUM_STR_SIZE];
1247 int pipefd = -1, nullfd = -1;
1250 FILE *dumpout = NULL;
1252 char *errmsg = NULL;
1253 off_t size = (off_t)1;
1255 amwait_t wait_status;
1259 char *amandates_file;
1261 qdisk = quote_string(disk);
1263 amandates_file = getconf_str(CNF_AMANDATES);
1264 if(!start_amandates(amandates_file, 0)) {
1265 char *errstr = strerror(errno);
1266 char *errmsg = vstrallocf(_("could not open %s: %s"), amandates_file, errstr);
1267 char *qerrmsg = quote_string(errmsg);
1268 g_printf(_("ERROR %s\n"), qerrmsg);
1276 cmd = vstralloc(amlibexecdir, "/", "calcsize", NULL);
1279 g_ptr_array_add(argv_ptr, stralloc("calcsize"));
1281 g_ptr_array_add(argv_ptr, stralloc(config));
1283 g_ptr_array_add(argv_ptr, stralloc("NOCONFIG"));
1285 g_ptr_array_add(argv_ptr, stralloc(program));
1287 canonicalize_pathname(disk, tmppath);
1288 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1289 canonicalize_pathname(dirname, tmppath);
1290 g_ptr_array_add(argv_ptr, stralloc(tmppath));
1293 g_ptr_array_add(argv_ptr, stralloc("-X"));
1294 g_ptr_array_add(argv_ptr, stralloc(file_exclude));
1298 g_ptr_array_add(argv_ptr, stralloc("-I"));
1299 g_ptr_array_add(argv_ptr, stralloc(file_include));
1302 for (alevel = levels; alevel != NULL; alevel = alevel->next) {
1303 amdp = amandates_lookup(disk);
1304 level = GPOINTER_TO_INT(alevel->data);
1305 dbprintf("level: %d\n", level);
1307 for (i=0; i < level; i++) {
1308 if (dumpsince < amdp->dates[i])
1309 dumpsince = amdp->dates[i];
1311 g_snprintf(number, SIZEOF(number), "%d", level);
1312 g_ptr_array_add(argv_ptr, stralloc(number));
1313 g_snprintf(number, SIZEOF(number), "%d", dumpsince);
1314 g_ptr_array_add(argv_ptr, stralloc(number));
1317 g_ptr_array_add(argv_ptr, NULL);
1318 command = (char *)g_ptr_array_index(argv_ptr, 0);
1319 cmdline = stralloc(command);
1320 for(i = 1; i < argv_ptr->len - 1; i++)
1321 cmdline = vstrextend(&cmdline, " ",
1322 (char *)g_ptr_array_index(argv_ptr,i), NULL);
1323 dbprintf(_("running: \"%s\"\n"), cmdline);
1326 start_time = curclock();
1328 fflush(stderr); fflush(stdout);
1330 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
1331 errmsg = vstrallocf(_("Cannot access /dev/null : %s"),
1333 dbprintf("%s\n", errmsg);
1337 calcpid = pipespawnv(cmd, STDERR_PIPE, 0,
1338 &nullfd, &nullfd, &pipefd, (char **)argv_ptr->pdata);
1341 dumpout = fdopen(pipefd,"r");
1343 error(_("Can't fdopen: %s"), strerror(errno));
1347 match_expr = vstralloc(" %d SIZE %lld", NULL);
1348 len = strlen(qdisk);
1349 for(size = (off_t)-1; (line = agets(dumpout)) != NULL; free(line)) {
1350 long long size_ = (long long)0;
1351 if (line[0] == '\0' || (int)strlen(line) <= len)
1353 /* Don't use sscanf for qdisk because it can have a '%'. */
1354 if (strncmp(line, qdisk, len) == 0 &&
1355 sscanf(line+len, match_expr, &level, &size_) == 2) {
1356 g_printf("%d %lld %d\n", level, size_, 1); /* write to sendsize */
1357 dbprintf(_("estimate size for %s level %d: %lld KB\n"),
1358 qdisk, level, size_);
1360 size = (off_t)size_;
1364 dbprintf(_("waiting for %s %s child (pid=%d)\n"),
1365 command, qdisk, (int)calcpid);
1366 waitpid(calcpid, &wait_status, 0);
1367 if (WIFSIGNALED(wait_status)) {
1368 errmsg = vstrallocf(_("%s terminated with signal %d: see %s"),
1369 "calcsize", WTERMSIG(wait_status),
1371 } else if (WIFEXITED(wait_status)) {
1372 if (WEXITSTATUS(wait_status) != 0) {
1373 errmsg = vstrallocf(_("%s exited with status %d: see %s"),
1374 "calcsize", WEXITSTATUS(wait_status),
1380 errmsg = vstrallocf(_("%s got bad exit: see %s"),
1381 "calcsize", dbfn());
1384 dbprintf(_("after %s %s wait: child pid=%d status=%d\n"),
1386 (int)calcpid, WEXITSTATUS(wait_status));
1388 dbprintf(_(".....\n"));
1389 dbprintf(_("estimate time for %s: %s\n"),
1391 walltime_str(timessub(curclock(), start_time)));
1394 if (errmsg && errmsg[0] != '\0') {
1395 char *qerrmsg = quote_string(errmsg);
1396 dbprintf(_("errmsg is %s\n"), errmsg);
1397 g_printf("ERROR %s\n", qerrmsg);
1402 g_ptr_array_free_full(argv_ptr);
1413 char *noun, *adjective;
1414 char *quoted = quote_string(filename);
1417 noun = "find", adjective = "exists";
1418 else if((mode & X_OK) == X_OK)
1419 noun = "execute", adjective = "executable";
1420 else if((mode & (W_OK|R_OK)) == (W_OK|R_OK))
1421 noun = "read/write", adjective = "read/writable";
1423 noun = "access", adjective = "accessible";
1425 if(access(filename, mode) == -1)
1426 g_printf(_("ERROR [can not %s %s: %s]\n"), noun, quoted, strerror(errno));
1428 g_printf(_("OK %s %s\n"), quoted, adjective);
1437 struct stat stat_buf;
1440 if(!stat(filename, &stat_buf)) {
1441 if(!S_ISREG(stat_buf.st_mode)) {
1442 quoted = quote_string(filename);
1443 g_printf(_("ERROR [%s is not a file]\n"), quoted);
1447 int save_errno = errno;
1448 quoted = quote_string(filename);
1449 g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
1450 strerror(save_errno));
1453 if (getuid() == geteuid()) {
1454 check_access(filename, mode);
1463 struct stat stat_buf;
1467 if(!stat(dirname, &stat_buf)) {
1468 if(!S_ISDIR(stat_buf.st_mode)) {
1469 quoted = quote_string(dirname);
1470 g_printf(_("ERROR [%s is not a directory]\n"), quoted);
1474 int save_errno = errno;
1475 quoted = quote_string(dirname);
1476 g_printf(_("ERROR [can not stat %s: %s]\n"), quoted,
1477 strerror(save_errno));
1480 if (getuid() == geteuid()) {
1481 dir = stralloc2(dirname, "/.");
1482 check_access(dir, mode);
1491 #ifndef SINGLE_USERID
1492 struct stat stat_buf;
1493 char *quoted = quote_string(filename);
1495 if(!stat(filename, &stat_buf)) {
1496 if(stat_buf.st_uid != 0 ) {
1497 g_printf(_("ERROR [%s is not owned by root]\n"), quoted);
1499 if((stat_buf.st_mode & S_ISUID) != S_ISUID) {
1500 g_printf(_("ERROR [%s is not SUID root]\n"), quoted);
1504 g_printf(_("ERROR [can not stat %s: %s]\n"), quoted, strerror(errno));
1508 (void)filename; /* Quiet unused parameter warning */
1513 * Returns the value of the first integer in a string.
1527 while(ch && !isdigit(ch)) ch = *str++;
1528 if (pos == 1) break;
1530 while(ch && (isdigit(ch) || ch == '.')) ch = *str++;
1533 while(isdigit(ch) || ch == '.') ch = *str++;
1542 config_errors_to_error_string(
1546 gboolean multiple_errors = FALSE;
1549 errmsg = (char *)errlist->data;
1551 multiple_errors = TRUE;
1553 errmsg = _("(no error message)");
1556 return vstrallocf("ERROR %s%s", errmsg,
1557 multiple_errors? _(" (additional errors not displayed)"):"");
1564 amregex_t **re_table,
1565 amregex_t *orig_re_table,
1566 GSList *normal_message,
1567 GSList *ignore_message,
1568 GSList *strange_message)
1572 for(rp = orig_re_table; rp->regex != NULL; rp++) {
1573 if (rp->typ == typ) {
1577 for (mes = normal_message; mes != NULL; mes = mes->next) {
1578 if (strcmp(rp->regex, (char *)mes->data) == 0)
1581 for (mes = ignore_message; mes != NULL; mes = mes->next) {
1582 if (strcmp(rp->regex, (char *)mes->data) == 0)
1585 for (mes = strange_message; mes != NULL; mes = mes->next) {
1586 if (strcmp(rp->regex, (char *)mes->data) == 0)
1590 (*re_table)->regex = rp->regex;
1591 (*re_table)->srcline = rp->srcline;
1592 (*re_table)->scale = rp->scale;
1593 (*re_table)->field = rp->field;
1594 (*re_table)->typ = rp->typ;
1604 amregex_t **re_table,
1609 for (mes = message; mes != NULL; mes = mes->next) {
1610 (*re_table)->regex = (char *)mes->data;
1611 (*re_table)->srcline = 0;
1612 (*re_table)->scale = 0;
1613 (*re_table)->field = 0;
1614 (*re_table)->typ = typ;
1621 amregex_t *orig_re_table,
1622 GSList *normal_message,
1623 GSList *ignore_message,
1624 GSList *strange_message)
1628 amregex_t *re_table, *new_re_table;
1630 for(rp = orig_re_table; rp->regex != NULL; rp++) {
1633 nb += g_slist_length(normal_message);
1634 nb += g_slist_length(ignore_message);
1635 nb += g_slist_length(strange_message);
1638 re_table = new_re_table = malloc(nb * sizeof(amregex_t));
1640 /* add SIZE from orig_re_table */
1641 add_type_table(DMP_SIZE, &re_table, orig_re_table,
1642 normal_message, ignore_message, strange_message);
1644 /* add ignore_message */
1645 add_list_table(DMP_IGNORE, &re_table, ignore_message);
1647 /* add IGNORE from orig_re_table */
1648 add_type_table(DMP_IGNORE, &re_table, orig_re_table,
1649 normal_message, ignore_message, strange_message);
1651 /* add normal_message */
1652 add_list_table(DMP_NORMAL, &re_table, normal_message);
1654 /* add NORMAL from orig_re_table */
1655 add_type_table(DMP_NORMAL, &re_table, orig_re_table,
1656 normal_message, ignore_message, strange_message);
1658 /* add strange_message */
1659 add_list_table(DMP_STRANGE, &re_table, strange_message);
1661 /* add STRANGE from orig_re_table */
1662 add_type_table(DMP_STRANGE, &re_table, orig_re_table,
1663 normal_message, ignore_message, strange_message);
1665 /* Add DMP_STRANGE with NULL regex, */
1666 /* it is not copied by previous statement */
1667 re_table->regex = NULL;
1668 re_table->srcline = 0;
1669 re_table->scale = 0;
1670 re_table->field = 0;
1671 re_table->typ = DMP_STRANGE;
1673 return new_re_table;
1684 gpointer user_data_p)
1686 char *property_s = key_p;
1687 GSList *value_s = value_p;
1688 merge_property_t *merge_p = user_data_p;
1689 GSList *value = g_hash_table_lookup(merge_p->result, property_s);
1691 if (value) { /* remove old value */
1692 g_hash_table_remove(merge_p->result, key_p);
1694 g_hash_table_insert(merge_p->result, key_p, value_s);
1699 proplist_t proplist1,
1700 proplist_t proplist2)
1702 merge_property_t merge_p = {proplist1};
1704 if (proplist2 == NULL) {
1707 g_hash_table_foreach(proplist2,