⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 amcheck.c

📁 开源备份软件源码 AMANDA, the Advanced Maryland Automatic Network Disk Archiver, is a backup system that a
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * 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 + -