/*
* Amanda, The Advanced Maryland Automatic Network Disk Archiver
* Copyright (c) 1991-2000 University of Maryland at College Park
* Copyright (c) 2007-2012 Zmanda, Inc. All Rights Reserved.
* Copyright (c) 2013-2016 Carbonite, Inc. All Rights Reserved.
* All Rights Reserved.
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* the above copyright notice appear in all copies and that both that
* copyright notice and this permission notice appear in supporting
* documentation, and that the name of U.M. not be used in advertising or
* publicity pertaining to distribution of the software without specific,
* written prior permission. U.M. makes no representations about the
* suitability of this software for any purpose. It is provided "as is"
* without express or implied warranty.
*
* U.M. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL U.M.
* BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Authors: the Amanda Development Team. Its members are listed in a
* file named AUTHORS, in the root directory of this distribution.
*/
/*
* $Id: amcheck.c,v 1.149 2006/08/24 01:57:16 paddy_s Exp $
*
* checks for common problems in server and clients
*/
#include "amanda.h"
#include "amutil.h"
#include "conffile.h"
#include "fsusage.h"
#include "diskfile.h"
#include "tapefile.h"
#include "packet.h"
#include "security.h"
#include "protocol.h"
#include "clock.h"
#include "amindex.h"
#include "server_util.h"
#include "pipespawn.h"
#include "amfeatures.h"
#include "device.h"
#include "property.h"
#include "timestamp.h"
#include "amxml.h"
#include "ammessage.h"
#include "physmem.h"
#include <getopt.h>
#define BUFFER_SIZE 32768
static time_t conf_ctimeout;
static int overwrite;
static disklist_t origq;
static uid_t uid_dumpuser;
static gboolean who_check_host_setting = TRUE;// TRUE => local check auth
// FALSE => client check auth
/* local functions */
void amcheck_exit(int status);
void usage(void);
pid_t start_client_checks(FILE *fd);
pid_t start_server_check(FILE *fd, int do_localchk, int do_tapechk);
int main(int argc, char **argv);
int check_tapefile(FILE *outf, char *tapefile);
int test_server_pgm(FILE *outf, char *dir, char *pgm, int suid, uid_t dumpuid);
static int check_host_setting(FILE *outf);
static am_feature_t *our_features = NULL;
static char *our_feature_string = NULL;
static char *displayunit;
static long int unitdivisor;
static gboolean dev_amanda_data_path = TRUE;
static gboolean dev_directtcp_data_path = TRUE;
static int client_verbose = FALSE;
static gboolean exact_match = FALSE;
static gboolean opt_message = FALSE;
static struct option long_options[] = {
{"client-verbose", 0, NULL, 1},
{"version" , 0, NULL, 2},
{"exact-match" , 0, NULL, 3},
{"message" , 0, NULL, 4},
{NULL, 0, NULL, 0}
};
static message_t *
amcheck_fprint_message(
FILE *file,
message_t *message);
static message_t *
amcheck_print_message(
message_t *message)
{
return amcheck_fprint_message(stdout, message);
}
static message_t *
amcheck_fprint_message(
FILE *file,
message_t *message)
{
char *hint;
if (opt_message) {
fprint_message(file, message);
} else {
char *prefix;
int severity = message_get_severity(message);
char *dle_hostname = message_get_argument(message, "dle_hostname");
if (dle_hostname && *dle_hostname) {
if (severity == MSG_SUCCESS) {
prefix = g_strdup_printf("HOST %s OK: ", dle_hostname);
} else if (severity == MSG_INFO) {
prefix = g_strdup_printf("HOST %s OK: ", dle_hostname);
} else if (severity == MSG_MESSAGE) {
prefix = g_strdup_printf("HOST %s OK: ", dle_hostname);
} else if (severity == MSG_WARNING) {
prefix = g_strdup_printf("HOST %s WARNING: ", dle_hostname);
} else if (severity == MSG_ERROR) {
prefix = g_strdup_printf("HOST %s ERROR: ", dle_hostname);
} else if (severity == MSG_CRITICAL) {
prefix = g_strdup_printf("HOST %s CRITICAL: ", dle_hostname);
} else {
prefix = g_strdup_printf("HOST %s BAD: ", dle_hostname);
}
} else {
if (severity == MSG_SUCCESS) {
prefix = g_strdup("NOTE: ");
} else if (severity == MSG_INFO) {
prefix = g_strdup("NOTE: ");
} else if (severity == MSG_MESSAGE) {
prefix = g_strdup("");
} else if (severity == MSG_WARNING) {
prefix = g_strdup("WARNING: ");
} else if (severity == MSG_ERROR) {
prefix = g_strdup("ERROR: ");
} else if (severity == MSG_CRITICAL) {
prefix = g_strdup("CRITICAL: ");
} else {
prefix = g_strdup("BAD: ");
}
}
g_fprintf(file, "%s%s\n", prefix, get_message(message));
if ((hint = message_get_hint(message)) != NULL) {
int len = strlen(prefix);
g_fprintf(file, "%*c%s\n", len, ' ', hint);
}
g_free(prefix);
}
return message;
}
void
amcheck_exit(
int status)
{
exit(status);
}
void
usage(void)
{
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800000, MSG_MESSAGE, 0)));
amcheck_exit(1);
/*NOTREACHED*/
}
int
main(
int argc,
char ** argv)
{
char buffer[BUFFER_SIZE];
char *mainfname = NULL;
char pid_str[NUM_STR_SIZE];
int do_clientchk, client_probs;
int do_localchk, do_tapechk, server_probs;
pid_t clientchk_pid, serverchk_pid;
FILE *tempfd, *mainfd;
amwait_t retstat;
pid_t pid;
extern int optind;
char *mailto = NULL;
extern char *optarg;
int mailout;
int alwaysmail;
char *tempfname = NULL;
char *conf_diskfile;
char *dumpuser;
struct passwd *pw;
uid_t uid_me;
GPtrArray *err_array;
guint i;
config_overrides_t *cfg_ovr;
char *mailer;
glib_init();
/*
* Configure program for internationalization:
* 1) Only set the message locale for now.
* 2) Set textdomain for all amanda related programs to "amanda"
* We don't want to be forced to support dozens of message catalogs.
*/
setlocale(LC_MESSAGES, "C");
textdomain("amanda");
safe_fd(-1, 0);
safe_cd();
set_pname("amcheck");
if (geteuid() != getuid()) {
error("amcheck must not be setuid (%d, %d)", (int)geteuid(), (int)getuid());
}
/* drop root privileges */
set_root_privs(-1);
/* Don't die when child closes pipe */
signal(SIGPIPE, SIG_IGN);
dbopen(DBG_SUBDIR_SERVER);
memset(buffer, 0, sizeof(buffer));
g_snprintf(pid_str, sizeof(pid_str), "%ld", (long)getpid());
add_amanda_log_handler(amanda_log_stderr);
our_features = am_init_feature_set();
our_feature_string = am_feature_to_string(our_features);
uid_me = geteuid();
alwaysmail = mailout = overwrite = 0;
do_localchk = do_tapechk = do_clientchk = 0;
server_probs = client_probs = 0;
tempfd = mainfd = NULL;
/* process arguments */
cfg_ovr = new_config_overrides(argc/2);
while (1) {
int option_index = 0;
int c;
c = getopt_long (argc, argv, "M:mawsclto:", long_options, &option_index);
if (c == -1) {
break;
}
switch(c) {
case 1: client_verbose = TRUE;
break;
case 2: delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800001, MSG_MESSAGE, 1,
"version", VERSION)));
return(0);
break;
case 3: exact_match = TRUE;
break;
case 4: opt_message = TRUE;
break;
case 'M': if (mailto) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800002, MSG_ERROR, 0)));
amcheck_exit(1);
}
mailto=g_strdup(optarg);
if(!validate_mailto(mailto)){
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800003, MSG_ERROR, 0)));
amcheck_exit(1);
}
/*FALLTHROUGH*/
case 'm': mailout = 1;
break;
case 'a': mailout = 1;
alwaysmail = 1;
break;
case 's': do_localchk = do_tapechk = 1;
break;
case 'c': do_clientchk = 1;
break;
case 'l': do_localchk = 1;
break;
case 'w': overwrite = 1;
break;
case 'o': add_config_override_opt(cfg_ovr, optarg);
break;
case 't': do_tapechk = 1;
break;
case '?':
default:
usage();
}
}
argc -= optind, argv += optind;
if(argc < 1) usage();
if ((do_localchk | do_clientchk | do_tapechk) == 0) {
/* Check everything if individual checks were not asked for */
do_localchk = do_clientchk = do_tapechk = 1;
}
if(overwrite)
do_tapechk = 1;
set_config_overrides(cfg_ovr);
config_init_with_global(CONFIG_INIT_EXPLICIT_NAME, argv[0]);
dbrename(get_config_name(), DBG_SUBDIR_SERVER);
/*
* Make sure we are running as the dump user. Don't use
* check_running_as(..) here, because we want to produce more
* verbose error messages.
*/
dumpuser = getconf_str(CNF_DUMPUSER);
if ((pw = getpwnam(dumpuser)) == NULL) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800215, MSG_ERROR, 1,
"dumpuser" , dumpuser)));
exit(1);
/*NOTREACHED*/
}
uid_dumpuser = pw->pw_uid;
if ((pw = getpwuid(uid_me)) == NULL) {
char *str_ui_me = g_strdup_printf("%ld", (long)uid_me);
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800216, MSG_ERROR, 1,
"uid" ,str_ui_me)));
g_free(str_ui_me);
exit(1);
/*NOTREACHED*/
}
#ifdef CHECK_USERID
if (uid_me != uid_dumpuser) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800217, MSG_ERROR, 2,
"running_user" , pw->pw_name,
"expected_user" , dumpuser)));
exit(1);
/*NOTREACHED*/
}
#endif
conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE));
read_diskfile(conf_diskfile, &origq);
disable_skip_disk(&origq);
amfree(conf_diskfile);
if (config_errors(NULL) >= CFGERR_WARNINGS) {
if (opt_message) {
config_print_errors_as_message();
} else {
config_print_errors();
}
if (config_errors(NULL) >= CFGERR_ERRORS) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800228, MSG_ERROR, 0)));
exit(1);
//g_critical("errors processing config file");
}
}
mailer = getconf_str(CNF_MAILER);
if ((!mailer || *mailer == '\0') && mailout == 1) {
if (alwaysmail == 1) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800004, MSG_ERROR, 0)));
} else {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800005, MSG_ERROR, 0)));
}
amcheck_exit(1);
}
if(mailout && !mailto &&
(getconf_seen(CNF_MAILTO)==0 || strlen(getconf_str(CNF_MAILTO)) == 0)) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800006, MSG_ERROR, 0)));
if (alwaysmail) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800008, MSG_ERROR, 0)));
} else {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800009, MSG_ERROR, 0)));
}
amcheck_exit(1);
}
if(mailout && !mailto)
{
if(getconf_seen(CNF_MAILTO) &&
strlen(getconf_str(CNF_MAILTO)) > 0) {
if(!validate_mailto(getconf_str(CNF_MAILTO))){
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800010, MSG_ERROR, 1,
"mailto", getconf_str(CNF_MAILTO))));
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800011, MSG_INFO, 0)));
mailout = 0;
}
}
else {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800012, MSG_ERROR, 0)));
if (alwaysmail) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800013, MSG_ERROR, 0)));
} else {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800014, MSG_ERROR, 0)));
}
amcheck_exit(1);
}
}
conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT);
err_array = match_disklist(&origq, exact_match, argc-1, argv+1);
if (err_array->len > 0) {
for (i = 0; i < err_array->len; i++) {
char *errstr = g_ptr_array_index(err_array, i);
g_debug("%s", errstr);
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800015, MSG_MESSAGE, 1,
"errstr", errstr)));
}
}
g_ptr_array_free(err_array, TRUE);
displayunit = getconf_str(CNF_DISPLAYUNIT);
unitdivisor = getconf_unit_divisor();
/*
* If both server and client side checks are being done, the server
* check output goes to the main output, while the client check output
* goes to a temporary file and is copied to the main output when done.
*
* If the output is to be mailed, the main output is also a disk file,
* otherwise it is stdout.
*/
if(do_clientchk && (do_localchk || do_tapechk)) {
/* we need the temp file */
tempfname = g_strjoin(NULL, AMANDA_TMPDIR, "/amcheck.temp.", pid_str, NULL);
if((tempfd = fopen(tempfname, "w+")) == NULL) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800218, MSG_ERROR, 2,
"filename", tempfname,
"errno" , errno)));
exit(1);
/*NOTREACHED*/
}
}
if(mailout) {
/* the main fd is a file too */
mainfname = g_strjoin(NULL, AMANDA_TMPDIR, "/amcheck.main.", pid_str, NULL);
if((mainfd = fopen(mainfname, "w+")) == NULL) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800219, MSG_ERROR, 2,
"filename", tempfname,
"errno" , errno)));
exit(1);
/*NOTREACHED*/
}
unlink(mainfname); /* so it goes away on close */
amfree(mainfname);
}
else
/* just use stdout */
mainfd = stdout;
who_check_host_setting = do_localchk;
/* start server side checks */
if(do_localchk || do_tapechk)
serverchk_pid = start_server_check(mainfd, do_localchk, do_tapechk);
else
serverchk_pid = 0;
/* start client side checks */
if(do_clientchk) {
clientchk_pid = start_client_checks((do_localchk || do_tapechk) ? tempfd : mainfd);
} else {
clientchk_pid = 0;
}
/* wait for child processes and note any problems */
while(1) {
if((pid = wait(&retstat)) == -1) {
if(errno == EINTR) continue;
else break;
} else if(pid == clientchk_pid) {
client_probs = WIFSIGNALED(retstat) || WEXITSTATUS(retstat);
clientchk_pid = 0;
} else if(pid == serverchk_pid) {
server_probs = WIFSIGNALED(retstat) || WEXITSTATUS(retstat);
serverchk_pid = 0;
} else {
delete_message(amcheck_fprint_message(mainfd, build_message(
AMANDA_FILE, __LINE__, 2800021, MSG_ERROR, 1,
"pid", g_strdup_printf("%ld", (long)pid))));
}
}
/* copy temp output to main output and write tagline */
if (tempfd) {
char line[1025];
FILE *tempfdr;
tempfdr = fopen(tempfname, "r");
if (!tempfdr) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800228, MSG_ERROR, 2,
"filename", tempfname,
"errno" , errno)));
} else {
if(fseek(tempfdr, (off_t)0, 0) == (off_t)-1) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800220, MSG_ERROR, 2,
"errno" , errno)));
exit(1);
/*NOTREACHED*/
}
if (opt_message) fprintf(mainfd,",\n");
while (fgets(line, 1024, tempfdr)) {
fprintf(mainfd, "%s", line);
}
fclose(tempfdr);
}
fclose(tempfd);
unlink(tempfname); /* so it goes away on close */
amfree(tempfname);
}
if (opt_message) fprintf(mainfd, ",\n");
delete_message(amcheck_fprint_message(mainfd, build_message(
AMANDA_FILE, __LINE__, 2800016, MSG_MESSAGE, 1,
"version", VERSION)));
amfree(our_feature_string);
am_release_feature_set(our_features);
our_features = NULL;
/* send mail if requested, but only if there were problems */
if((server_probs || client_probs || alwaysmail) && mailout) {
int mailfd;
int nullfd;
int errfd;
FILE *ferr;
char *subject;
char **a, **b;
GPtrArray *pipeargs;
amwait_t retstat;
size_t r;
size_t w;
char *err = NULL;
char *extra_info = NULL;
char *line = NULL;
int rc;
int valid_mailto = 0;
fflush(stdout);
if (fseek(mainfd, (off_t)0, SEEK_SET) == (off_t)-1) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800221, MSG_ERROR, 2,
"errno" , errno)));
exit(1);
/*NOTREACHED*/
}
if(alwaysmail && !(server_probs || client_probs)) {
subject = g_strdup_printf("%s AMCHECK REPORT: NO PROBLEMS FOUND",
getconf_str(CNF_ORG));
} else {
subject = g_strdup_printf(
"%s AMANDA PROBLEM: FIX BEFORE RUN, IF POSSIBLE",
getconf_str(CNF_ORG));
}
if(mailto) {
a = (char **) g_new0(char *, 2);
a[0] = g_strdup(mailto);
a[1] = NULL;
} else {
/* (note that validate_mailto doesn't allow any quotes, so this
* is really just splitting regular old strings) */
a = split_quoted_strings(getconf_str(CNF_MAILTO));
if (!a) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800017, MSG_ERROR, 1,
"mailto", getconf_str(CNF_MAILTO))));
amcheck_exit(1);
}
}
if((nullfd = open("/dev/null", O_RDWR)) < 0) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800227, MSG_ERROR, 2,
"errno" , errno)));
exit(1);
/*NOTREACHED*/
}
/* assemble the command line for the mailer */
pipeargs = g_ptr_array_sized_new(4);
g_ptr_array_add(pipeargs, mailer);
g_ptr_array_add(pipeargs, "-s");
g_ptr_array_add(pipeargs, subject);
for (b = a; *b; b++) {
if (strlen(*b) > 0) {
g_ptr_array_add(pipeargs, *b);
valid_mailto++;
}
}
g_ptr_array_add(pipeargs, NULL);
if (!valid_mailto) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800017, MSG_ERROR, 1,
"mailto", getconf_str(CNF_MAILTO))));
amcheck_exit(1);
}
pipespawnv(mailer, STDIN_PIPE | STDERR_PIPE, 0,
&mailfd, &nullfd, &errfd,
(char **)pipeargs->pdata);
g_ptr_array_free(pipeargs, FALSE);
amfree(subject);
amfree(mailto);
g_strfreev(a);
/*
* There is the potential for a deadlock here since we are writing
* to the process and then reading stderr, but in the normal case,
* nothing should be coming back to us, and hopefully in error
* cases, the pipe will break and we will exit out of the loop.
*/
signal(SIGPIPE, SIG_IGN);
while((r = read_fully(fileno(mainfd), buffer, sizeof(buffer), NULL)) > 0) {
if((w = full_write(mailfd, buffer, r)) != r) {
if(errno == EPIPE) {
strappend(extra_info, "EPIPE writing to mail process\n");
break;
} else if(errno != 0) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800222, MSG_ERROR, 2,
"errno" , errno)));
exit(1);
/*NOTREACHED*/
} else {
char *str_w = g_strdup_printf("%zd", w);
char *str_r = g_strdup_printf("%zd", r);
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800223, MSG_ERROR, 2,
"write_size" , str_w,
"expected_size" , str_r)));
g_free(str_w);
g_free(str_r);
exit(1);
/*NOTREACHED*/
}
}
}
aclose(mailfd);
ferr = fdopen(errfd, "r");
if (!ferr) {
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800224, MSG_ERROR, 1,
"errno" , errno)));
exit(1);
/*NOTREACHED*/
}
for(; (line = pgets(ferr)) != NULL; free(line)) {
if (line[0] == '\0')
continue;
strappend(extra_info, line);
strappend(extra_info, "\n");
}
afclose(ferr);
errfd = -1;
rc = 0;
while (wait(&retstat) != -1) {
if (!WIFEXITED(retstat) || WEXITSTATUS(retstat) != 0) {
char *mailer_error = str_exit_status("mailer", retstat);
strappend(err, mailer_error);
amfree(mailer_error);
rc = 1;
}
}
if (rc != 0) {
if(extra_info) {
fputs(extra_info, stderr);
amfree(extra_info);
}
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800225, MSG_ERROR, 2,
"mailer" , mailer,
"errmsg" , err?err:"(unknown)")));
exit(1);
/*NOTREACHED*/
} else {
amfree(extra_info);
}
}
g_debug("server_probs: %d", server_probs);
g_debug("client_probs: %d", client_probs);
dbclose();
return (server_probs || client_probs);
}
/* --------------------------------------------------- */
int check_tapefile(
FILE *outf,
char *tapefile)
{
struct stat statbuf;
int tapebad = 0;
if (stat(tapefile, &statbuf) == 0) {
if (!S_ISREG(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800018, MSG_ERROR, 1,
"tapelist" , tapefile)));
tapebad = 1;
} else if (access(tapefile, F_OK) != 0) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800019, MSG_ERROR, 2,
"errno" , errno,
"tapelist" , tapefile)));
tapebad = 1;
} else if (access(tapefile, W_OK) != 0) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800020, MSG_ERROR, 2,
"errno" , errno,
"tapelist" , tapefile)));
tapebad = 1;
}
}
return tapebad;
}
int
test_server_pgm(
FILE * outf,
char * dir,
char * pgm,
int suid,
uid_t dumpuid)
{
struct stat statbuf;
int pgmbad = 0;
pgm = g_strjoin(NULL, dir, "/", pgm, NULL);
if(stat(pgm, &statbuf) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800022, MSG_ERROR, 1,
"program", pgm)));
pgmbad = 1;
} else if (!S_ISREG(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800023, MSG_ERROR, 1,
"program", pgm)));
pgmbad = 1;
} else if (access(pgm, X_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800024, MSG_ERROR, 1,
"program", pgm)));
pgmbad = 1;
#ifndef SINGLE_USERID
} else if (suid) {
if (dumpuid != 0 &&
(statbuf.st_uid != 0 || (statbuf.st_mode & 04000) == 0)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800025, MSG_ERROR, 1,
"program", pgm)));
pgmbad = 1;
} else if ((statbuf.st_mode & 00023) != 0) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800235, MSG_ERROR, 1,
"program", pgm)));
pgmbad = 1;
}
#else
/* Quiet unused parameter warnings */
(void)suid;
(void)dumpuid;
#endif /* SINGLE_USERID */
}
amfree(pgm);
return pgmbad;
}
/* check that the tape is a valid amanda tape
Returns TRUE if all tests passed; FALSE otherwise. */
static gboolean test_tape_status(FILE * outf) {
int dev_outfd = -1;
FILE *dev_outf = NULL;
int outfd;
int nullfd = -1;
pid_t devpid;
char *amcheck_device = NULL;
char *line;
gchar **args;
amwait_t wait_status;
gboolean success = TRUE;
identlist_t il;
int i;
if ((nullfd = open("/dev/null", O_RDWR)) == -1) {
return FALSE;
}
fflush(outf);
outfd = fileno(outf);
amcheck_device = g_strjoin(NULL, amlibexecdir, "/", "amcheck-device", NULL);
i = 3;
if (opt_message) i++;
if (overwrite) i++;
args = get_config_options(i);
args[0] = amcheck_device; /* steal the reference */
args[1] = g_strdup(get_config_name());
args[2] = NULL;
i = 3;
if (opt_message)
args[i++] = g_strdup("--message");
if (overwrite)
args[i++] = g_strdup("-w");
for (il = getconf_identlist(CNF_STORAGE); il != NULL; il = il->next) {
args[2] = (char *)il->data;
/* run libexecdir/amcheck-device.pl, capturing STDERR and STDOUT to outf */
devpid = pipespawnv(amcheck_device, STDOUT_PIPE, 0,
&nullfd, &dev_outfd, &outfd,
(char **)args);
dev_outf = fdopen(dev_outfd, "r");
if (dev_outf == NULL) {
g_debug("Can't fdopen amcheck-device stdout: %s", strerror(errno));
aclose(dev_outfd);
} else {
while ((line = agets(dev_outf)) != NULL) {
if (strncmp(line, "DATA-PATH", 9) == 0) {
char *c = line;
dev_amanda_data_path = FALSE;
dev_directtcp_data_path = FALSE;
while ((c = strchr(c, ' ')) != NULL) {
c++;
if (strncmp(c, "AMANDA", 6) == 0) {
dev_amanda_data_path = TRUE;
} else if (strncmp(c, "DIRECTTCP", 9) == 0) {
dev_directtcp_data_path = TRUE;
}
}
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 123, MSG_MESSAGE, 1,
"errstr", line)));
}
g_free(line);
}
fclose(dev_outf);
}
/* and immediately wait for it to die */
waitpid(devpid, &wait_status, 0);
if (WIFSIGNALED(wait_status)) {
char *str_signal = g_strdup_printf("%d", WTERMSIG(wait_status));
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800026, MSG_ERROR, 1,
"signal", str_signal)));
g_free(str_signal);
success = FALSE;
} else if (WIFEXITED(wait_status)) {
if (WEXITSTATUS(wait_status) != 0)
success = FALSE;
} else {
success = FALSE;
}
args[2] = NULL;
}
g_strfreev(args);
close(nullfd);
return success;
}
pid_t
start_server_check(
FILE *outf,
int do_localchk,
int do_tapechk)
{
struct fs_usage fsusage;
pid_t pid G_GNUC_UNUSED;
int confbad = 0, tapebad = 0, disklow = 0, logbad = 0;
int userbad = 0, infobad = 0, indexbad = 0, pgmbad = 0;
int testtape = do_tapechk;
tapetype_t *tp = NULL;
storage_t *storage = NULL;
int res;
intmax_t kb_avail, kb_needed;
off_t tape_size;
gboolean printed_small_part_size_warning = FALSE;
switch(pid = fork()) {
case -1:
delete_message(amcheck_print_message(build_message(
AMANDA_FILE, __LINE__, 2800226, MSG_ERROR, 1,
"errno" , errno)));
exit(1);
g_assert_not_reached();
case 0:
break;
default:
return pid;
}
set_pname("amcheck-server");
startclock();
/* server does not need root privileges, and the access() calls below use the real userid,
* so totally drop privileges at this point (making the userid equal to the dumpuser) */
set_root_privs(-1);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800027, MSG_MESSAGE, 0)));
if (!opt_message) {
fprintf(outf, "-----------------------------\n");
}
if (who_check_host_setting) {
check_host_setting(outf);
}
if (do_localchk || testtape) {
identlist_t il;
for (il = getconf_identlist(CNF_STORAGE); il != NULL; il = il->next) {
char *storage_n = il->data;
policy_s *policy;
char *policy_n;
char *lbl_templ;
storage = lookup_storage(storage_n);
if (storage)
tp = lookup_tapetype(storage_get_tapetype(storage));
lbl_templ = tapetype_get_lbl_templ(tp);
if (!g_str_equal(lbl_templ, "")) {
lbl_templ = config_dir_relative(lbl_templ);
if (access(lbl_templ, R_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800029, MSG_ERROR, 3,
"errno", errno,
"storage", storage_n,
"filename", lbl_templ)));
confbad = 1;
}
amfree(lbl_templ);
#if !defined(HAVE_LPR_CMD)
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800030, MSG_ERROR, 1,
"storage", storage_n)));
confbad = 1;
#endif
}
if (storage_get_flush_threshold_scheduled(storage)
< storage_get_flush_threshold_dumped(storage)) {
char *str_flush_threshold_dumped = g_strdup_printf("%d", storage_get_flush_threshold_dumped(storage));
char *str_flush_threshold_scheduled = g_strdup_printf("%d", storage_get_flush_threshold_scheduled(storage));
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800031, MSG_WARNING, 3,
"storage", storage_n,
"flush_threshold_dumped", str_flush_threshold_dumped,
"flush_threshold_scheduled", str_flush_threshold_scheduled)));
g_free(str_flush_threshold_scheduled);
g_free(str_flush_threshold_dumped);
}
if (storage_get_flush_threshold_scheduled(storage)
< storage_get_taperflush(storage)) {
char *str_taperflush = g_strdup_printf("%d",storage_get_taperflush(storage));
char *str_flush_threshold_scheduled = g_strdup_printf("%d", storage_get_flush_threshold_scheduled(storage));
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800032, MSG_WARNING, 3,
"storage", storage_n,
"taperflush", str_taperflush,
"flush_threshold_scheduled", str_flush_threshold_scheduled)));
g_free(str_flush_threshold_scheduled);
g_free(str_taperflush);
}
if (storage_get_taperflush(storage) &&
!storage_get_autoflush(storage)) {
char *str_taperflush = g_strdup_printf("%d",storage_get_taperflush(storage));
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800033, MSG_WARNING, 3,
"storage", storage_n,
"taperflush", str_taperflush)));
g_free(str_taperflush);
}
if (!storage_seen(storage, STORAGE_TAPETYPE)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800034, MSG_ERROR, 1,
"storage", storage_n)));
confbad = 1;
}
policy_n = storage_get_policy(storage);
policy = lookup_policy(policy_n);
if (policy_get_retention_tapes(policy) <= storage_get_runtapes(storage)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800035, MSG_ERROR, 2,
"storage", storage_n,
"policy", policy_n)));
}
{
uintmax_t kb_avail = physmem_total() / 1024;
uintmax_t kb_needed = storage_get_device_output_buffer_size(storage) / 1024;
if (kb_avail < kb_needed) {
char *str_avail = g_strdup_printf("%ju", kb_avail);
char *str_needed = g_strdup_printf("%ju", kb_needed);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800036, MSG_ERROR, 2,
"kb_avail", str_avail,
"kb_needed", str_needed)));
g_free(str_avail);
g_free(str_needed);
}
}
}
/* Double-check that 'localhost' resolves properly */
if ((res = resolve_hostname("localhost", 0, NULL, NULL) != 0)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800037, MSG_ERROR, 1,
"gai_strerror", gai_strerror(res))));
confbad = 1;
}
}
/*
* Look up the programs used on the server side.
*/
if(do_localchk) {
/*
* entreprise version will do planner/dumper suid check
*/
if(access(amlibexecdir, X_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800038, MSG_ERROR, 2,
"dir", amlibexecdir,
"errno", errno)));
pgmbad = 1;
} else {
if(test_server_pgm(outf, amlibexecdir, "ambind", 1, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, amlibexecdir, "planner", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, amlibexecdir, "dumper", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, amlibexecdir, "driver", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, amlibexecdir, "taper", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, amlibexecdir, "amtrmidx", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, amlibexecdir, "amlogroll", 0, uid_dumpuser))
pgmbad = 1;
}
if(access(sbindir, X_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800040, MSG_ERROR, 2,
"dir", sbindir,
"errno", errno)));
pgmbad = 1;
} else {
if(test_server_pgm(outf, sbindir, "amgetconf", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, sbindir, "amcheck", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, sbindir, "amdump", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, sbindir, "amreport", 0, uid_dumpuser))
pgmbad = 1;
if(test_server_pgm(outf, sbindir, "amservice", 0, uid_dumpuser))
pgmbad = 1;
}
if(access(COMPRESS_PATH, X_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800042, MSG_WARNING, 2,
"program", COMPRESS_PATH,
"errno", errno)));
}
}
/*
* Check that the directory for the tapelist file is writable, as well
* as the tapelist file itself (if it already exists). Also, check for
* a "hold" file (just because it is convenient to do it here) and warn
* if tapedev is set to the null device.
*/
if(do_localchk || do_tapechk) {
char *tapefile;
char *newtapefile;
char *tape_dir;
char *lastslash;
char *holdfile;
char * tapename;
struct stat statbuf;
guint64 part_size, part_cache_max_size, tape_size;
part_cache_type_t part_cache_type;
char *part_cache_dir;
tapefile = config_dir_relative(getconf_str(CNF_TAPELIST));
/*
* XXX There Really Ought to be some error-checking here... dhw
*/
tape_dir = g_strdup(tapefile);
if ((lastslash = strrchr((const char *)tape_dir, '/')) != NULL) {
*lastslash = '\0';
/*
* else whine Really Loudly about a path with no slashes??!?
*/
}
if(access(tape_dir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800044, MSG_ERROR, 2,
"tape_dir", tape_dir,
"errno", errno)));
tapebad = 1;
}
else if(stat(tapefile, &statbuf) == -1) {
if (errno != ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800045, MSG_ERROR, 2,
"tapefile", tapefile,
"errno", errno)));
tapebad = 1;
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800046, MSG_INFO, 0)));
}
} else {
tapebad |= check_tapefile(outf, tapefile);
if (tapebad == 0 && read_tapelist(tapefile)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800047, MSG_INFO, 1,
"tapefile", tapefile)));
tapebad = 1;
}
newtapefile = g_strconcat(tapefile, ".new", NULL);
tapebad |= check_tapefile(outf, newtapefile);
amfree(newtapefile);
newtapefile = g_strconcat(tapefile, ".amlabel", NULL);
tapebad |= check_tapefile(outf, newtapefile);
amfree(newtapefile);
newtapefile = g_strconcat(tapefile, ".amlabel.new", NULL);
tapebad |= check_tapefile(outf, newtapefile);
amfree(newtapefile);
newtapefile = g_strconcat(tapefile, ".yesterday", NULL);
tapebad |= check_tapefile(outf, newtapefile);
amfree(newtapefile);
newtapefile = g_strconcat(tapefile, ".yesterday.new", NULL);
tapebad |= check_tapefile(outf, newtapefile);
amfree(newtapefile);
}
holdfile = config_dir_relative("hold");
if(access(holdfile, F_OK) != -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800048, MSG_WARNING, 1,
"holdfile", holdfile)));
}
amfree(tapefile);
amfree(tape_dir);
amfree(holdfile);
tapename = getconf_str(CNF_TAPEDEV);
if (tapename == NULL) {
if (getconf_str(CNF_TPCHANGER) == NULL &&
getconf_identlist(CNF_STORAGE) == NULL) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800051, MSG_WARNING, 1,
"storage", storage_name)));
testtape = 0;
do_tapechk = 0;
}
}
/* check tapetype-based splitting parameters */
part_size = tapetype_get_part_size(tp);
part_cache_type = tapetype_get_part_cache_type(tp);
part_cache_dir = tapetype_get_part_cache_dir(tp);
part_cache_max_size = tapetype_get_part_cache_max_size(tp);
if (!tapetype_seen(tp, TAPETYPE_PART_SIZE)) {
if (tapetype_seen(tp, TAPETYPE_PART_CACHE_TYPE)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800052, MSG_ERROR, 0)));
tapebad = 1;
}
if (tapetype_seen(tp, TAPETYPE_PART_CACHE_DIR)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800053, MSG_ERROR, 0)));
tapebad = 1;
}
if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800054, MSG_ERROR, 0)));
tapebad = 1;
}
} else {
switch (part_cache_type) {
case PART_CACHE_TYPE_DISK:
if (!tapetype_seen(tp, TAPETYPE_PART_CACHE_DIR)
|| !part_cache_dir || !*part_cache_dir) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800055, MSG_ERROR, 0)));
tapebad = 1;
} else {
if(get_fs_usage(part_cache_dir, NULL, &fsusage) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800056, MSG_ERROR, 2,
"errno", errno,
"part-cache-dir", part_cache_dir)));
tapebad = 1;
} else {
kb_avail = fsusage.fsu_bavail_top_bit_set?
0 : fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
kb_needed = part_size;
if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
kb_needed = part_cache_max_size;
}
if (kb_avail < kb_needed) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800057, MSG_ERROR, 2,
"kb_avail", kb_avail,
"kb_needed", kb_needed)));
tapebad = 1;
}
}
}
break;
case PART_CACHE_TYPE_MEMORY:
kb_avail = physmem_total() / 1024;
kb_needed = part_size;
if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
kb_needed = part_cache_max_size;
}
if (kb_avail < kb_needed) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800058, MSG_ERROR, 2,
"kb_avail", kb_avail,
"kb_needed", kb_needed)));
tapebad = 1;
}
/* FALL THROUGH */
case PART_CACHE_TYPE_NONE:
if (tapetype_seen(tp, TAPETYPE_PART_CACHE_DIR)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800059, MSG_ERROR, 0)));
tapebad = 1;
}
break;
}
}
if (tapetype_seen(tp, TAPETYPE_PART_SIZE) && part_size == 0
&& part_cache_type != PART_CACHE_TYPE_NONE) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800060, MSG_ERROR, 0)));
tapebad = 1;
}
if (tapetype_seen(tp, TAPETYPE_PART_CACHE_MAX_SIZE)) {
if (part_cache_type == PART_CACHE_TYPE_NONE) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800061, MSG_ERROR, 0)));
tapebad = 1;
}
if (part_cache_max_size > part_size) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800062, MSG_WARNING, 0)));
}
}
tape_size = tapetype_get_length(tp);
if (part_size && part_size * 1000 < tape_size) {
char *str_part_size = g_strdup_printf("%ju", (uintmax_t)part_size);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800063, MSG_WARNING, 1,
"part_size", str_part_size)));
g_free(str_part_size);
if (!printed_small_part_size_warning) {
printed_small_part_size_warning = TRUE;
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800064, MSG_WARNING, 0)));
}
} else if (part_cache_max_size && part_cache_max_size * 1000 < tape_size) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800065, MSG_WARNING, 1,
"part_size_max_size", part_cache_max_size)));
if (!printed_small_part_size_warning) {
printed_small_part_size_warning = TRUE;
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800064, MSG_WARNING, 0)));
}
}
}
/* check available disk space */
if(do_localchk) {
identlist_t il;
holdingdisk_t *hdp;
for (il = getconf_identlist(CNF_HOLDINGDISK);
il != NULL;
il = il->next) {
hdp = lookup_holdingdisk(il->data);
if(get_fs_usage(holdingdisk_get_diskdir(hdp), NULL, &fsusage) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800066, MSG_ERROR, 2,
"errno", errno,
"holding_dir", holdingdisk_get_diskdir(hdp))));
disklow = 1;
continue;
}
/* do the division first to avoid potential integer overflow */
if (fsusage.fsu_bavail_top_bit_set)
kb_avail = 0;
else
kb_avail = fsusage.fsu_bavail / 1024 * fsusage.fsu_blocksize;
if(access(holdingdisk_get_diskdir(hdp), W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800067, MSG_ERROR, 2,
"errno", errno,
"holding_dir", holdingdisk_get_diskdir(hdp))));
disklow = 1;
}
else if(access(holdingdisk_get_diskdir(hdp), X_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800069, MSG_ERROR, 2,
"errno", errno,
"holding_dir", holdingdisk_get_diskdir(hdp))));
disklow = 1;
}
else if(holdingdisk_get_disksize(hdp) > (off_t)0) {
if(kb_avail == 0) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800071, MSG_WARNING, 2,
"holding_dir", holdingdisk_get_diskdir(hdp),
"size", holdingdisk_get_disksize(hdp))));
disklow = 1;
}
else if(kb_avail < holdingdisk_get_disksize(hdp)) {
char *str_holdingdisk_get_disksize = g_strdup_printf("%jd", holdingdisk_get_disksize(hdp));
char *str_avail = g_strdup_printf("%jd", kb_avail);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800072, MSG_WARNING, 3,
"holding_dir", holdingdisk_get_diskdir(hdp),
"avail", str_avail,
"requested", str_holdingdisk_get_disksize)));
g_free(str_avail);
g_free(str_holdingdisk_get_disksize);
disklow = 1;
}
else {
char *str_holdingdisk_get_disksize = g_strdup_printf("%jd", holdingdisk_get_disksize(hdp));
char *str_avail = g_strdup_printf("%jd", kb_avail);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800073, MSG_INFO, 3,
"holding_dir", holdingdisk_get_diskdir(hdp),
"avail", str_avail,
"requested", str_holdingdisk_get_disksize)));
g_free(str_avail);
g_free(str_holdingdisk_get_disksize);
}
}
else {
if(kb_avail < -holdingdisk_get_disksize(hdp)) {
char *str_avail = g_strdup_printf("%jd", kb_avail);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800074, MSG_WARNING, 2,
"holding_dir", holdingdisk_get_diskdir(hdp),
"avail", str_avail)));
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800075, MSG_WARNING, 0)));
g_free(str_avail);
disklow = 1;
}
else {
char *str_avail = g_strdup_printf("%jd", kb_avail);
char *str_using = g_strdup_printf("%jd", kb_avail + holdingdisk_get_disksize(hdp));
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800076, MSG_INFO, 3,
"holding_dir", holdingdisk_get_diskdir(hdp),
"avail", str_avail,
"using", str_using)));
g_free(str_using);
g_free(str_avail);
}
}
}
}
/* check that the log file is writable if it already exists */
if(do_localchk) {
char *conf_logdir;
char *olddir;
struct stat stat_old;
struct stat statbuf;
conf_logdir = config_dir_relative(getconf_str(CNF_LOGDIR));
if(stat(conf_logdir, &statbuf) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800077, MSG_INFO, 2,
"errno", errno,
"logdir", conf_logdir)));
disklow = 1;
}
else if(access(conf_logdir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800078, MSG_ERROR, 2,
"errno", errno,
"logdir", conf_logdir)));
logbad = 1;
}
olddir = g_strjoin(NULL, conf_logdir, "/oldlog", NULL);
if (logbad == 0 && stat(olddir,&stat_old) == 0) { /* oldlog exist */
if(!(S_ISDIR(stat_old.st_mode))) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800079, MSG_ERROR, 2,
"oldlogdir", olddir)));
logbad = 1;
}
if(logbad == 0 && access(olddir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800081, MSG_ERROR, 2,
"errno", errno,
"oldlogdir", olddir)));
logbad = 1;
}
}
else if(logbad == 0 && lstat(olddir,&stat_old) == 0) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800083, MSG_ERROR, 2,
"errno", errno,
"oldlogdir", olddir)));
logbad = 1;
}
amfree(olddir);
amfree(conf_logdir);
}
if (testtape) {
tapebad = !test_tape_status(outf);
} else if (do_tapechk) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800085, MSG_WARNING, 0)));
dev_amanda_data_path = TRUE;
dev_directtcp_data_path = TRUE;
} else if (logbad == 2) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800087, MSG_MESSAGE, 0)));
/* we skipped the tape checks, but this is just a NOTE and
* should not result in a nonzero exit status, so reset logbad to 0 */
logbad = 0;
dev_amanda_data_path = TRUE;
dev_directtcp_data_path = TRUE;
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800089, MSG_INFO, 0)));
dev_amanda_data_path = TRUE;
dev_directtcp_data_path = TRUE;
}
/*
* See if the information file and index directory for each client
* and disk is OK. Since we may be seeing clients and/or disks for
* the first time, these are just warnings, not errors.
*/
if(do_localchk) {
char *conf_infofile;
char *conf_indexdir;
char *hostinfodir = NULL;
char *hostindexdir = NULL;
char *diskdir = NULL;
char *infofile = NULL;
struct stat statbuf;
disk_t *dp;
am_host_t *hostp;
int indexdir_checked = 0;
int hostindexdir_checked = 0;
char *host;
char *disk;
int conf_runspercycle;
identlist_t pp_scriptlist;
identlist_t il;
conf_runspercycle = getconf_int(CNF_RUNSPERCYCLE);
for (il = getconf_identlist(CNF_STORAGE); il != NULL; il = il->next) {
char *storage_name = (char *)il->data;
storage_t *storage = lookup_storage(storage_name);
char *policy_name = storage_get_policy(storage);
policy_s *policy = lookup_policy(policy_name);
int retention_tape = policy_get_retention_tapes(policy);
int runtapes = storage_get_runtapes(storage);
if (retention_tape <= conf_runspercycle) {
char *str_retention_tape = g_strdup_printf("%d", retention_tape);
char *str_conf_runspercycle = g_strdup_printf("%d", conf_runspercycle);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800090, MSG_INFO, 3,
"storage", storage_name,
"retention_tapes", str_retention_tape,
"runspercycle", str_conf_runspercycle)));
g_free(str_conf_runspercycle);
g_free(str_retention_tape);
}
if (retention_tape <= runtapes) {
char *str_retention_tape = g_strdup_printf("%d", retention_tape);
char *str_runtapes = g_strdup_printf("%d", runtapes);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800091, MSG_INFO, 3,
"storage", storage_name,
"retention_tapes", str_retention_tape,
"runtapes", str_runtapes)));
g_free(str_runtapes);
g_free(str_retention_tape);
}
}
for (il = getconf_identlist(CNF_VAULT_STORAGE); il != NULL; il = il->next) {
char *storage_name = (char *)il->data;
storage_t *storage = lookup_storage(storage_name);
char *policy_name = storage_get_policy(storage);
policy_s *policy = lookup_policy(policy_name);
int retention_tape = policy_get_retention_tapes(policy);
int runtapes = storage_get_runtapes(storage);
if (retention_tape <= conf_runspercycle) {
char *str_retention_tape = g_strdup_printf("%d", retention_tape);
char *str_conf_runspercycle = g_strdup_printf("%d", conf_runspercycle);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800090, MSG_INFO, 3,
"storage", storage_name,
"retention_tapes", str_retention_tape,
"runtapes", str_conf_runspercycle)));
g_free(str_conf_runspercycle);
g_free(str_retention_tape);
}
if (retention_tape <= runtapes) {
char *str_retention_tape = g_strdup_printf("%d", retention_tape);
char *str_runtapes = g_strdup_printf("%d", runtapes);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800091, MSG_INFO, 3,
"storage", storage_name,
"retention_tapes", str_retention_tape,
"runtapes", str_runtapes)));
g_free(str_runtapes);
g_free(str_retention_tape);
}
}
conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE));
conf_indexdir = config_dir_relative(getconf_str(CNF_INDEXDIR));
if(stat(conf_infofile, &statbuf) == -1) {
if (errno == ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800092, MSG_INFO, 1,
"infodir", conf_infofile)));
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800094, MSG_ERROR, 2,
"errno", errno,
"infodir", conf_infofile)));
infobad = 1;
}
amfree(conf_infofile);
} else if (!S_ISDIR(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800095, MSG_ERROR, 1,
"infodir", conf_infofile)));
amfree(conf_infofile);
infobad = 1;
} else if (access(conf_infofile, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800097, MSG_ERROR, 1,
"infodir", conf_infofile)));
amfree(conf_infofile);
infobad = 1;
} else {
char *errmsg = NULL;
if (check_infofile(conf_infofile, &origq, &errmsg) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800099, MSG_ERROR, 1,
"errmsg", errmsg)));
infobad = 1;
amfree(errmsg);
}
strappend(conf_infofile, "/");
}
while(!empty(origq)) {
hostp = ((disk_t *)origq.head->data)->host;
host = sanitise_filename(hostp->hostname);
if(conf_infofile) {
g_free(hostinfodir);
hostinfodir = g_strconcat(conf_infofile, host, NULL);
if(stat(hostinfodir, &statbuf) == -1) {
if (errno == ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800100, MSG_INFO, 1,
"hostinfodir", hostinfodir)));
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800102, MSG_ERROR, 2,
"errno", errno,
"hostinfodir", hostinfodir)));
infobad = 1;
}
amfree(hostinfodir);
} else if (!S_ISDIR(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800103, MSG_ERROR, 1,
"hostinfodir", hostinfodir)));
amfree(hostinfodir);
infobad = 1;
} else if (access(hostinfodir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800105, MSG_ERROR, 1,
"hostinfodir", hostinfodir)));
amfree(hostinfodir);
infobad = 1;
} else {
strappend(hostinfodir, "/");
}
}
for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
disk = sanitise_filename(dp->name);
if(hostinfodir) {
g_free(diskdir);
diskdir = g_strconcat(hostinfodir, disk, NULL);
infofile = g_strjoin(NULL, diskdir, "/", "info", NULL);
if(stat(diskdir, &statbuf) == -1) {
if (errno == ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800107, MSG_INFO, 1,
"diskdir", diskdir)));
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800109, MSG_ERROR, 2,
"errno", errno,
"diskdir", diskdir)));
infobad = 1;
}
} else if (!S_ISDIR(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800110, MSG_ERROR, 1,
"diskdir", diskdir)));
infobad = 1;
} else if (access(diskdir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800112, MSG_ERROR, 1,
"diskdir", diskdir)));
infobad = 1;
} else if(stat(infofile, &statbuf) == -1) {
if (errno == ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800114, MSG_INFO, 1,
"infofile", infofile)));
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800116, MSG_INFO, 2,
"errno", errno,
"diskdir", diskdir)));
infobad = 1;
}
} else if (!S_ISREG(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800117, MSG_ERROR, 1,
"infofile", infofile)));
infobad = 1;
} else if (access(infofile, R_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800119, MSG_ERROR, 1,
"infofile", infofile)));
infobad = 1;
}
amfree(infofile);
}
if(dp->index) {
if(! indexdir_checked) {
if(stat(conf_indexdir, &statbuf) == -1) {
if (errno == ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800120, MSG_INFO, 1,
"indexdir", conf_indexdir)));
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800122, MSG_ERROR, 2,
"errno", errno,
"indexdir", conf_indexdir)));
indexbad = 1;
}
amfree(conf_indexdir);
} else if (!S_ISDIR(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800123, MSG_ERROR, 1,
"indexdir", conf_indexdir)));
amfree(conf_indexdir);
indexbad = 1;
} else if (access(conf_indexdir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800125, MSG_ERROR, 1,
"indexdir", conf_indexdir)));
amfree(conf_indexdir);
indexbad = 1;
} else {
strappend(conf_indexdir, "/");
}
indexdir_checked = 1;
}
if(conf_indexdir) {
if(! hostindexdir_checked) {
hostindexdir = g_strconcat(conf_indexdir, host, NULL);
if(stat(hostindexdir, &statbuf) == -1) {
if (errno == ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800126, MSG_INFO, 1,
"hostindexdir", hostindexdir)));
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800128, MSG_ERROR, 2,
"errno", errno,
"hostindexdir", hostindexdir)));
indexbad = 1;
}
amfree(hostindexdir);
} else if (!S_ISDIR(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800129, MSG_ERROR, 1,
"hostindexdir", hostindexdir)));
amfree(hostindexdir);
indexbad = 1;
} else if (access(hostindexdir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800131, MSG_ERROR, 1,
"hostindexdir", hostindexdir)));
amfree(hostindexdir);
indexbad = 1;
} else {
strappend(hostindexdir, "/");
}
hostindexdir_checked = 1;
}
if(hostindexdir) {
g_free(diskdir);
diskdir = g_strconcat(hostindexdir, disk, NULL);
if(stat(diskdir, &statbuf) == -1) {
if (errno == ENOENT) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800132, MSG_INFO, 1,
"diskindexdir", diskdir)));
} else {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800132, MSG_ERROR, 2,
"errno", errno,
"diskindexdir", diskdir)));
indexbad = 1;
}
} else if (!S_ISDIR(statbuf.st_mode)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800135, MSG_ERROR, 2,
"errno", errno,
"diskindexdir", diskdir)));
indexbad = 1;
} else if (access(diskdir, W_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800137, MSG_ERROR, 1,
"diskindexdir", diskdir)));
indexbad = 1;
}
}
}
}
if ( dp->encrypt == ENCRYPT_SERV_CUST ) {
if ( dp->srv_encrypt[0] == '\0' ) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800138, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
else if(access(dp->srv_encrypt, X_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800140, MSG_ERROR, 1,
"program", dp->srv_encrypt)));
pgmbad = 1;
}
}
if ( dp->compress == COMP_SERVER_CUST ) {
if ( dp->srvcompprog[0] == '\0' ) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800142, MSG_ERROR, 0)));
pgmbad = 1;
}
else if(access(dp->srvcompprog, X_OK) == -1) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800144, MSG_ERROR, 1,
"program", dp->srvcompprog)));
pgmbad = 1;
}
}
/* check deprecated splitting parameters */
if (dumptype_seen(dp->config, DUMPTYPE_TAPE_SPLITSIZE)
|| dumptype_seen(dp->config, DUMPTYPE_SPLIT_DISKBUFFER)
|| dumptype_seen(dp->config, DUMPTYPE_FALLBACK_SPLITSIZE)) {
tape_size = tapetype_get_length(tp);
if (dp->tape_splitsize > tape_size) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800145, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
if (dp->tape_splitsize && dp->fallback_splitsize * 1024 > physmem_total()) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800147, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
if (dp->tape_splitsize && dp->fallback_splitsize > tape_size) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800148, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
/* also check for part sizes that are too small */
if (dp->tape_splitsize && dp->tape_splitsize * 1000 < tape_size) {
char *str_tape_splitsize = g_strdup_printf("%jd", (intmax_t)dp->tape_splitsize);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800149, MSG_WARNING, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"tape_splitsize", str_tape_splitsize)));
g_free(str_tape_splitsize);
if (!printed_small_part_size_warning) {
printed_small_part_size_warning = TRUE;
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800064, MSG_WARNING, 0)));
}
}
/* fallback splitsize will be used if split_diskbuffer is empty or NULL */
if (dp->tape_splitsize != 0 && dp->fallback_splitsize != 0 &&
(dp->split_diskbuffer == NULL ||
dp->split_diskbuffer[0] == '\0') &&
dp->fallback_splitsize * 1000 < tape_size) {
char *str_fallback_splitsize = g_strdup_printf("%jd", (intmax_t)dp->fallback_splitsize);
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800151, MSG_WARNING, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"fallback_splitsize", str_fallback_splitsize)));
g_free(str_fallback_splitsize);
if (!printed_small_part_size_warning) {
printed_small_part_size_warning = TRUE;
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800064, MSG_WARNING, 0)));
}
}
}
if (dp->data_path == DATA_PATH_DIRECTTCP) {
if (dp->compress != COMP_NONE) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800153, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
if (dp->encrypt != ENCRYPT_NONE) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800154, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
if (dp->to_holdingdisk == HOLD_REQUIRED) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800155, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
}
if (dp->data_path == DATA_PATH_DIRECTTCP && !dev_directtcp_data_path) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800156, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
if (dp->data_path == DATA_PATH_AMANDA && !dev_amanda_data_path) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800157, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
pgmbad = 1;
}
for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
pp_scriptlist = pp_scriptlist->next) {
pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
g_assert(pp_script != NULL);
if (pp_script_get_execute_where(pp_script) == EXECUTE_WHERE_CLIENT &&
pp_script_get_execute_on(pp_script) & EXECUTE_ON_PRE_HOST_BACKUP) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800158, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
} else if (pp_script_get_execute_where(pp_script) == EXECUTE_WHERE_CLIENT &&
pp_script_get_execute_on(pp_script) & EXECUTE_ON_POST_HOST_BACKUP) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800159, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
}
}
// check TAG match one of the storage
{
identlist_t tags;
int count = 0;
int match_all = 0;
int match_full = 0;
int match_incr = 0;
for (tags = dp->tags; tags != NULL ; tags = tags->next) {
gboolean found = FALSE;
count++;
for (storage = get_first_storage(); storage != NULL;
storage = get_next_storage(storage)) {
dump_selection_list_t dsl = storage_get_dump_selection(storage);
if (!dsl)
continue;
for (; dsl != NULL ; dsl = dsl->next) {
dump_selection_t *ds = dsl->data;
if (ds->tag_type == TAG_NAME) {
if (g_str_equal(ds->tag, tags->data)) {
found = TRUE;
if (ds->level == LEVEL_ALL)
match_all++;
else if (ds->level == LEVEL_FULL)
match_full++;
else if (ds->level == LEVEL_INCR)
match_incr++;
}
}
}
}
if (!found) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800233, MSG_WARNING, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"tag", tags->data)));
}
}
if (dp->to_holdingdisk == HOLD_NEVER &&
(match_all+match_full > 1 ||
match_all+match_incr > 1)) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800234, MSG_WARNING, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
}
}
amfree(disk);
remove_disk(&origq, dp);
}
amfree(host);
amfree(hostindexdir);
hostindexdir_checked = 0;
}
amfree(diskdir);
amfree(hostinfodir);
amfree(conf_infofile);
amfree(conf_indexdir);
}
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__, 2800160, MSG_MESSAGE, 1,
"seconds", walltime_str(curclock()))));
fflush(outf);
g_debug("userbad: %d", userbad);
g_debug("confbad: %d", confbad);
g_debug("tapebad: %d", tapebad);
g_debug("disklow: %d", disklow);
g_debug("logbad: %d", logbad);
g_debug("infobad: %d", infobad);
g_debug("indexbad: %d", indexbad);
g_debug("pgmbad: %d", pgmbad);
amcheck_exit(userbad \
|| confbad \
|| tapebad \
|| disklow \
|| logbad \
|| infobad \
|| indexbad \
|| pgmbad);
/*NOTREACHED*/
return 0;
}
/* --------------------------------------------------- */
int remote_errors;
FILE *client_outf;
static void handle_result(void *, pkt_t *, security_handle_t *);
void start_host(am_host_t *hostp);
#define HOST_READY (0) /* must be 0 */
#define HOST_ACTIVE (1)
#define HOST_DONE (2)
#define DISK_READY (0) /* must be 0 */
#define DISK_ACTIVE (1)
#define DISK_DONE (2)
void
start_host(
am_host_t *hostp)
{
disk_t *dp;
char *req = NULL;
size_t req_len = 0;
int disk_count;
const security_driver_t *secdrv;
char number[NUM_STR_SIZE];
estimate_t estimate;
GString *strbuf;
if(hostp->status != HOST_READY) {
return;
}
/*
* The first time through here we send a "noop" request. This will
* return the feature list from the client if it supports that.
* If it does not, handle_result() will set the feature list to an
* empty structure. In either case, we do the disks on the second
* (and subsequent) pass(es).
*/
disk_count = 0;
if(hostp->features != NULL) { /* selfcheck service */
int has_features = am_has_feature(hostp->features,
fe_req_options_features);
int has_hostname = am_has_feature(hostp->features,
fe_req_options_hostname);
int has_maxdumps = am_has_feature(hostp->features,
fe_req_options_maxdumps);
int has_config = am_has_feature(hostp->features,
fe_req_options_config);
if(!am_has_feature(hostp->features, fe_selfcheck_req) &&
!am_has_feature(hostp->features, fe_selfcheck_req_device)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800161, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
if(!am_has_feature(hostp->features, fe_selfcheck_rep)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800163, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
if(!am_has_feature(hostp->features, fe_sendsize_req_options) &&
!am_has_feature(hostp->features, fe_sendsize_req_no_options) &&
!am_has_feature(hostp->features, fe_sendsize_req_device)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800165, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
if(!am_has_feature(hostp->features, fe_sendsize_rep)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800167, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
if(!am_has_feature(hostp->features, fe_sendbackup_req) &&
!am_has_feature(hostp->features, fe_sendbackup_req_device)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800169, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
if(!am_has_feature(hostp->features, fe_sendbackup_rep)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800171, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
g_snprintf(number, sizeof(number), "%d", hostp->maxdumps);
req = g_strjoin(NULL, "SERVICE ", "selfcheck", "\n",
"OPTIONS ",
has_features ? "features=" : "",
has_features ? our_feature_string : "",
has_features ? ";" : "",
has_maxdumps ? "maxdumps=" : "",
has_maxdumps ? number : "",
has_maxdumps ? ";" : "",
has_hostname ? "hostname=" : "",
has_hostname ? hostp->hostname : "",
has_hostname ? ";" : "",
has_config ? "config=" : "",
has_config ? get_config_name() : "",
has_config ? ";" : "",
"\n",
NULL);
req_len = strlen(req);
req_len += 128; /* room for SECURITY ... */
req_len += 256; /* room for non-disk answers */
for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
char *l;
char *es;
size_t l_len;
char *o = NULL;
char *calcsize;
char *qname, *b64disk;
char *qdevice, *b64device = NULL;
gchar **errors;
if(dp->status != DISK_READY || dp->todo != 1) {
continue;
}
qname = quote_string(dp->name);
errors = validate_optionstr(dp);
if (errors) {
gchar **ptr;
for (ptr = errors; *ptr; ptr++)
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800173, MSG_ERROR, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"errstr" , *ptr)));
g_strfreev(errors);
amfree(qname);
remote_errors++;
continue;
} else if (am_has_feature(hostp->features, fe_req_xml)) {
o = xml_optionstr(dp, 0);
} else {
o = optionstr(dp);
}
b64disk = amxml_format_tag("disk", dp->name);
qdevice = quote_string(dp->device);
if (dp->device)
b64device = amxml_format_tag("diskdevice", dp->device);
if ((qname[0] == '"') ||
(dp->device && qdevice[0] == '"')) {
if(!am_has_feature(hostp->features, fe_interface_quoted_text)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800174, MSG_ERROR, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"device" , dp->device)));
}
}
if(dp->device) {
if(!am_has_feature(hostp->features, fe_selfcheck_req_device)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800176, MSG_ERROR, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"device" , dp->device)));
}
if(!am_has_feature(hostp->features, fe_sendsize_req_device)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800178, MSG_ERROR, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"device" , dp->device)));
}
if(!am_has_feature(hostp->features, fe_sendbackup_req_device)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800180, MSG_ERROR, 3,
"hostname", hostp->hostname,
"diskname", dp->name,
"device" , dp->device)));
}
if (dp->data_path != DATA_PATH_AMANDA &&
!am_has_feature(hostp->features, fe_xml_data_path)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800182, MSG_ERROR, 2,
"hostname", hostp->hostname,
"data-path", data_path_to_string(dp->data_path))));
} else if (dp->data_path == DATA_PATH_DIRECTTCP &&
!am_has_feature(hostp->features, fe_xml_directtcp_list)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800183, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
}
if (dp->program &&
(g_str_equal(dp->program, "DUMP") ||
g_str_equal(dp->program, "GNUTAR"))) {
if(g_str_equal(dp->program, "DUMP") &&
!am_has_feature(hostp->features, fe_program_dump)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800184, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
}
if(g_str_equal(dp->program, "GNUTAR") &&
!am_has_feature(hostp->features, fe_program_gnutar)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800186, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
}
estimate = (estimate_t)GPOINTER_TO_INT(dp->estimatelist->data);
if(estimate == ES_CALCSIZE &&
!am_has_feature(hostp->features, fe_calcsize_estimate)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800188, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
estimate = ES_CLIENT;
}
if(estimate == ES_CALCSIZE &&
am_has_feature(hostp->features, fe_selfcheck_calcsize))
calcsize = "CALCSIZE ";
else
calcsize = "";
if(dp->compress == COMP_CUST &&
!am_has_feature(hostp->features, fe_options_compress_cust)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800190, MSG_ERROR, 1,
"hostname", hostp->hostname)));
}
if(dp->encrypt == ENCRYPT_CUST ) {
if ( !am_has_feature(hostp->features, fe_options_encrypt_cust)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800193, MSG_ERROR, 1,
"hostname", hostp->hostname)));
remote_errors++;
} else if ( dp->compress == COMP_SERVER_FAST ||
dp->compress == COMP_SERVER_BEST ||
dp->compress == COMP_SERVER_CUST ) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800195, MSG_ERROR, 1,
"hostname", hostp->hostname)));
remote_errors++;
}
}
if (am_has_feature(hostp->features, fe_req_xml)) {
strbuf = g_string_new("<dle>\n");
es = xml_estimate(dp->estimatelist, hostp->features);
g_string_append_printf(strbuf,
" <program>%s</program>\n"
"%s\n"
" %s\n",
dp->program, es, b64disk
);
g_free(es);
if (dp->device)
g_string_append_printf(strbuf, " %s\n", b64device);
g_string_append_printf(strbuf, "%s</dle>\n", o);
l = g_string_free(strbuf, FALSE);
} else {
if (dp->device) {
l = g_strjoin(NULL, calcsize,
dp->program, " ",
qname, " ",
qdevice,
" 0 OPTIONS |",
o,
"\n",
NULL);
} else {
l = g_strjoin(NULL, calcsize,
dp->program, " ",
qname,
" 0 OPTIONS |",
o,
"\n",
NULL);
}
}
} else {
if (!am_has_feature(hostp->features, fe_program_application_api) ||
!am_has_feature(hostp->features, fe_req_xml)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800196, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
remote_errors++;
l = g_strdup("");
} else {
strbuf = g_string_new("<dle>\n <program>APPLICATION</program>\n");
if (dp->application) {
application_t *application = lookup_application(dp->application);
if (!application) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800198, MSG_ERROR, 1,
"application", dp->application)));
} else {
char *xml_app = xml_application(dp, application, hostp->features);
char *client_name = application_get_client_name(application);
if (client_name && strlen(client_name) > 0 &&
!am_has_feature(hostp->features, fe_application_client_name)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800199, MSG_WARNING, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
}
g_string_append(strbuf, xml_app);
g_free(xml_app);
}
}
if (dp->pp_scriptlist) {
if (!am_has_feature(hostp->features, fe_pp_script)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800200, MSG_ERROR, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
} else {
identlist_t pp_scriptlist;
for (pp_scriptlist = dp->pp_scriptlist; pp_scriptlist != NULL;
pp_scriptlist = pp_scriptlist->next) {
pp_script_t *pp_script = lookup_pp_script((char *)pp_scriptlist->data);
char *client_name = pp_script_get_client_name(pp_script);;
if (client_name && strlen(client_name) > 0 &&
!am_has_feature(hostp->features, fe_script_client_name)) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800201, MSG_WARNING, 2,
"hostname", hostp->hostname,
"diskname", dp->name)));
}
}
}
}
es = xml_estimate(dp->estimatelist, hostp->features);
g_string_append_printf(strbuf, "%s\n %s\n", es, b64disk);
g_free(es);
if (dp->device)
g_string_append_printf(strbuf, " %s\n", b64device);
g_string_append_printf(strbuf, "%s</dle>\n", o);
l = g_string_free(strbuf, FALSE);
}
}
amfree(qname);
amfree(qdevice);
amfree(b64disk);
amfree(b64device);
l_len = strlen(l);
amfree(o);
strappend(req, l);
req_len += l_len;
amfree(l);
dp->status = DISK_ACTIVE;
disk_count++;
}
}
else { /* noop service */
req = g_strjoin(NULL, "SERVICE ", "noop", "\n",
"OPTIONS ",
"features=", our_feature_string, ";",
"\n",
NULL);
for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
if(dp->status != DISK_READY || dp->todo != 1) {
continue;
}
disk_count++;
}
}
if(disk_count == 0) {
amfree(req);
hostp->status = HOST_DONE;
return;
}
secdrv = security_getdriver(hostp->disks->auth);
if (secdrv == NULL) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800213, MSG_ERROR, 2,
"hostname", hostp->hostname,
"auth", hostp->disks->auth)));
} else {
protocol_sendreq(hostp->hostname, secdrv, amhost_get_security_conf,
req, conf_ctimeout, handle_result, hostp);
}
amfree(req);
hostp->status = HOST_ACTIVE;
}
pid_t
start_client_checks(
FILE *outf)
{
am_host_t *hostp;
GList *dlist;
disk_t *dp, *dp1;
int hostcount;
pid_t pid;
int userbad = 0;
switch(pid = fork()) {
case -1:
error("INTERNAL ERROR:could not fork client check: %s", strerror(errno));
/*NOTREACHED*/
case 0:
break;
default:
return pid;
}
set_pname("amcheck-clients");
client_outf = outf;
startclock();
// fprint_message(outf, 2800214, "\n");
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800202, MSG_MESSAGE, 0)));
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800203, MSG_MESSAGE, 0)));
hostcount = remote_errors = 0;
if (!who_check_host_setting) {
remote_errors = check_host_setting(client_outf);
}
run_server_global_scripts(EXECUTE_ON_PRE_AMCHECK, get_config_name(), NULL);
protocol_init();
for(dlist = origq.head; dlist != NULL; dlist = dlist->next) {
dp = dlist->data;
hostp = dp->host;
if(hostp->status == HOST_READY && dp->todo == 1) {
run_server_host_scripts(EXECUTE_ON_PRE_HOST_AMCHECK,
get_config_name(), NULL, hostp);
for(dp1 = hostp->disks; dp1 != NULL; dp1 = dp1->hostnext) {
run_server_dle_scripts(EXECUTE_ON_PRE_DLE_AMCHECK,
get_config_name(), NULL, dp1, -1);
}
start_host(hostp);
hostcount++;
protocol_check();
}
}
protocol_run();
run_server_global_scripts(EXECUTE_ON_POST_AMCHECK, get_config_name(), NULL);
{
char *str_hostcount = g_strdup_printf("%d", hostcount);
char *str_remote_errors = g_strdup_printf("%d", remote_errors);
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800204, MSG_MESSAGE, 3,
"hostcount", str_hostcount,
"remote_errors", str_remote_errors,
"seconds", walltime_str(curclock()))));
g_free(str_hostcount);
g_free(str_remote_errors);
}
fflush(outf);
g_debug("userbad: %d", userbad);
g_debug("remote_errors: %d", remote_errors);
amcheck_exit(userbad || remote_errors > 0);
/*NOTREACHED*/
return 0;
}
static void amcheck_print_array_message(gpointer data, gpointer user_data);
static void
amcheck_print_array_message(
gpointer data,
gpointer user_data)
{
FILE *stream = (FILE *)user_data;
message_t *message = data;
int severity = message_get_severity(message);
if ((severity == MSG_SUCCESS ||
severity == MSG_INFO) &&
client_verbose) {
amcheck_fprint_message(stream, message);
} else if (severity > MSG_INFO) {
remote_errors++;
amcheck_fprint_message(stream, message);
}
delete_message(message);
}
static void add_hostname_message(gpointer data, gpointer user_data);
static void
add_hostname_message(
gpointer data,
gpointer user_data)
{
char *dle_hostname = (char *)user_data;
message_t *message = data;
message_add_argument(message, "dle_hostname", dle_hostname);
}
static void
handle_result(
void * datap,
pkt_t * pkt,
security_handle_t * sech)
{
am_host_t *hostp;
disk_t *dp;
char *line;
char *s;
char *t;
int ch;
int tch;
gboolean printed_hostname = FALSE;
char *message_buffer = NULL;
hostp = (am_host_t *)datap;
hostp->status = HOST_READY;
if (pkt == NULL) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800206, MSG_ERROR, 2,
"hostname", hostp->hostname,
"errstr", security_geterror(sech))));
remote_errors++;
hostp->status = HOST_DONE;
security_close_connection(sech, hostp->hostname);
return;
}
s = pkt->body;
ch = *s++;
while(ch) {
line = s - 1;
skip_quoted_line(s, ch);
if (s[-2] == '\n') {
s[-2] = '\0';
}
if(strncmp_const(line, "OPTIONS ") == 0) {
t = strstr(line, "features=");
if(t != NULL && (g_ascii_isspace((int)t[-1]) || t[-1] == ';')) {
char *u = strchr(t, ';');
if (u)
*u = '\0';
t += sizeof("features=")-1;
am_release_feature_set(hostp->features);
if((hostp->features = am_string_to_feature(t)) == NULL) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800207, MSG_ERROR, 2,
"hostname", hostp->hostname,
"features", t)));
remote_errors++;
hostp->status = HOST_DONE;
}
if (u)
*u = ';';
}
continue;
}
if (client_verbose && !printed_hostname) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800209, MSG_INFO, 1,
"dle_hostname", hostp->hostname)));
printed_hostname = TRUE;
}
if (strncmp_const(line, "MESSAGE JSON") == 0) {
// line+13 is the complete buffer
message_buffer = g_strdup(line+13);
break;
}
if(strncmp_const(line, "OK ") == 0) {
if (client_verbose) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800210, MSG_INFO, 2,
"dle_hostname", hostp->hostname,
"ok_line", line+3)));
}
continue;
}
t = line;
if(strncmp_const_skip(line, "ERROR ", t, tch) == 0) {
skip_whitespace(t, tch);
/*
* If the "error" is that the "noop" service is unknown, it
* just means the client is "old" (does not support the service).
* We can ignore this.
*/
if(!((hostp->features == NULL) && (pkt->type == P_NAK)
&& ((g_str_equal(t - 1, "unknown service: noop"))
|| (g_str_equal(t - 1, "noop: invalid service"))))) {
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800211, MSG_ERROR, 3,
"hostname", hostp->hostname,
"type", (pkt->type == P_NAK) ? "NAK " : "",
"errstr", t - 1)));
remote_errors++;
hostp->status = HOST_DONE;
}
continue;
}
delete_message(amcheck_fprint_message(client_outf, build_message(
AMANDA_FILE, __LINE__, 2800212, MSG_ERROR, 2,
"hostname", hostp->hostname,
"errstr", line)));
remote_errors++;
hostp->status = HOST_DONE;
}
if (message_buffer) {
/* parse message_buffer into a message_t array */
GPtrArray *message_array = parse_json_message(message_buffer);
/* add hostname to all messages */
g_ptr_array_foreach(message_array, add_hostname_message, hostp->hostname);
/* print and delete the messages */
g_ptr_array_foreach(message_array, amcheck_print_array_message, client_outf);
g_free(message_buffer);
g_ptr_array_free(message_array, TRUE);
}
if(hostp->status == HOST_READY && hostp->features == NULL) {
/*
* The client does not support the features list, so give it an
* empty one.
*/
g_debug("no feature set from host %s", hostp->hostname);
hostp->features = am_set_default_feature_set();
}
for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
if(dp->status == DISK_ACTIVE) {
dp->status = DISK_DONE;
}
}
start_host(hostp);
if(hostp->status == HOST_DONE) {
security_close_connection(sech, hostp->hostname);
for(dp = hostp->disks; dp != NULL; dp = dp->hostnext) {
run_server_dle_scripts(EXECUTE_ON_POST_DLE_AMCHECK,
get_config_name(), NULL, dp, -1);
}
run_server_host_scripts(EXECUTE_ON_POST_HOST_AMCHECK,
get_config_name(), NULL, hostp);
}
/* try to clean up any defunct processes, since Amanda doesn't wait() for
them explicitly */
while(waitpid(-1, NULL, WNOHANG)> 0);
}
static int
check_host_setting(
FILE *outf)
{
am_host_t *p;
disk_t *dp;
int count = 0;
for (p = get_hostlist(); p != NULL; p = p->next) {
for(dp = p->disks; dp != NULL; dp = dp->hostnext) {
if (strcmp(dp->auth, p->disks->auth) != 0) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__,
2800231, MSG_ERROR, 3,
"hostname", p->hostname,
"auth1", p->disks->auth,
"auth2", dp->auth)));
count++;
break;
}
}
for(dp = p->disks; dp != NULL; dp = dp->hostnext) {
if (dp->maxdumps != p->disks->maxdumps) {
delete_message(amcheck_fprint_message(outf, build_message(
AMANDA_FILE, __LINE__,
2800232, MSG_ERROR, 1,
"hostname", p->hostname)));
count++;
break;
}
}
}
return count;
}