📄 amcheck.c
字号:
/* * Amanda, The Advanced Maryland Automatic Network Disk Archiver * Copyright (c) 1991-2000 University of Maryland at College Park * 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 "util.h"#include "conffile.h"#include "columnar.h"#include "fsusage.h"#include "diskfile.h"#include "tapefile.h"#include "changer.h"#include "packet.h"#include "security.h"#include "protocol.h"#include "clock.h"#include "version.h"#include "amindex.h"#include "token.h"#include "taperscan.h"#include "server_util.h"#include "pipespawn.h"#include "amfeatures.h"#include "device.h"#include "property.h"#include "timestamp.h"#define BUFFER_SIZE 32768static time_t conf_ctimeout;static int overwrite;static disklist_t origq;static uid_t uid_dumpuser;/* local functions */void usage(void);pid_t start_client_checks(int fd);pid_t start_server_check(int 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);voidusage(void){ error(_("Usage: amcheck%s [-am] [-w] [-sclt] [-M <address>] <conf> [host [disk]* ]* [-o configoption]*"), versionsuffix()); /*NOTREACHED*/}static am_feature_t *our_features = NULL;static char *our_feature_string = NULL;static char *displayunit;static long int unitdivisor;intmain( int argc, char ** argv){ char buffer[BUFFER_SIZE]; char *version_string; 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; int opt, tempfd, mainfd; ssize_t size; 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; char *errstr; config_overwrites_t *cfg_ovr; /* * 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"); /* drop root privileges */ if (!set_root_privs(0)) { error(_("amcheck must be run setuid root")); } /* 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()); erroutput_type = ERR_INTERACTIVE; our_features = am_init_feature_set(); our_feature_string = am_feature_to_string(our_features); uid_me = getuid(); alwaysmail = mailout = overwrite = 0; do_localchk = do_tapechk = do_clientchk = 0; server_probs = client_probs = 0; tempfd = mainfd = -1; /* process arguments */ cfg_ovr = new_config_overwrites(argc/2); while((opt = getopt(argc, argv, "M:mawsclto:")) != EOF) { switch(opt) { case 'M': mailto=stralloc(optarg); if(!validate_mailto(mailto)){ g_printf(_("Invalid characters in mail address\n")); exit(1); } /*FALLTHROUGH*/ case 'm': #ifdef MAILER mailout = 1;#else g_printf(_("You can't use -%c because configure didn't " "find a mailer./usr/bin/mail not found\n"), opt); exit(1);#endif break; case 'a': #ifdef MAILER mailout = 1; alwaysmail = 1;#else g_printf(_("You can't use -%c because configure didn't " "find a mailer./usr/bin/mail not found\n"), opt); exit(1);#endif 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_overwrite_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; config_init(CONFIG_INIT_EXPLICIT_NAME|CONFIG_INIT_FATAL, argv[0]); apply_config_overwrites(cfg_ovr); dbrename(config_name, DBG_SUBDIR_SERVER); if(mailout && !mailto && (getconf_seen(CNF_MAILTO)==0 || strlen(getconf_str(CNF_MAILTO)) == 0)) { g_printf(_("\nWARNING:No mail address configured in amanda.conf.\n")); g_printf(_("To receive dump results by email configure the " "\"mailto\" parameter in amanda.conf\n")); if(alwaysmail) g_printf(_("When using -a option please specify -Maddress also\n\n")); else g_printf(_("Use -Maddress instead of -m\n\n")); exit(1); } if(mailout && !mailto) { if(getconf_seen(CNF_MAILTO) && strlen(getconf_str(CNF_MAILTO)) > 0) { if(!validate_mailto(getconf_str(CNF_MAILTO))){ g_printf(_("\nMail address in amanda.conf has invalid characters")); g_printf(_("\nNo email will be sent\n")); mailout = 0; } } else { g_printf(_("\nNo mail address configured in amanda.conf\n")); if(alwaysmail) g_printf(_("When using -a option please specify -Maddress also\n\n")); else g_printf(_("Use -Maddress instead of -m\n\n")); exit(1); } } conf_ctimeout = (time_t)getconf_int(CNF_CTIMEOUT); conf_diskfile = config_dir_relative(getconf_str(CNF_DISKFILE)); if(read_diskfile(conf_diskfile, &origq) < 0) { error(_("could not load disklist %s. Make sure it exists and has correct permissions"), conf_diskfile); /*NOTREACHED*/ } errstr = match_disklist(&origq, argc-1, argv+1); if (errstr) { g_printf(_("%s"),errstr); amfree(errstr); } amfree(conf_diskfile); /* * 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) { error(_("amanda.conf has dump user configured to \"%s\", but that user does not exist."), dumpuser); /*NOTREACHED*/ } uid_dumpuser = pw->pw_uid; if ((pw = getpwuid(uid_me)) == NULL) { error(_("cannot get username for running user, uid %ld is not in your user database."), (long)uid_me); /*NOTREACHED*/ }#ifdef CHECK_USERID if (uid_me != uid_dumpuser) { error(_("running as user \"%s\" instead of \"%s\".\n" "Change user to \"%s\" or change dump user to \"%s\" in amanda.conf"), pw->pw_name, dumpuser, dumpuser, pw->pw_name); /*NOTREACHED*/ }#endif 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 = vstralloc(AMANDA_TMPDIR, "/amcheck.temp.", pid_str, NULL); if((tempfd = open(tempfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) { error(_("could not open temporary amcheck output file %s: %s. Check permissions"), tempfname, strerror(errno)); /*NOTREACHED*/ } unlink(tempfname); /* so it goes away on close */ amfree(tempfname); } if(mailout) { /* the main fd is a file too */ mainfname = vstralloc(AMANDA_TMPDIR, "/amcheck.main.", pid_str, NULL); if((mainfd = open(mainfname, O_RDWR|O_CREAT|O_TRUNC, 0600)) == -1) { error(_("could not open amcheck server output file %s: %s. Check permissions"), mainfname, strerror(errno)); /*NOTREACHED*/ } unlink(mainfname); /* so it goes away on close */ amfree(mainfname); } else /* just use stdout */ mainfd = 1; /* 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 { char *wait_msg = NULL; wait_msg = vstrallocf(_("parent: reaped bogus pid %ld\n"), (long)pid); if (fullwrite(mainfd, wait_msg, strlen(wait_msg)) < 0) { error(_("write main file: %s"), strerror(errno)); /*NOTREACHED*/ } amfree(wait_msg); } } /* copy temp output to main output and write tagline */ if(do_clientchk && (do_localchk || do_tapechk)) { if(lseek(tempfd, (off_t)0, 0) == (off_t)-1) { error(_("seek temp file: %s"), strerror(errno)); /*NOTREACHED*/ } while((size = fullread(tempfd, buffer, SIZEOF(buffer))) > 0) { if (fullwrite(mainfd, buffer, (size_t)size) < 0) { error(_("write main file: %s"), strerror(errno)); /*NOTREACHED*/ } } if(size < 0) { error(_("read temp file: %s"), strerror(errno)); /*NOTREACHED*/ } aclose(tempfd); } version_string = vstrallocf(_("\n(brought to you by Amanda %s)\n"), version()); if (fullwrite(mainfd, version_string, strlen(version_string)) < 0) { error(_("write main file: %s"), strerror(errno)); /*NOTREACHED*/ } amfree(version_string); amfree(our_feature_string); am_release_feature_set(our_features); our_features = NULL; /* send mail if requested, but only if there were problems */#ifdef MAILER#define MAILTO_LIMIT 10 if((server_probs || client_probs || alwaysmail) && mailout) { int mailfd; int nullfd; int errfd; FILE *ferr; char *subject; char **a; amwait_t retstat; ssize_t r; ssize_t w; char *err = NULL; char *extra_info = NULL; char *line = NULL; int rc; fflush(stdout); if(lseek(mainfd, (off_t)0, SEEK_SET) == (off_t)-1) { error(_("lseek main file: %s"), strerror(errno)); /*NOTREACHED*/ } if(alwaysmail && !(server_probs || client_probs)) { subject = vstrallocf(_("%s AMCHECK REPORT: NO PROBLEMS FOUND"), getconf_str(CNF_ORG)); } else { subject = vstrallocf( _("%s AMANDA PROBLEM: FIX BEFORE RUN, IF POSSIBLE"), getconf_str(CNF_ORG)); } /* * Variable arg lists are hard to deal with when we do not know * ourself how many args are involved. Split the address list * and hope there are not more than 9 entries. * * Remember that split() returns the original input string in * argv[0], so we have to skip over that. */ a = (char **) alloc((MAILTO_LIMIT + 1) * SIZEOF(char *)); memset(a, 0, (MAILTO_LIMIT + 1) * SIZEOF(char *)); if(mailto) { a[1] = mailto; a[2] = NULL; } else { r = (ssize_t)split(getconf_str(CNF_MAILTO), a, MAILTO_LIMIT, " "); a[r + 1] = NULL; } if((nullfd = open("/dev/null", O_RDWR)) < 0) { error("nullfd: /dev/null: %s", strerror(errno)); /*NOTREACHED*/ } pipespawn(MAILER, STDIN_PIPE | STDERR_PIPE, &mailfd, &nullfd, &errfd, MAILER, "-s", subject, a[1], a[2], a[3], a[4], a[5], a[6], a[7], a[8], a[9], NULL); amfree(subject); /* * 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 = fullread(mainfd, buffer, SIZEOF(buffer))) > 0) { if((w = fullwrite(mailfd, buffer, (size_t)r)) != (ssize_t)r) { if(w < 0 && errno == EPIPE) { strappend(extra_info, _("EPIPE writing to mail process\n")); break; } else if(w < 0) { error(_("mailfd write: %s"), strerror(errno)); /*NOTREACHED*/ } else { error(_("mailfd write: wrote %zd instead of %zd"), w, r); /*NOTREACHED*/ } } } aclose(mailfd); ferr = fdopen(errfd, "r"); if (!ferr) { error(_("Can't fdopen: %s"), strerror(errno)); /*NOTREACHED*/ } for(; (line = agets(ferr)) != NULL; free(line)) { if (line[0] == '\0')
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -