2 * Amanda, The Advanced Maryland Automatic Network Disk Archiver
3 * Copyright (c) 1991-2000 University of Maryland at College Park
4 * Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
7 * Permission to use, copy, modify, distribute, and sell this software and its
8 * documentation for any purpose is hereby granted without fee, provided that
9 * the above copyright notice appear in all copies and that both that
10 * copyright notice and this permission notice appear in supporting
11 * documentation, and that the name of U.M. not be used in advertising or
12 * publicity pertaining to distribution of the software without specific,
13 * written prior permission. U.M. makes no representations about the
14 * suitability of this software for any purpose. It is provided "as is"
15 * without express or implied warranty.
17 * U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
19 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
20 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
21 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
22 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
24 * Authors: the Amanda Development Team. Its members are listed in a
25 * file named AUTHORS, in the root directory of this distribution.
28 * $Id: amcheck.c,v 1.149 2006/08/24 01:57:16 paddy_s Exp $
30 * checks for common problems in server and clients
44 #include "server_util.h"
45 #include "pipespawn.h"
46 #include "amfeatures.h"
49 #include "timestamp.h"
54 #define BUFFER_SIZE 32768
56 static time_t conf_ctimeout;
59 static disklist_t origq;
61 static uid_t uid_dumpuser;
66 pid_t start_client_checks(int fd);
67 pid_t start_server_check(int fd, int do_localchk, int do_tapechk);
68 int main(int argc, char **argv);
69 int check_tapefile(FILE *outf, char *tapefile);
70 int test_server_pgm(FILE *outf, char *dir, char *pgm, int suid, uid_t dumpuid);
75 g_printf(_("Usage: amcheck [--version] [-am] [-w] [-sclt] [-M <address>] [--client-verbose] [--exact_match] [-o configoption]* <conf> [host [disk]* ]*\n"));
80 static am_feature_t *our_features = NULL;
81 static char *our_feature_string = NULL;
82 static char *displayunit;
83 static long int unitdivisor;
85 static int client_verbose = FALSE;
86 static gboolean exact_match = FALSE;
87 static struct option long_options[] = {
88 {"client-verbose", 0, NULL, 1},
89 {"version" , 0, NULL, 2},
90 {"exact-match" , 0, NULL, 3},
99 char buffer[BUFFER_SIZE];
100 char *version_string;
101 char *mainfname = NULL;
102 char pid_str[NUM_STR_SIZE];
103 int do_clientchk, client_probs;
104 int do_localchk, do_tapechk, server_probs;
105 pid_t clientchk_pid, serverchk_pid;
115 char *tempfname = NULL;
121 config_overrides_t *cfg_ovr;
125 * Configure program for internationalization:
126 * 1) Only set the message locale for now.
127 * 2) Set textdomain for all amanda related programs to "amanda"
128 * We don't want to be forced to support dozens of message catalogs.
130 setlocale(LC_MESSAGES, "C");
131 textdomain("amanda");
136 set_pname("amcheck");
137 /* drop root privileges */
138 if (!set_root_privs(0)) {
139 error(_("amcheck must be run setuid root"));
142 /* Don't die when child closes pipe */
143 signal(SIGPIPE, SIG_IGN);
145 dbopen(DBG_SUBDIR_SERVER);
147 memset(buffer, 0, sizeof(buffer));
149 g_snprintf(pid_str, SIZEOF(pid_str), "%ld", (long)getpid());
151 add_amanda_log_handler(amanda_log_stderr);
153 our_features = am_init_feature_set();
154 our_feature_string = am_feature_to_string(our_features);
158 alwaysmail = mailout = overwrite = 0;
159 do_localchk = do_tapechk = do_clientchk = 0;
160 server_probs = client_probs = 0;
161 tempfd = mainfd = -1;
163 /* process arguments */
165 cfg_ovr = new_config_overrides(argc/2);
167 int option_index = 0;
169 c = getopt_long (argc, argv, "M:mawsclto:", long_options, &option_index);
175 case 1: client_verbose = TRUE;
177 case 2: printf("amcheck-%s\n", VERSION);
180 case 3: exact_match = TRUE;
182 case 'M': if (mailto) {
183 g_printf(_("Multiple -M options\n"));
186 mailto=stralloc(optarg);
187 if(!validate_mailto(mailto)){
188 g_printf(_("Invalid characters in mail address\n"));
199 case 's': do_localchk = do_tapechk = 1;
201 case 'c': do_clientchk = 1;
203 case 'l': do_localchk = 1;
205 case 'w': overwrite = 1;
207 case 'o': add_config_override_opt(cfg_ovr, optarg);
209 case 't': do_tapechk = 1;
216 argc -= optind, argv += optind;
217 if(argc < 1) usage();
220 if ((do_localchk | do_clientchk | do_tapechk) == 0) {
221 /* Check everything if individual checks were not asked for */
222 do_localchk = do_clientchk = do_tapechk = 1;
228 set_config_overrides(cfg_ovr);
229 config_init(CONFIG_INIT_EXPLICIT_NAME, argv[0]);
230 dbrename(get_config_name(), DBG_SUBDIR_SERVER);
232 conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
233 read_diskfile(conf_diskfile, &origq);
234 disable_skip_disk(&origq);
235 amfree(conf_diskfile);
237 if (config_errors(NULL) >= CFGERR_WARNINGS) {
238 config_print_errors();
239 if (config_errors(NULL) >= CFGERR_ERRORS) {
240 g_critical(_("errors processing config file"));
244 mailer = getconf_str(CNF_MAILER);
245 if ((!mailer || *mailer == '\0') && mailout == 1) {
246 if (alwaysmail == 1) {
247 g_printf(_("You can't use -a because a mailer is not defined\n"));
249 g_printf(_("You can't use -m because a mailer is not defined\n"));
253 if(mailout && !mailto &&
254 (getconf_seen(CNF_MAILTO)==0 || strlen(getconf_str(CNF_MAILTO)) == 0)) {
255 g_printf(_("\nWARNING:No mail address configured in amanda.conf.\n"));
256 g_printf(_("To receive dump results by email configure the "
257 "\"mailto\" parameter in amanda.conf\n"));
259 g_printf(_("When using -a option please specify -Maddress also\n\n"));
261 g_printf(_("Use -Maddress instead of -m\n\n"));
264 if(mailout && !mailto)
266 if(getconf_seen(CNF_MAILTO) &&
267 strlen(getconf_str(CNF_MAILTO)) > 0) {
268 if(!validate_mailto(getconf_str(CNF_MAILTO))){
269 g_printf(_("\nMail address in amanda.conf has invalid characters"));
270 g_printf(_("\nNo email will be sent\n"));
275 g_printf(_("\nNo mail address configured in amanda.conf\n"));
277 g_printf(_("When using -a option please specify -Maddress also\n\n"));
279 g_printf(_("Use -Maddress instead of -m\n\n"));
284 conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT);
286 errstr = match_disklist(&origq, exact_match, argc-1, argv+1);
288 g_printf(_("%s"),errstr);
293 * Make sure we are running as the dump user. Don't use
294 * check_running_as(..) here, because we want to produce more
295 * verbose error messages.
297 dumpuser = getconf_str(CNF_DUMPUSER);
298 if ((pw = getpwnam(dumpuser)) == NULL) {
299 error(_("amanda.conf has dump user configured to \"%s\", but that user does not exist."), dumpuser);
302 uid_dumpuser = pw->pw_uid;
303 if ((pw = getpwuid(uid_me)) == NULL) {
304 error(_("cannot get username for running user, uid %ld is not in your user database."),
309 if (uid_me != uid_dumpuser) {
310 error(_("running as user \"%s\" instead of \"%s\".\n"
311 "Change user to \"%s\" or change dump user to \"%s\" in amanda.conf"),
312 pw->pw_name, dumpuser, dumpuser, pw->pw_name);
317 displayunit = getconf_str(CNF_DISPLAYUNIT);
318 unitdivisor = getconf_unit_divisor();
321 * If both server and client side checks are being done, the server
322 * check output goes to the main output, while the client check output
323 * goes to a temporary file and is copied to the main output when done.
325 * If the output is to be mailed, the main output is also a disk file,
326 * otherwise it is stdout.
328 if(do_clientchk && (do_localchk || do_tapechk)) {
329 /* we need the temp file */
330 tempfname = vstralloc(AMANDA_TMPDIR, "/amcheck.temp.", pid_str, NULL);
331 if((tempfd = open(tempfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) {
332 error(_("could not open temporary amcheck output file %s: %s. Check permissions"), tempfname, strerror(errno));
335 unlink(tempfname); /* so it goes away on close */
340 /* the main fd is a file too */
341 mainfname = vstralloc(AMANDA_TMPDIR, "/amcheck.main.", pid_str, NULL);
342 if((mainfd = open(mainfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) {
343 error(_("could not open amcheck server output file %s: %s. Check permissions"), mainfname, strerror(errno));
346 unlink(mainfname); /* so it goes away on close */
350 /* just use stdout */
353 /* start server side checks */
355 if(do_localchk || do_tapechk)
356 serverchk_pid = start_server_check(mainfd, do_localchk, do_tapechk);
360 /* start client side checks */
363 clientchk_pid = start_client_checks((do_localchk || do_tapechk) ? tempfd : mainfd);
368 /* wait for child processes and note any problems */
371 if((pid = wait(&retstat)) == -1) {
372 if(errno == EINTR) continue;
374 } else if(pid == clientchk_pid) {
375 client_probs = WIFSIGNALED(retstat) || WEXITSTATUS(retstat);
377 } else if(pid == serverchk_pid) {
378 server_probs = WIFSIGNALED(retstat) || WEXITSTATUS(retstat);
381 char *wait_msg = NULL;
383 wait_msg = vstrallocf(_("parent: reaped bogus pid %ld\n"), (long)pid);
384 if (full_write(mainfd, wait_msg, strlen(wait_msg)) < strlen(wait_msg)) {
385 error(_("write main file: %s"), strerror(errno));
392 /* copy temp output to main output and write tagline */
394 if(do_clientchk && (do_localchk || do_tapechk)) {
395 if(lseek(tempfd, (off_t)0, 0) == (off_t)-1) {
396 error(_("seek temp file: %s"), strerror(errno));
400 while((size = full_read(tempfd, buffer, SIZEOF(buffer))) > 0) {
401 if (full_write(mainfd, buffer, size) < size) {
402 error(_("write main file: %s"), strerror(errno));
407 error(_("read temp file: %s"), strerror(errno));
413 version_string = vstrallocf(_("\n(brought to you by Amanda %s)\n"), VERSION);
414 if (full_write(mainfd, version_string, strlen(version_string)) < strlen(version_string)) {
415 error(_("write main file: %s"), strerror(errno));
418 amfree(version_string);
419 amfree(our_feature_string);
420 am_release_feature_set(our_features);
423 /* send mail if requested, but only if there were problems */
425 if((server_probs || client_probs || alwaysmail) && mailout) {
437 char *extra_info = NULL;
442 if(lseek(mainfd, (off_t)0, SEEK_SET) == (off_t)-1) {
443 error(_("lseek main file: %s"), strerror(errno));
446 if(alwaysmail && !(server_probs || client_probs)) {
447 subject = vstrallocf(_("%s AMCHECK REPORT: NO PROBLEMS FOUND"),
448 getconf_str(CNF_ORG));
450 subject = vstrallocf(
451 _("%s AMANDA PROBLEM: FIX BEFORE RUN, IF POSSIBLE"),
452 getconf_str(CNF_ORG));
455 a = (char **) g_new0(char *, 2);
456 a[1] = stralloc(mailto);
459 /* (note that validate_mailto doesn't allow any quotes, so this
460 * is really just splitting regular old strings) */
461 a = split_quoted_strings(getconf_str(CNF_MAILTO));
463 if((nullfd = open("/dev/null", O_RDWR)) < 0) {
464 error("nullfd: /dev/null: %s", strerror(errno));
468 /* assemble the command line for the mailer */
469 pipeargs = g_ptr_array_sized_new(4);
470 g_ptr_array_add(pipeargs, mailer);
471 g_ptr_array_add(pipeargs, "-s");
472 g_ptr_array_add(pipeargs, subject);
474 g_ptr_array_add(pipeargs, *b);
475 g_ptr_array_add(pipeargs, NULL);
477 pipespawnv(mailer, STDIN_PIPE | STDERR_PIPE, 0,
478 &mailfd, &nullfd, &errfd,
479 (char **)pipeargs->pdata);
481 g_ptr_array_free(pipeargs, FALSE);
487 * There is the potential for a deadlock here since we are writing
488 * to the process and then reading stderr, but in the normal case,
489 * nothing should be coming back to us, and hopefully in error
490 * cases, the pipe will break and we will exit out of the loop.
492 signal(SIGPIPE, SIG_IGN);
493 while((r = full_read(mainfd, buffer, SIZEOF(buffer))) > 0) {
494 if((w = full_write(mailfd, buffer, r)) != r) {
496 strappend(extra_info, _("EPIPE writing to mail process\n"));
498 } else if(errno != 0) {
499 error(_("mailfd write: %s"), strerror(errno));
502 error(_("mailfd write: wrote %zd instead of %zd"), w, r);
508 ferr = fdopen(errfd, "r");
510 error(_("Can't fdopen: %s"), strerror(errno));
513 for(; (line = agets(ferr)) != NULL; free(line)) {
516 strappend(extra_info, line);
517 strappend(extra_info, "\n");
522 while (wait(&retstat) != -1) {
523 if (!WIFEXITED(retstat) || WEXITSTATUS(retstat) != 0) {
524 char *mailer_error = str_exit_status("mailer", retstat);
525 strappend(err, mailer_error);
526 amfree(mailer_error);
533 fputs(extra_info, stderr);
536 error(_("error running mailer %s: %s"), mailer, err?err:"(unknown)");
542 return (server_probs || client_probs);
545 /* --------------------------------------------------- */
547 static char *datestamp;
548 static FILE *errf = NULL;
558 if (stat(tapefile, &statbuf) == 0) {
559 if (!S_ISREG(statbuf.st_mode)) {
560 quoted = quote_string(tapefile);
561 g_fprintf(outf, _("ERROR: tapelist %s: should be a regular file.\n"),
565 } else if (access(tapefile, F_OK) != 0) {
566 quoted = quote_string(tapefile);
567 g_fprintf(outf, _("ERROR: can't access tapelist %s\n"), quoted);
570 } else if (access(tapefile, W_OK) != 0) {
571 quoted = quote_string(tapefile);
572 g_fprintf(outf, _("ERROR: tapelist %s: not writable\n"), quoted);
592 pgm = vstralloc(dir, "/", pgm, NULL);
593 quoted = quote_string(pgm);
594 if(stat(pgm, &statbuf) == -1) {
595 g_fprintf(outf, _("ERROR: program %s: does not exist\n"),
598 } else if (!S_ISREG(statbuf.st_mode)) {
599 g_fprintf(outf, _("ERROR: program %s: not a file\n"),
602 } else if (access(pgm, X_OK) == -1) {
603 g_fprintf(outf, _("ERROR: program %s: not executable\n"),
606 #ifndef SINGLE_USERID
609 && (statbuf.st_uid != 0 || (statbuf.st_mode & 04000) == 0)) {
610 g_fprintf(outf, _("ERROR: program %s: not setuid-root\n"),
614 /* Quiet unused parameter warnings */
617 #endif /* SINGLE_USERID */
624 /* check that the tape is a valid amanda tape
625 Returns TRUE if all tests passed; FALSE otherwise. */
626 static gboolean test_tape_status(FILE * outf) {
630 char *amcheck_device = NULL;
632 amwait_t wait_status;
635 if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
640 outfd = fileno(outf);
642 amcheck_device = vstralloc(amlibexecdir, "/", "amcheck-device", NULL);
643 args = get_config_options(overwrite? 3 : 2);
644 args[0] = amcheck_device; /* steal the reference */
645 args[1] = g_strdup(get_config_name());
647 args[2] = g_strdup("-w");
649 /* run libexecdir/amcheck-device.pl, capturing STDERR and STDOUT to outf */
650 devpid = pipespawnv(amcheck_device, 0, 0,
651 &nullfd, &outfd, &outfd,
654 /* and immediately wait for it to die */
655 waitpid(devpid, &wait_status, 0);
657 if (WIFSIGNALED(wait_status)) {
658 g_fprintf(outf, _("amcheck-device terminated with signal %d"),
659 WTERMSIG(wait_status));
661 } else if (WIFEXITED(wait_status)) {
662 success = (WEXITSTATUS(wait_status) == 0);
679 struct fs_usage fsusage;
681 pid_t pid G_GNUC_UNUSED;
682 int confbad = 0, tapebad = 0, disklow = 0, logbad = 0;
683 int userbad = 0, infobad = 0, indexbad = 0, pgmbad = 0;
684 int testtape = do_tapechk;
685 tapetype_t *tp = NULL;
688 intmax_t kb_avail, kb_needed;
690 gboolean printed_small_part_size_warning = FALSE;
691 char *small_part_size_warning =
692 _(" This may create > 1000 parts, severely degrading backup/restore performance.\n"
693 " See http://wiki.zmanda.com/index.php/Splitsize_too_small for more information.\n");
695 switch(pid = fork()) {
697 error(_("could not spawn a process for checking the server: %s"), strerror(errno));
698 g_assert_not_reached();
710 set_pname("amcheck-server");
714 /* server does not need root privileges, and the access() calls below use the real userid,
715 * so totally drop privileges at this point (making the userid equal to the dumpuser) */
718 if((outf = fdopen(fd, "w")) == NULL) {
719 error(_("fdopen %d: %s"), fd, strerror(errno));
724 g_fprintf(outf, _("Amanda Tape Server Host Check\n"));
725 g_fprintf(outf, "-----------------------------\n");
727 if (do_localchk || testtape) {
728 tp = lookup_tapetype(getconf_str(CNF_TAPETYPE));
732 * Check various server side config file settings.
739 ColumnSpec = getconf_str(CNF_COLUMNSPEC);
740 if(SetColumnDataFromString(ColumnData, ColumnSpec, &errstr) < 0) {
741 g_fprintf(outf, _("ERROR: %s\n"), errstr);
745 lbl_templ = tapetype_get_lbl_templ(tp);
746 if(strcmp(lbl_templ, "") != 0) {
747 lbl_templ = config_dir_relative(lbl_templ);
748 if(access(lbl_templ, R_OK) == -1) {
750 _("ERROR: cannot read label template (lbl-templ) file %s: %s. Check permissions\n"),
755 #if !defined(HAVE_LPR_CMD)
756 g_fprintf(outf, _("ERROR: lbl-templ set but no LPR command defined. You should reconfigure amanda\n and make sure it finds a lpr or lp command.\n"));
761 if (getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED) <
762 getconf_int(CNF_FLUSH_THRESHOLD_DUMPED)) {
763 g_fprintf(outf, _("WARNING: flush-threshold-dumped (%d) must be less than or equal to flush-threshold-scheduled (%d).\n"),
764 getconf_int(CNF_FLUSH_THRESHOLD_DUMPED),
765 getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED));
768 if (getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED) <
769 getconf_int(CNF_TAPERFLUSH)) {
770 g_fprintf(outf, _("WARNING: taperflush (%d) must be less than or equal to flush-threshold-scheduled (%d).\n"),
771 getconf_int(CNF_TAPERFLUSH),
772 getconf_int(CNF_FLUSH_THRESHOLD_SCHEDULED));
775 if (getconf_int(CNF_TAPERFLUSH) > 0 &&
776 !getconf_no_yes_all(CNF_AUTOFLUSH)) {
777 g_fprintf(outf, _("WARNING: autoflush must be set to 'yes' or 'all' if taperflush (%d) is greater that 0.\n"),
778 getconf_int(CNF_TAPERFLUSH));
781 /* Double-check that 'localhost' resolves properly */
782 if ((res = resolve_hostname("localhost", 0, NULL, NULL) != 0)) {
783 g_fprintf(outf, _("ERROR: Cannot resolve `localhost': %s\n"), gai_strerror(res));
787 if (!getconf_seen(CNF_TAPETYPE)) {
789 _("ERROR: no tapetype specified; you must give a value for "
790 "the 'tapetype' parameter\n"));
796 * Look up the programs used on the server side.
800 * entreprise version will do planner/dumper suid check
802 if(access(amlibexecdir, X_OK) == -1) {
803 quoted = quote_string(amlibexecdir);
804 g_fprintf(outf, _("ERROR: Directory %s containing Amanda tools is not accessible\n."),
806 g_fprintf(outf, _("Check permissions\n"));
810 if(test_server_pgm(outf, amlibexecdir, "planner", 1, uid_dumpuser))
812 if(test_server_pgm(outf, amlibexecdir, "dumper", 1, uid_dumpuser))
814 if(test_server_pgm(outf, amlibexecdir, "driver", 0, uid_dumpuser))
816 if(test_server_pgm(outf, amlibexecdir, "taper", 0, uid_dumpuser))
818 if(test_server_pgm(outf, amlibexecdir, "amtrmidx", 0, uid_dumpuser))
820 if(test_server_pgm(outf, amlibexecdir, "amlogroll", 0, uid_dumpuser))
823 if(access(sbindir, X_OK) == -1) {
824 quoted = quote_string(sbindir);
825 g_fprintf(outf, _("ERROR: Directory %s containing Amanda tools is not accessible\n"),
827 g_fprintf(outf, _("Check permissions\n"));
831 if(test_server_pgm(outf, sbindir, "amgetconf", 0, uid_dumpuser))
833 if(test_server_pgm(outf, sbindir, "amcheck", 1, uid_dumpuser))
835 if(test_server_pgm(outf, sbindir, "amdump", 0, uid_dumpuser))
837 if(test_server_pgm(outf, sbindir, "amreport", 0, uid_dumpuser))
840 if(access(COMPRESS_PATH, X_OK) == -1) {
841 quoted = quote_string(COMPRESS_PATH);
842 g_fprintf(outf, _("WARNING: %s is not executable, server-compression "
843 "and indexing will not work. \n"),quoted);
844 g_fprintf(outf, _("Check permissions\n"));
850 * Check that the directory for the tapelist file is writable, as well
851 * as the tapelist file itself (if it already exists). Also, check for
852 * a "hold" file (just because it is convenient to do it here) and warn
853 * if tapedev is set to the null device.
856 if(do_localchk || do_tapechk) {
864 guint64 part_size, part_cache_max_size, tape_size;
865 part_cache_type_t part_cache_type;
866 char *part_cache_dir;
868 tapefile = config_dir_relative(getconf_str(CNF_TAPELIST));
870 * XXX There Really Ought to be some error-checking here... dhw
872 tape_dir = stralloc(tapefile);
873 if ((lastslash = strrchr((const char *)tape_dir, '/')) != NULL) {
876 * else whine Really Loudly about a path with no slashes??!?
879 if(access(tape_dir, W_OK) == -1) {
880 quoted = quote_string(tape_dir);
881 g_fprintf(outf, _("ERROR: tapelist dir %s: not writable.\nCheck permissions\n"),
886 else if(stat(tapefile, &statbuf) == -1) {
887 if (errno != ENOENT) {
888 quoted = quote_string(tape_dir);
889 g_fprintf(outf, _("ERROR: tapelist %s (%s), "
890 "you must create an empty file.\n"),
891 quoted, strerror(errno));
895 g_fprintf(outf, _("NOTE: tapelist will be created on the next run.\n"));
898 tapebad |= check_tapefile(outf, tapefile);
899 if (tapebad == 0 && read_tapelist(tapefile)) {
900 quoted = quote_string(tapefile);
901 g_fprintf(outf, _("ERROR: tapelist %s: parse error\n"), quoted);
905 newtapefile = stralloc2(tapefile, ".new");
906 tapebad |= check_tapefile(outf, newtapefile);
908 newtapefile = stralloc2(tapefile, ".amlabel");
909 tapebad |= check_tapefile(outf, newtapefile);
911 newtapefile = stralloc2(tapefile, ".amlabel.new");
912 tapebad |= check_tapefile(outf, newtapefile);
914 newtapefile = stralloc2(tapefile, ".yesterday");
915 tapebad |= check_tapefile(outf, newtapefile);
917 newtapefile = stralloc2(tapefile, ".yesterday.new");
918 tapebad |= check_tapefile(outf, newtapefile);
921 holdfile = config_dir_relative("hold");
922 if(access(holdfile, F_OK) != -1) {
923 quoted = quote_string(holdfile);
924 g_fprintf(outf, _("WARNING: hold file %s exists."), holdfile);
925 g_fprintf(outf, _("Amdump will sleep as long as this file exists.\n"));
926 g_fprintf(outf, _("You might want to delete the existing hold file\n"));
932 tapename = getconf_str(CNF_TAPEDEV);
933 if (tapename == NULL) {
934 if (getconf_str(CNF_TPCHANGER) == NULL) {
935 g_fprintf(outf, _("WARNING:Parameter \"tapedev\" or \"tpchanger\" not specified in amanda.conf.\n"));
941 /* check tapetype-based splitting parameters */
942 part_size = tapetype_get_part_size(tp);
943 part_cache_type = tapetype_get_part_cache_type(tp);
944 part_cache_dir = tapetype_get_part_cache_dir(tp);
945 part_cache_max_size = tapetype_get_part_cache_max_size(tp);
947 if (!tapetype_seen(tp, TAPETYPE_PART_SIZE)) {
948 if (tapetype_seen(tp, TAPETYPE_PART_CACHE_TYPE)) {
949 g_fprintf(outf, "ERROR: part-cache-type specified, but no part-size\n");
952 if (tapetype_seen(tp, TAPETYPE_PART_CACHE_DIR)) {
953 g_fprintf(outf, "ERROR: part-cache-dir specified, but no part-size\n");
956 if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
957 g_fprintf(outf, "ERROR: part-cache-max-size specified, but no part-size\n");
961 switch (part_cache_type) {
962 case PART_CACHE_TYPE_DISK:
963 if (!tapetype_seen(tp, TAPETYPE_PART_CACHE_DIR)
964 || !part_cache_dir || !*part_cache_dir) {
966 "ERROR: part-cache-type is DISK, but no part-cache-dir specified\n");
969 if(get_fs_usage(part_cache_dir, NULL, &fsusage) == -1) {
970 g_fprintf(outf, "ERROR: part-cache-dir '%s': %s\n",
971 part_cache_dir, strerror(errno));
974 kb_avail = fsusage.fsu_bavail_top_bit_set?
975 0 : fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
976 kb_needed = part_size;
977 if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
978 kb_needed = part_cache_max_size;
980 if (kb_avail < kb_needed) {
982 "ERROR: part-cache-dir has %ju %sB available, but needs %ju %sB\n",
983 kb_avail/(uintmax_t)unitdivisor, displayunit,
984 kb_needed/(uintmax_t)unitdivisor, displayunit);
991 case PART_CACHE_TYPE_MEMORY:
992 kb_avail = physmem_total() / 1024;
993 kb_needed = part_size;
994 if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
995 kb_needed = part_cache_max_size;
997 if (kb_avail < kb_needed) {
999 "ERROR: system has %ju %sB memory, but part cache needs %ju %sB\n",
1000 kb_avail/(uintmax_t)unitdivisor, displayunit,
1001 kb_needed/(uintmax_t)unitdivisor, displayunit);
1007 case PART_CACHE_TYPE_NONE:
1008 if (tapetype_seen(tp, TAPETYPE_PART_CACHE_DIR)) {
1010 "ERROR: part-cache-dir specified, but part-cache-type is not DISK\n");
1017 if (tapetype_seen(tp, TAPETYPE_PART_SIZE) && part_size == 0
1018 && part_cache_type != PART_CACHE_TYPE_NONE) {
1020 "ERROR: part_size is zero, but part-cache-type is not 'none'\n");
1024 if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
1025 if (part_cache_type == PART_CACHE_TYPE_NONE) {
1027 "ERROR: part-cache-max-size is specified but no part cache is in use\n");
1031 if (part_cache_max_size > part_size) {
1033 "WARNING: part-cache-max-size is greater than part-size\n");
1037 tape_size = tapetype_get_length(tp);
1038 if (part_size && part_size * 1000 < tape_size) {
1040 _("WARNING: part-size of %ju %sB < 0.1%% of tape length.\n"),
1041 (uintmax_t)part_size/(uintmax_t)unitdivisor, displayunit);
1042 if (!printed_small_part_size_warning) {
1043 printed_small_part_size_warning = TRUE;
1044 g_fprintf(outf, "%s", small_part_size_warning);
1046 } else if (part_cache_max_size && part_cache_max_size * 1000 < tape_size) {
1048 _("WARNING: part-cache-max-size of %ju %sB < 0.1%% of tape length.\n"),
1049 (uintmax_t)part_cache_max_size/(uintmax_t)unitdivisor, displayunit);
1050 if (!printed_small_part_size_warning) {
1051 printed_small_part_size_warning = TRUE;
1052 g_fprintf(outf, "%s", small_part_size_warning);
1057 /* check available disk space */
1063 for (il = getconf_identlist(CNF_HOLDINGDISK);
1066 hdp = lookup_holdingdisk(il->data);
1067 quoted = quote_string(holdingdisk_get_diskdir(hdp));
1068 if(get_fs_usage(holdingdisk_get_diskdir(hdp), NULL, &fsusage) == -1) {
1069 g_fprintf(outf, _("ERROR: holding dir %s (%s), "
1070 "you must create a directory.\n"),
1071 quoted, strerror(errno));
1077 /* do the division first to avoid potential integer overflow */
1078 if (fsusage.fsu_bavail_top_bit_set)
1081 kb_avail = fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
1083 if(access(holdingdisk_get_diskdir(hdp), W_OK) == -1) {
1084 g_fprintf(outf, _("ERROR: holding disk %s: not writable: %s.\n"),
1085 quoted, strerror(errno));
1086 g_fprintf(outf, _("Check permissions\n"));
1089 else if(access(holdingdisk_get_diskdir(hdp), X_OK) == -1) {
1090 g_fprintf(outf, _("ERROR: holding disk %s: not searcheable: %s.\n"),
1091 quoted, strerror(errno));
1092 g_fprintf(outf, _("Check permissions of ancestors of %s\n"), quoted);
1095 else if(holdingdisk_get_disksize(hdp) > (off_t)0) {
1098 _("WARNING: holding disk %s: "
1099 "no space available (%lld %sB requested)\n"), quoted,
1100 (long long)(holdingdisk_get_disksize(hdp)/(off_t)unitdivisor),
1104 else if(kb_avail < holdingdisk_get_disksize(hdp)) {
1106 _("WARNING: holding disk %s: "
1107 "only %lld %sB available (%lld %sB requested)\n"), quoted,
1108 (long long)(kb_avail / (off_t)unitdivisor),
1110 (long long)(holdingdisk_get_disksize(hdp)/(off_t)unitdivisor),
1116 _("Holding disk %s: %lld %sB disk space available,"
1117 " using %lld %sB as requested\n"),
1119 (long long)(kb_avail / (off_t)unitdivisor),
1121 (long long)(holdingdisk_get_disksize(hdp)/(off_t)unitdivisor),
1126 if(kb_avail < -holdingdisk_get_disksize(hdp)) {
1128 _("WARNING: holding disk %s: "
1129 "only %lld %sB free, using nothing\n"),
1130 quoted, (long long)(kb_avail / (off_t)unitdivisor),
1132 g_fprintf(outf, _("WARNING: Not enough free space specified in amanda.conf\n"));
1137 _("Holding disk %s: %lld %sB disk space available, using %lld %sB\n"),
1139 (long long)(kb_avail/(off_t)unitdivisor),
1141 (long long)((kb_avail + holdingdisk_get_disksize(hdp)) / (off_t)unitdivisor),
1149 /* check that the log file is writable if it already exists */
1155 struct stat stat_old;
1156 struct stat statbuf;
1158 conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
1159 logfile = vstralloc(conf_logdir, "/log", NULL);
1161 quoted = quote_string(conf_logdir);
1162 if(stat(conf_logdir, &statbuf) == -1) {
1163 g_fprintf(outf, _("ERROR: logdir %s (%s), you must create directory.\n"),
1164 quoted, strerror(errno));
1167 else if(access(conf_logdir, W_OK) == -1) {
1168 g_fprintf(outf, _("ERROR: log dir %s: not writable\n"), quoted);
1173 if(logbad == 0 && access(logfile, F_OK) == 0) {
1176 if(access(logfile, W_OK) != 0) {
1177 quoted = quote_string(logfile);
1178 g_fprintf(outf, _("ERROR: log file %s: not writable\n"), quoted);
1183 olddir = vstralloc(conf_logdir, "/oldlog", NULL);
1184 quoted = quote_string(olddir);
1185 if (logbad == 0 && stat(olddir,&stat_old) == 0) { /* oldlog exist */
1186 if(!(S_ISDIR(stat_old.st_mode))) {
1187 g_fprintf(outf, _("ERROR: oldlog directory %s is not a directory\n"),
1189 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1192 if(logbad == 0 && access(olddir, W_OK) == -1) {
1193 g_fprintf(outf, _("ERROR: oldlog dir %s: not writable\n"), quoted);
1194 g_fprintf(outf, _("Check permissions\n"));
1198 else if(logbad == 0 && lstat(olddir,&stat_old) == 0) {
1199 g_fprintf(outf, _("ERROR: oldlog directory %s is not a directory\n"),
1201 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1206 if (logbad == 0 && testtape) {
1207 logfile = newvstralloc(logfile, conf_logdir, "/amdump", NULL);
1208 if (access(logfile, F_OK) == 0) {
1216 amfree(conf_logdir);
1220 tapebad = !test_tape_status(outf);
1221 } else if (do_tapechk) {
1222 g_fprintf(outf, _("WARNING: skipping tape test because amdump or amflush seem to be running\n"));
1223 g_fprintf(outf, _("WARNING: if they are not, you must run amcleanup\n"));
1224 } else if (logbad == 2) {
1225 g_fprintf(outf, _("NOTE: amdump or amflush seem to be running\n"));
1226 g_fprintf(outf, _("NOTE: if they are not, you must run amcleanup\n"));
1228 /* we skipped the tape checks, but this is just a NOTE and
1229 * should not result in a nonzero exit status, so reset logbad to 0 */
1232 g_fprintf(outf, _("NOTE: skipping tape checks\n"));
1236 * See if the information file and index directory for each client
1237 * and disk is OK. Since we may be seeing clients and/or disks for
1238 * the first time, these are just warnings, not errors.
1241 char *conf_infofile;
1242 char *conf_indexdir;
1243 char *hostinfodir = NULL;
1244 char *hostindexdir = NULL;
1245 char *diskdir = NULL;
1246 char *infofile = NULL;
1247 struct stat statbuf;
1250 int indexdir_checked = 0;
1251 int hostindexdir_checked = 0;
1254 int conf_tapecycle, conf_runspercycle;
1255 identlist_t pp_scriptlist;
1257 conf_tapecycle = getconf_int(CNF_TAPECYCLE);
1258 conf_runspercycle = getconf_int(CNF_RUNSPERCYCLE);
1260 if(conf_tapecycle <= conf_runspercycle) {
1261 g_fprintf(outf, _("WARNING: tapecycle (%d) <= runspercycle (%d).\n"),
1262 conf_tapecycle, conf_runspercycle);
1265 conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE));
1266 conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR));
1268 quoted = quote_string(conf_infofile);
1269 if(stat(conf_infofile, &statbuf) == -1) {
1270 if (errno == ENOENT) {
1271 g_fprintf(outf, _("NOTE: conf info dir %s does not exist\n"),
1273 g_fprintf(outf, _("NOTE: it will be created on the next run.\n"));
1275 g_fprintf(outf, _("ERROR: conf info dir %s (%s)\n"),
1276 quoted, strerror(errno));
1279 amfree(conf_infofile);
1280 } else if (!S_ISDIR(statbuf.st_mode)) {
1281 g_fprintf(outf, _("ERROR: info dir %s: not a directory\n"), quoted);
1282 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1283 amfree(conf_infofile);
1285 } else if (access(conf_infofile, W_OK) == -1) {
1286 g_fprintf(outf, _("ERROR: info dir %s: not writable\n"), quoted);
1287 g_fprintf(outf, _("Check permissions\n"));
1288 amfree(conf_infofile);
1291 char *errmsg = NULL;
1292 if (check_infofile(conf_infofile, &origq, &errmsg) == -1) {
1293 g_fprintf(outf, "ERROR: Can't copy infofile: %s\n", errmsg);
1297 strappend(conf_infofile, "/");
1301 while(!empty(origq)) {
1302 hostp = origq.head->host;
1303 host = sanitise_filename(hostp->hostname);
1305 hostinfodir = newstralloc2(hostinfodir, conf_infofile, host);
1306 quoted = quote_string(hostinfodir);
1307 if(stat(hostinfodir, &statbuf) == -1) {
1308 if (errno == ENOENT) {
1309 g_fprintf(outf, _("NOTE: host info dir %s does not exist\n"),
1312 _("NOTE: it will be created on the next run.\n"));
1314 g_fprintf(outf, _("ERROR: host info dir %s (%s)\n"),
1315 quoted, strerror(errno));
1318 amfree(hostinfodir);
1319 } else if (!S_ISDIR(statbuf.st_mode)) {
1320 g_fprintf(outf, _("ERROR: info dir %s: not a directory\n"),
1322 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1323 amfree(hostinfodir);
1325 } else if (access(hostinfodir, W_OK) == -1) {
1326 g_fprintf(outf, _("ERROR: info dir %s: not writable\n"), quoted);
1327 g_fprintf(outf, _("Check permissions\n"));
1328 amfree(hostinfodir);
1331 strappend(hostinfodir, "/");
1335 for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
1336 disk = sanitise_filename(dp->name);
1340 diskdir = newstralloc2(diskdir, hostinfodir, disk);
1341 infofile = vstralloc(diskdir, "/", "info", NULL);
1342 quoted = quote_string(diskdir);
1343 quotedif = quote_string(infofile);
1344 if(stat(diskdir, &statbuf) == -1) {
1345 if (errno == ENOENT) {
1346 g_fprintf(outf, _("NOTE: info dir %s does not exist\n"),
1349 _("NOTE: it will be created on the next run.\n"));
1351 g_fprintf(outf, _("ERROR: info dir %s (%s)\n"),
1352 quoted, strerror(errno));
1355 } else if (!S_ISDIR(statbuf.st_mode)) {
1356 g_fprintf(outf, _("ERROR: info dir %s: not a directory\n"),
1358 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1360 } else if (access(diskdir, W_OK) == -1) {
1361 g_fprintf(outf, _("ERROR: info dir %s: not writable\n"),
1363 g_fprintf(outf,_("Check permissions\n"));
1365 } else if(stat(infofile, &statbuf) == -1) {
1366 if (errno == ENOENT) {
1367 g_fprintf(outf, _("NOTE: info file %s does not exist\n"),
1369 g_fprintf(outf, _("NOTE: it will be created on the next run.\n"));
1371 g_fprintf(outf, _("ERROR: info dir %s (%s)\n"),
1372 quoted, strerror(errno));
1375 } else if (!S_ISREG(statbuf.st_mode)) {
1376 g_fprintf(outf, _("ERROR: info file %s: not a file\n"),
1378 g_fprintf(outf, _("Remove the entry and create a new file\n"));
1380 } else if (access(infofile, R_OK) == -1) {
1381 g_fprintf(outf, _("ERROR: info file %s: not readable\n"),
1390 if(! indexdir_checked) {
1391 quoted = quote_string(conf_indexdir);
1392 if(stat(conf_indexdir, &statbuf) == -1) {
1393 if (errno == ENOENT) {
1394 g_fprintf(outf, _("NOTE: index dir %s does not exist\n"),
1396 g_fprintf(outf, _("NOTE: it will be created on the next run.\n"));
1398 g_fprintf(outf, _("ERROR: index dir %s (%s)\n"),
1399 quoted, strerror(errno));
1402 amfree(conf_indexdir);
1403 } else if (!S_ISDIR(statbuf.st_mode)) {
1404 g_fprintf(outf, _("ERROR: index dir %s: not a directory\n"),
1406 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1407 amfree(conf_indexdir);
1409 } else if (access(conf_indexdir, W_OK) == -1) {
1410 g_fprintf(outf, _("ERROR: index dir %s: not writable\n"),
1412 amfree(conf_indexdir);
1415 strappend(conf_indexdir, "/");
1417 indexdir_checked = 1;
1421 if(! hostindexdir_checked) {
1422 hostindexdir = stralloc2(conf_indexdir, host);
1423 quoted = quote_string(hostindexdir);
1424 if(stat(hostindexdir, &statbuf) == -1) {
1425 if (errno == ENOENT) {
1426 g_fprintf(outf, _("NOTE: index dir %s does not exist\n"),
1428 g_fprintf(outf, _("NOTE: it will be created on the next run.\n"));
1430 g_fprintf(outf, _("ERROR: index dir %s (%s)\n"),
1431 quoted, strerror(errno));
1434 amfree(hostindexdir);
1435 } else if (!S_ISDIR(statbuf.st_mode)) {
1436 g_fprintf(outf, _("ERROR: index dir %s: not a directory\n"),
1438 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1439 amfree(hostindexdir);
1441 } else if (access(hostindexdir, W_OK) == -1) {
1442 g_fprintf(outf, _("ERROR: index dir %s: not writable\n"),
1444 amfree(hostindexdir);
1447 strappend(hostindexdir, "/");
1449 hostindexdir_checked = 1;
1453 diskdir = newstralloc2(diskdir, hostindexdir, disk);
1454 quoted = quote_string(diskdir);
1455 if(stat(diskdir, &statbuf) == -1) {
1456 if (errno == ENOENT) {
1457 g_fprintf(outf, _("NOTE: index dir %s does not exist\n"),
1459 g_fprintf(outf, _("NOTE: it will be created on the next run.\n"));
1461 g_fprintf(outf, _("ERROR: index dir %s (%s)\n"),
1462 quoted, strerror(errno));
1465 } else if (!S_ISDIR(statbuf.st_mode)) {
1466 g_fprintf(outf, _("ERROR: index dir %s: not a directory\n"),
1468 g_fprintf(outf, _("Remove the entry and create a new directory\n"));
1470 } else if (access(diskdir, W_OK) == -1) {
1471 g_fprintf(outf, _("ERROR: index dir %s: is not writable\n"),
1480 if ( dp->encrypt == ENCRYPT_SERV_CUST ) {
1481 if ( dp->srv_encrypt[0] == '\0' ) {
1482 g_fprintf(outf, _("ERROR: server encryption program not specified\n"));
1483 g_fprintf(outf, _("Specify \"server-custom-encrypt\" in the dumptype\n"));
1486 else if(access(dp->srv_encrypt, X_OK) == -1) {
1487 g_fprintf(outf, _("ERROR: %s is not executable, server encryption will not work\n"),
1489 g_fprintf(outf, _("Check file type\n"));
1493 if ( dp->compress == COMP_SERVER_CUST ) {
1494 if ( dp->srvcompprog[0] == '\0' ) {
1495 g_fprintf(outf, _("ERROR: server custom compression program "
1496 "not specified\n"));
1497 g_fprintf(outf, _("Specify \"server-custom-compress\" in "
1501 else if(access(dp->srvcompprog, X_OK) == -1) {
1502 quoted = quote_string(dp->srvcompprog);
1504 g_fprintf(outf, _("ERROR: %s is not executable, server custom "
1505 "compression will not work\n"),
1508 g_fprintf(outf, _("Check file type\n"));
1513 /* check deprecated splitting parameters */
1514 if (dumptype_seen(dp->config, DUMPTYPE_TAPE_SPLITSIZE)
1515 || dumptype_seen(dp->config, DUMPTYPE_SPLIT_DISKBUFFER)
1516 || dumptype_seen(dp->config, DUMPTYPE_FALLBACK_SPLITSIZE)) {
1517 tape_size = tapetype_get_length(tp);
1518 if (dp->tape_splitsize > tape_size) {
1520 _("ERROR: %s %s: tape-splitsize > tape size\n"),
1521 hostp->hostname, dp->name);
1524 if (dp->tape_splitsize && dp->fallback_splitsize * 1024 > physmem_total()) {
1526 _("ERROR: %s %s: fallback-splitsize > total available memory\n"),
1527 hostp->hostname, dp->name);
1530 if (dp->tape_splitsize && dp->fallback_splitsize > tape_size) {
1532 _("ERROR: %s %s: fallback-splitsize > tape size\n"),
1533 hostp->hostname, dp->name);
1537 /* also check for part sizes that are too small */
1538 if (dp->tape_splitsize && dp->tape_splitsize * 1000 < tape_size) {
1540 _("WARNING: %s %s: tape-splitsize of %ju %sB < 0.1%% of tape length.\n"),
1541 hostp->hostname, dp->name,
1542 (uintmax_t)dp->tape_splitsize/(uintmax_t)unitdivisor,
1544 if (!printed_small_part_size_warning) {
1545 printed_small_part_size_warning = TRUE;
1546 g_fprintf(outf, "%s", small_part_size_warning);
1550 /* fallback splitsize will be used if split_diskbuffer is empty or NULL */
1551 if (dp->tape_splitsize != 0 && dp->fallback_splitsize != 0 &&
1552 (dp->split_diskbuffer == NULL ||
1553 dp->split_diskbuffer[0] == '\0') &&
1554 dp->fallback_splitsize * 1000 < tape_size) {
1556 _("WARNING: %s %s: fallback-splitsize of %ju %sB < 0.1%% of tape length.\n"),
1557 hostp->hostname, dp->name,
1558 (uintmax_t)dp->fallback_splitsize/(uintmax_t)unitdivisor,
1560 if (!printed_small_part_size_warning) {
1561 printed_small_part_size_warning = TRUE;
1562 g_fprintf(outf, "%s", small_part_size_warning);
1567 if (dp->data_path == DATA_PATH_DIRECTTCP) {
1568 if (dp->compress != COMP_NONE) {
1570 _("ERROR: %s %s: Can't compress directtcp data-path\n"),
1571 hostp->hostname, dp->name);
1574 if (dp->encrypt != ENCRYPT_NONE) {
1576 _("ERROR: %s %s: Can't encrypt directtcp data-path\n"),
1577 hostp->hostname, dp->name);
1580 if (dp->to_holdingdisk == HOLD_REQUIRED) {
1582 _("ERROR: %s %s: Holding disk can't be use for directtcp data-path\n"),
1583 hostp->hostname, dp->name);
1588 for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
1589 pp_scriptlist = pp_scriptlist->next) {
1590 pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
1591 g_assert(pp_script != NULL);
1592 if (pp_script_get_execute_where(pp_script) == ES_CLIENT &&
1593 pp_script_get_execute_on(pp_script) & EXECUTE_ON_PRE_HOST_BACKUP) {
1595 _("ERROR: %s %s: Can't run pre-host-backup script on client\n"),
1596 hostp->hostname, dp->name);
1597 } else if (pp_script_get_execute_where(pp_script) == ES_CLIENT &&
1598 pp_script_get_execute_on(pp_script) & EXECUTE_ON_POST_HOST_BACKUP) {
1600 _("ERROR: %s %s: Can't run post-host-backup script on client\n"),
1601 hostp->hostname, dp->name);
1606 remove_disk(&origq, dp);
1609 amfree(hostindexdir);
1610 hostindexdir_checked = 0;
1613 amfree(hostinfodir);
1614 amfree(conf_infofile);
1615 amfree(conf_indexdir);
1620 g_fprintf(outf, _("Server check took %s seconds\n"), walltime_str(curclock()));
1623 g_debug("userbad: %d", userbad);
1624 g_debug("confbad: %d", confbad);
1625 g_debug("tapebad: %d", tapebad);
1626 g_debug("disklow: %d", disklow);
1627 g_debug("logbad: %d", logbad);
1628 g_debug("infobad: %d", infobad);
1629 g_debug("indexbad: %d", indexbad);
1630 g_debug("pgmbad: %d", pgmbad);
1644 /* --------------------------------------------------- */
1649 static void handle_result(void *, pkt_t *, security_handle_t *);
1650 void start_host(am_host_t *hostp);
1652 #define HOST_READY ((void *)0) /* must be 0 */
1653 #define HOST_ACTIVE ((void *)1)
1654 #define HOST_DONE ((void *)2)
1656 #define DISK_READY ((void *)0) /* must be 0 */
1657 #define DISK_ACTIVE ((void *)1)
1658 #define DISK_DONE ((void *)2)
1668 const security_driver_t *secdrv;
1669 char number[NUM_STR_SIZE];
1670 estimate_t estimate;
1672 if(hostp->up != HOST_READY) {
1677 * The first time through here we send a "noop" request. This will
1678 * return the feature list from the client if it supports that.
1679 * If it does not, handle_result() will set the feature list to an
1680 * empty structure. In either case, we do the disks on the second
1681 * (and subsequent) pass(es).
1684 if(hostp->features != NULL) { /* selfcheck service */
1685 int has_features = am_has_feature(hostp->features,
1686 fe_req_options_features);
1687 int has_hostname = am_has_feature(hostp->features,
1688 fe_req_options_hostname);
1689 int has_maxdumps = am_has_feature(hostp->features,
1690 fe_req_options_maxdumps);
1691 int has_config = am_has_feature(hostp->features,
1692 fe_req_options_config);
1694 if(!am_has_feature(hostp->features, fe_selfcheck_req) &&
1695 !am_has_feature(hostp->features, fe_selfcheck_req_device)) {
1697 _("ERROR: Client %s does not support selfcheck REQ packet.\n"),
1699 g_fprintf(outf, _("Client might be of a very old version\n"));
1701 if(!am_has_feature(hostp->features, fe_selfcheck_rep)) {
1703 _("ERROR: Client %s does not support selfcheck REP packet.\n"),
1705 g_fprintf(outf, _("Client might be of a very old version\n"));
1707 if(!am_has_feature(hostp->features, fe_sendsize_req_options) &&
1708 !am_has_feature(hostp->features, fe_sendsize_req_no_options) &&
1709 !am_has_feature(hostp->features, fe_sendsize_req_device)) {
1711 _("ERROR: Client %s does not support sendsize REQ packet.\n"),
1713 g_fprintf(outf, _("Client might be of a very old version\n"));
1715 if(!am_has_feature(hostp->features, fe_sendsize_rep)) {
1717 _("ERROR: Client %s does not support sendsize REP packet.\n"),
1719 g_fprintf(outf, _("Client might be of a very old version\n"));
1721 if(!am_has_feature(hostp->features, fe_sendbackup_req) &&
1722 !am_has_feature(hostp->features, fe_sendbackup_req_device)) {
1724 _("ERROR: Client %s does not support sendbackup REQ packet.\n"),
1726 g_fprintf(outf, _("Client might be of a very old version\n"));
1728 if(!am_has_feature(hostp->features, fe_sendbackup_rep)) {
1730 _("ERROR: Client %s does not support sendbackup REP packet.\n"),
1732 g_fprintf(outf, _("Client might be of a very old version\n"));
1735 g_snprintf(number, SIZEOF(number), "%d", hostp->maxdumps);
1736 req = vstralloc("SERVICE ", "selfcheck", "\n",
1738 has_features ? "features=" : "",
1739 has_features ? our_feature_string : "",
1740 has_features ? ";" : "",
1741 has_maxdumps ? "maxdumps=" : "",
1742 has_maxdumps ? number : "",
1743 has_maxdumps ? ";" : "",
1744 has_hostname ? "hostname=" : "",
1745 has_hostname ? hostp->hostname : "",
1746 has_hostname ? ";" : "",
1747 has_config ? "config=" : "",
1748 has_config ? get_config_name() : "",
1749 has_config ? ";" : "",
1753 req_len = strlen(req);
1754 req_len += 128; /* room for SECURITY ... */
1755 req_len += 256; /* room for non-disk answers */
1756 for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
1762 char *qname, *b64disk;
1763 char *qdevice, *b64device = NULL;
1764 GPtrArray *errarray;
1767 if(dp->up != DISK_READY || dp->todo != 1) {
1770 qname = quote_string(dp->name);
1772 errarray = validate_optionstr(dp);
1773 if (errarray->len > 0) {
1774 for (i=0; i < errarray->len; i++) {
1775 g_fprintf(outf, _("ERROR: %s:%s %s\n"),
1776 hostp->hostname, qname,
1777 (char *)g_ptr_array_index(errarray, i));
1779 g_ptr_array_free(errarray, TRUE);
1783 } else if (am_has_feature(hostp->features, fe_req_xml)) {
1784 o = xml_optionstr(dp, 0);
1789 b64disk = amxml_format_tag("disk", dp->name);
1790 qdevice = quote_string(dp->device);
1792 b64device = amxml_format_tag("diskdevice", dp->device);
1793 if ((dp->name && qname[0] == '"') ||
1794 (dp->device && qdevice[0] == '"')) {
1795 if(!am_has_feature(hostp->features, fe_interface_quoted_text)) {
1797 _("WARNING: %s:%s:%s host does not support quoted text\n"),
1798 hostp->hostname, qname, qdevice);
1799 g_fprintf(outf, _("You must upgrade amanda on the client to "
1800 "specify a quoted text/device in the disklist, "
1801 "or don't use quoted text for the device.\n"));
1806 if(!am_has_feature(hostp->features, fe_selfcheck_req_device)) {
1808 _("ERROR: %s:%s (%s): selfcheck does not support device.\n"),
1809 hostp->hostname, qname, dp->device);
1810 g_fprintf(outf, _("You must upgrade amanda on the client to "
1811 "specify a diskdevice in the disklist "
1812 "or don't specify a diskdevice in the disklist.\n"));
1814 if(!am_has_feature(hostp->features, fe_sendsize_req_device)) {
1816 _("ERROR: %s:%s (%s): sendsize does not support device.\n"),
1817 hostp->hostname, qname, dp->device);
1818 g_fprintf(outf, _("You must upgrade amanda on the client to "
1819 "specify a diskdevice in the disklist"
1820 " or don't specify a diskdevice in the disklist.\n"));
1822 if(!am_has_feature(hostp->features, fe_sendbackup_req_device)) {
1824 _("ERROR: %s:%s (%s): sendbackup does not support device.\n"),
1825 hostp->hostname, qname, dp->device);
1826 g_fprintf(outf, _("You must upgrade amanda on the client to "
1827 "specify a diskdevice in the disklist"
1828 " or don't specify a diskdevice in the disklist.\n"));
1831 if (dp->data_path != DATA_PATH_AMANDA &&
1832 !am_has_feature(hostp->features, fe_xml_data_path)) {
1834 _("ERROR: Client %s does not support %s data-path\n"),
1835 hostp->hostname, data_path_to_string(dp->data_path));
1836 } else if (dp->data_path == DATA_PATH_DIRECTTCP &&
1837 !am_has_feature(hostp->features, fe_xml_directtcp_list)) {
1839 _("ERROR: Client %s does not support directtcp data-path\n"),
1844 (strcmp(dp->program,"DUMP") == 0 ||
1845 strcmp(dp->program,"GNUTAR") == 0)) {
1846 if(strcmp(dp->program, "DUMP") == 0 &&
1847 !am_has_feature(hostp->features, fe_program_dump)) {
1848 g_fprintf(outf, _("ERROR: %s:%s does not support DUMP.\n"),
1849 hostp->hostname, qname);
1850 g_fprintf(outf, _("You must upgrade amanda on the client to use DUMP "
1851 "or you can use another program.\n"));
1853 if(strcmp(dp->program, "GNUTAR") == 0 &&
1854 !am_has_feature(hostp->features, fe_program_gnutar)) {
1855 g_fprintf(outf, _("ERROR: %s:%s does not support GNUTAR.\n"),
1856 hostp->hostname, qname);
1857 g_fprintf(outf, _("You must upgrade amanda on the client to use GNUTAR "
1858 "or you can use another program.\n"));
1860 estimate = (estimate_t)GPOINTER_TO_INT(dp->estimatelist->data);
1861 if(estimate == ES_CALCSIZE &&
1862 !am_has_feature(hostp->features, fe_calcsize_estimate)) {
1863 g_fprintf(outf, _("ERROR: %s:%s does not support CALCSIZE for "
1864 "estimate, using CLIENT.\n"),
1865 hostp->hostname, qname);
1866 g_fprintf(outf, _("You must upgrade amanda on the client to use "
1867 "CALCSIZE for estimate or don't use CALCSIZE for estimate.\n"));
1868 estimate = ES_CLIENT;
1870 if(estimate == ES_CALCSIZE &&
1871 am_has_feature(hostp->features, fe_selfcheck_calcsize))
1872 calcsize = "CALCSIZE ";
1876 if(dp->compress == COMP_CUST &&
1877 !am_has_feature(hostp->features, fe_options_compress_cust)) {
1879 _("ERROR: Client %s does not support custom compression.\n"),
1881 g_fprintf(outf, _("You must upgrade amanda on the client to "
1882 "use custom compression\n"));
1883 g_fprintf(outf, _("Otherwise you can use the default client "
1884 "compression program.\n"));
1886 if(dp->encrypt == ENCRYPT_CUST ) {
1887 if ( !am_has_feature(hostp->features, fe_options_encrypt_cust)) {
1889 _("ERROR: Client %s does not support data encryption.\n"),
1891 g_fprintf(outf, _("You must upgrade amanda on the client to use encryption program.\n"));
1893 } else if ( dp->compress == COMP_SERVER_FAST ||
1894 dp->compress == COMP_SERVER_BEST ||
1895 dp->compress == COMP_SERVER_CUST ) {
1897 _("ERROR: %s: Client encryption with server compression "
1898 "is not supported. See amanda.conf(5) for detail.\n"),
1903 if (am_has_feature(hostp->features, fe_req_xml)) {
1904 l = vstralloc("<dle>\n"
1907 "</program>\n", NULL);
1908 es = xml_estimate(dp->estimatelist, hostp->features);
1909 vstrextend(&l, es, "\n", NULL);
1911 vstrextend(&l, " ", b64disk, "\n", NULL);
1913 vstrextend(&l, " ", b64device, "\n", NULL);
1914 vstrextend(&l, o, "</dle>\n", NULL);
1917 l = vstralloc(calcsize,
1926 l = vstralloc(calcsize,
1936 if (!am_has_feature(hostp->features, fe_program_application_api) ||
1937 !am_has_feature(hostp->features, fe_req_xml)) {
1938 g_fprintf(outf, _("ERROR: %s:%s does not support APPLICATION-API.\n"),
1939 hostp->hostname, qname);
1940 g_fprintf(outf, _("Dumptype configuration is not GNUTAR or DUMP."
1941 " It is case sensitive\n"));
1945 l = vstralloc("<dle>\n"
1946 " <program>APPLICATION</program>\n", NULL);
1947 if (dp->application) {
1948 application_t *application;
1951 application = lookup_application(dp->application);
1954 _("ERROR: application '%s' not found.\n"), dp->application);
1956 char *client_name = application_get_client_name(application);
1957 if (client_name && strlen(client_name) > 0 &&
1958 !am_has_feature(hostp->features, fe_application_client_name)) {
1960 _("WARNING: %s:%s does not support client-name in application.\n"),
1961 hostp->hostname, qname);
1963 xml_app = xml_application(dp, application, hostp->features);
1964 vstrextend(&l, xml_app, NULL);
1968 if (dp->pp_scriptlist) {
1969 if (!am_has_feature(hostp->features, fe_pp_script)) {
1971 _("ERROR: %s:%s does not support SCRIPT-API.\n"),
1972 hostp->hostname, qname);
1974 identlist_t pp_scriptlist;
1975 for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
1976 pp_scriptlist = pp_scriptlist->next) {
1977 pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
1978 char *client_name = pp_script_get_client_name(pp_script);;
1979 if (client_name && strlen(client_name) > 0 &&
1980 !am_has_feature(hostp->features, fe_script_client_name)) {
1982 _("WARNING: %s:%s does not support client-name in script.\n"),
1983 hostp->hostname, dp->name);
1988 es = xml_estimate(dp->estimatelist, hostp->features);
1989 vstrextend(&l, es, "\n", NULL);
1991 vstrextend(&l, " ", b64disk, "\n", NULL);
1993 vstrextend(&l, " ", b64device, "\n", NULL);
1994 vstrextend(&l, o, "</dle>\n", NULL);
2007 dp->up = DISK_ACTIVE;
2011 else { /* noop service */
2012 req = vstralloc("SERVICE ", "noop", "\n",
2014 "features=", our_feature_string, ";",
2017 for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
2018 if(dp->up != DISK_READY || dp->todo != 1) {
2025 if(disk_count == 0) {
2027 hostp->up = HOST_DONE;
2031 secdrv = security_getdriver(hostp->disks->auth);
2032 if (secdrv == NULL) {
2033 fprintf(stderr, _("Could not find security driver \"%s\" for host \"%s\". auth for this dle is invalid\n"),
2034 hostp->disks->auth, hostp->hostname);
2036 protocol_sendreq(hostp->hostname, secdrv, amhost_get_security_conf,
2037 req, conf_ctimeout, handle_result, hostp);
2042 hostp->up = HOST_ACTIVE;
2046 start_client_checks(
2055 switch(pid = fork()) {
2057 error(_("INTERNAL ERROR:could not fork client check: %s"), strerror(errno));
2070 set_pname("amcheck-clients");
2074 if((outf = fdopen(fd, "w")) == NULL) {
2075 error(_("fdopen %d: %s"), fd, strerror(errno));
2080 g_fprintf(outf, _("\nAmanda Backup Client Hosts Check\n"));
2081 g_fprintf(outf, "--------------------------------\n");
2083 run_server_global_scripts(EXECUTE_ON_PRE_AMCHECK, get_config_name());
2086 hostcount = remote_errors = 0;
2088 for(dp = origq.head; dp != NULL; dp = dp->next) {
2090 if(hostp->up == HOST_READY && dp->todo == 1) {
2091 run_server_host_scripts(EXECUTE_ON_PRE_HOST_AMCHECK,
2092 get_config_name(), hostp);
2093 for(dp1 = hostp->disks; dp1 != NULL; dp1 = dp1->hostnext) {
2094 run_server_dle_scripts(EXECUTE_ON_PRE_DLE_AMCHECK,
2095 get_config_name(), dp1, -1);
2104 run_server_global_scripts(EXECUTE_ON_POST_AMCHECK, get_config_name());
2106 g_fprintf(outf, plural(_("Client check: %d host checked in %s seconds."),
2107 _("Client check: %d hosts checked in %s seconds."),
2109 hostcount, walltime_str(curclock()));
2110 g_fprintf(outf, plural(_(" %d problem found.\n"),
2111 _(" %d problems found.\n"), remote_errors),
2115 exit(userbad || remote_errors > 0);
2124 security_handle_t * sech)
2133 gboolean printed_hostname = FALSE;
2135 hostp = (am_host_t *)datap;
2136 hostp->up = HOST_READY;
2140 _("WARNING: %s: selfcheck request failed: %s\n"), hostp->hostname,
2141 security_geterror(sech));
2143 hostp->up = HOST_DONE;
2148 g_fprintf(errf, _("got response from %s:\n----\n%s----\n\n"),
2149 hostp->hostname, pkt->body);
2156 skip_quoted_line(s, ch);
2157 if (s[-2] == '\n') {
2161 if(strncmp_const(line, "OPTIONS ") == 0) {
2163 t = strstr(line, "features=");
2164 if(t != NULL && (g_ascii_isspace((int)t[-1]) || t[-1] == ';')) {
2165 char *u = strchr(t, ';');
2168 t += SIZEOF("features=")-1;
2169 am_release_feature_set(hostp->features);
2170 if((hostp->features = am_string_to_feature(t)) == NULL) {
2171 g_fprintf(outf, _("ERROR: %s: bad features value: '%s'\n"),
2172 hostp->hostname, t);
2173 g_fprintf(outf, _("The amfeature in the reply packet is invalid\n"));
2175 hostp->up = HOST_DONE;
2184 if (client_verbose && !printed_hostname) {
2185 g_fprintf(outf, "HOST %s\n", hostp->hostname);
2186 printed_hostname = TRUE;
2189 if(strncmp_const(line, "OK ") == 0) {
2190 if (client_verbose) {
2191 g_fprintf(outf, "%s\n", line);
2197 if(strncmp_const_skip(line, "ERROR ", t, tch) == 0) {
2198 skip_whitespace(t, tch);
2200 * If the "error" is that the "noop" service is unknown, it
2201 * just means the client is "old" (does not support the service).
2202 * We can ignore this.
2204 if(!((hostp->features == NULL) && (pkt->type == P_NAK)
2205 && ((strcmp(t - 1, "unknown service: noop") == 0)
2206 || (strcmp(t - 1, "noop: invalid service") == 0)))) {
2207 g_fprintf(outf, _("ERROR: %s%s: %s\n"),
2208 (pkt->type == P_NAK) ? "NAK " : "",
2212 hostp->up = HOST_DONE;
2217 g_fprintf(outf, _("ERROR: %s: unknown response: %s\n"),
2218 hostp->hostname, line);
2220 hostp->up = HOST_DONE;
2222 if(hostp->up == HOST_READY && hostp->features == NULL) {
2224 * The client does not support the features list, so give it an
2227 dbprintf(_("no feature set from host %s\n"), hostp->hostname);
2228 hostp->features = am_set_default_feature_set();
2230 for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
2231 if(dp->up == DISK_ACTIVE) {
2236 if(hostp->up == HOST_DONE) {
2237 security_close_connection(sech, hostp->hostname);
2238 for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
2239 run_server_dle_scripts(EXECUTE_ON_POST_DLE_AMCHECK,
2240 get_config_name(), dp, -1);
2242 run_server_host_scripts(EXECUTE_ON_POST_HOST_AMCHECK,
2243 get_config_name(), hostp);
2245 /* try to clean up any defunct processes, since Amanda doesn't wait() for
2247 while(waitpid(-1, NULL, WNOHANG)> 0);