Files
Arquivotheca.Solaris-2.5/cmd/backup/dumpex/dumpex.c
seta75D 7c4988eac0 Init
2021-10-11 19:38:01 -03:00

779 lines
19 KiB
C
Executable File

#ident "@(#)dumpex.c 1.59 94/08/10"
/*
* Copyright (c) 1990,1991,1992 by Sun Microsystems, Inc.
*/
#include "structs.h"
#include "dumpex.h"
#include "tapelib.h"
#include <config.h>
#include <lfile.h>
#include <string.h>
#include <sys/param.h>
#include <time.h>
#include <pwd.h>
#include <signal.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <netdb.h>
#include <rmt.h>
#include <sys/mtio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <sys/systeminfo.h>
#ifdef USG
#define sigvec sigaction
#define sv_mask sa_mask
#define sv_flags sa_flags
#define sv_handler sa_handler
#else
#define SA_RESTART 0
#endif
#ifdef __STDC__
static void clear_tapes(void);
#else
static void clear_tapes();
#endif
static void
usage(void)
{
(void) fprintf(stderr, gettext("Usage: %s [-n] [-N] [-f] \
[-l level] [-o] [-t tapesup] [-r reservetime] [-s] configfile\n"),
progname);
}
int diesoon; /* got a SIGINT */
char dumplevel; /* level for all the dumps, if set */
int outofband; /* out-of-band dump */
struct oob_mail *outofband_mailp; /* info to mail after dumpex -o run */
static int tapesreserved; /* to know if we need to clean 'em up */
/* ARGSUSED */
static void
sighandler(sig, code)
{
struct string_f *remotedelete; /* command to remove remote file */
(void) fprintf(stderr, gettext(
"\n%s: SIG%02.2d: terminating %s abnormally.\n"),
progname, sig, progname);
if (nswitch == 0) {
if (sig == SIGINT) {
(void) fprintf(stderr, gettext(
"%s will terminate when next dump terminates.\n"), progname);
(void) fprintf(stderr, gettext(
"Some output from that dump is already lost.\n"));
diesoon = 1;
return;
}
if (lfilename[0]) {
(void) unlink(lfilename);
if (remote[0] && rlfilename[0]) {
rhp_t rhp;
remotedelete = newstring();
stringapp(remotedelete, "sh -c '( /bin/rm -f ");
stringapp(remotedelete, rlfilename);
stringapp(remotedelete, " ) 2>&1; echo ==$?'");
rhp = remote_setup(remote, cf_rdevuser,
remotedelete->s_string, 1);
if (rhp) {
/*
* It's OK if this fails...
* We currently do not even
* bother looking for the
* exit status.
*/
remote_shutdown(rhp);
}
}
}
if (tapesreserved)
clear_tapes();
log(gettext("Terminated: signal %d\n"), sig);
if (logfile)
(void) fclose(logfile);
}
if (sig == SIGSEGV)
abort();
exit(1);
}
#define SCHEDTAPES_DISPLAY 10 /* when tapesup is 0, use this value */
#define SCHEDTAPES_DEFAULT 20 /* when tapesup is 0, reserve 20 */
char *
fullname(host, fs)
char *host, *fs;
{
static char rc[MAXNAMELEN];
if (index(fs, ':'))
return (fs);
(void) sprintf(rc, "%s:%s", host, fs);
return (rc);
}
main(argc, argv)
int argc;
char *argv[];
{
extern int optind;
extern char *optarg;
struct sigvec sv;
int schedtapes; /* how many tapes to put up */
int reservetime = RESERVETIME; /* how long to reserve them */
int i, c;
struct tapes_f *t;
int tapesfound; /* how many tapes we came up short */
time_t timeval;
struct tm *tm;
char logfilename[MAXPATHLEN];
char mailcommand[MAXCOMMANDLEN];
int nbad; /* number of bad filesystems */
struct devcycle_f *d;
char scratchline[MAXPATHLEN];
FILE *auxfile;
char *p;
int skiptonexttape; /* 1 -> don't append to old tape */
(void) setlocale(LC_ALL, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
progname = strrchr(argv[0], '/');
if (progname == (char *)0)
progname = argv[0];
else
progname++;
setbuf(stderr, (char *) NULL);
if (sysinfo(SI_HOSTNAME, hostname, BCHOSTNAMELEN) == -1)
die(gettext("Cannot determine this host's name\n"));
dumplevel = '\0'; /* dumplevel overrides dc_dumplevels */
schedtapes = -1; /* schedtapes overrides cf_tapesup */
(void) umask(0006);
skiptonexttape = 0;
while ((c = getopt(argc, argv, "ol:t:nfNr:dzs")) != -1) {
switch (c) {
case 'l': /* more tapes up */
if (strcasecmp(optarg, "x") == 0) {
dumplevel = 'x';
} else {
int level = atoi(optarg);
if ((!isdigit(*optarg)) ||
level < 0 || level > 9)
die(gettext(
"Need valid dump level [0-9x] for -l option\n"));
dumplevel = *optarg;
}
break;
case 'o': /* out-of-band dump */
outofband = 1;
skiptonexttape = 1; /* implies -s as well */
break;
case 't': /* more tapes up */
schedtapes = atoi(optarg);
if (schedtapes < 0)
die(gettext(
"Need non-negative number for -t tapes\n"));
break;
case 'n': /* -n -> don't do it */
nswitch = 1;
break;
case 'f': /* -f -> force: retry all bad dumps */
fswitch = 1;
break;
case 'N': /* -N -> don't do it, but briefly */
Nswitch = nswitch = 1;
break;
case 'r': /* reserve time */
reservetime = atoi(optarg);
if (reservetime <= 0)
die(gettext(
"Need positive number for -r reservetime\n"));
break;
case 'd':
debug = 1;
break;
case 'z':
dontoffline = 1;
break;
case 's':
skiptonexttape = 1;
break;
default:
usage();
exit(1);
}
}
argc -= optind;
argv += optind;
if (argc != 1) {
(void) fprintf(stderr, gettext(
"%s: You must supply a configuration file name\n"),
progname);
usage();
exit(1);
}
checkroot(0);
(void) sprintf(confdir, "%s/dumps", gethsmpath(etcdir));
if (chdir(confdir) == -1)
die(gettext("Cannot chdir to %s; run this program as root\n"),
confdir);
/* set up output logfile: */
if (time(&timeval) == -1)
die(gettext("Cannot determine current time\n"));
tm = localtime(&timeval);
(void) sprintf(logfilename, "%s/%s/%02.2d.%02.2d.%02.2d",
gethsmpath(admdir), LOGFILEDIR,
tm->tm_year, tm->tm_mon + 1, tm->tm_mday);
if (nswitch == 0)
logfile = fopen(logfilename, "a+");
if (logfile != NULL)
(void) setvbuf(logfile, NULL, _IOLBF, 0);
/* logfile might be NULL when "logfiledir" does not exist */
#ifdef USG
(void) sigemptyset(&sv.sv_mask);
#else
sv.sv_mask = 0;
#endif
sv.sv_flags = SA_RESTART;
sv.sv_handler = sighandler;
(void) sigvec(SIGHUP, &sv, (struct sigvec *)0);
(void) sigvec(SIGINT, &sv, (struct sigvec *)0);
(void) sigvec(SIGQUIT, &sv, (struct sigvec *)0);
(void) sigvec(SIGBUS, &sv, (struct sigvec *)0);
(void) sigvec(SIGSEGV, &sv, (struct sigvec *)0);
(void) sigvec(SIGTERM, &sv, (struct sigvec *)0);
(void) strcpy(filename, argv[0]);
if (index(filename, '/') != NULL)
die(gettext(
"Names of configuration files must not contain slashes (`%s')\n"),
filename);
openconfig(filename); /* stays open mostly */
readit();
if (outofband) {
cf_longplay = 0; /* force long-play off */
cf_dumplib = ""; /* force database updates off */
}
(void) sprintf(scratchline, gettext(
"This configuration file (%s) is reserved by another executor\n\
or the dump editor. Please try again when the file is released.\n"),
filename);
lockfid = exlock(filename, scratchline);
if ((int)strlen(filename) > MAXPATHLEN - 5) /* 5 = strlen(".new\0") */
die(gettext("Configuration file name too long\n"));
(void) sprintf(newfilename, "%s.new", filename);
display_init(); /* operator console mesgs */
log(gettext("Start: By %s -------------------------------\n"),
p = getpwuid(getuid())->pw_name);
(void) sprintf(scratchline, gettext("[%s/%s] Start %s by %s ------"),
hostname, filename, progname, p);
display(scratchline);
(void) sprintf(auxstatusfile, "%s.lp", filename);
if (nswitch == 0 && (skiptonexttape || cf_longplay == 0))
unlinklpfile();
tl_open(cf_tapelib, filename);
if (schedtapes == -1)
schedtapes = cf_tapesup;
if (schedtapes == 0) /* our default */
schedtapes = SCHEDTAPES_DEFAULT;
reposition = 0;
tapeposofnextfile = 1;
/*
* figure out if we will be incrementing mastercycle before we start
* for real, and if so, go ahead and do it so we don't screw up and
* reserve based on the wrong mastercycle:
*/
for (i = 1; i < MAXDUMPSETS; i++) {
if (cf_tapeset[i] == NULL)
continue;
for (d = cf_tapeset[i]->ts_devlist; d; d = d->dc_next)
if (d->dc_filesys[0] == '-' ||
(fswitch && d->dc_filesys[0] == '*'))
goto dontincr;
}
incrmastercycle();
dontincr:
/* Get `schedtapes' number of free tapes */
for (tapesfound = i = 0; i < schedtapes; i++) {
struct tapedesc_f td;
/*LINTED [alignment ok]*/
t = (struct tapes_f *) checkalloc(sizeof (struct tapes_f));
t->ta_number = -1;
if (cf_longplay && i == 0 && skiptonexttape == 0 &&
(auxfile = fopen(auxstatusfile, "r")) != NULL) {
if (fgets(scratchline, MAXLINELEN, auxfile) == NULL) {
log(gettext(
"%s: Cannot read longplay file (%s) for volume information\n"),
progname, auxstatusfile);
} else {
t->ta_number = atoi(&scratchline[IDCOLUMN]);
t->ta_status = LF_PARTIAL; /* partially full */
tapeposofnextfile =
atoi(&scratchline[POSCOLUMN]);
reposition = 1;
}
(void) fclose(auxfile);
}
if (t->ta_number == -1) {
t->ta_number = tl_findfree(cf_mastercycle, reservetime);
if (t->ta_number < 0)
break;
tapesreserved++;
/* mark tape as new or new/unlabeled */
tl_read(t->ta_number, &td);
if (td.t_status & TL_LABELED)
t->ta_status = LF_NEWLABELD;
else
t->ta_status = LF_UNLABELD;
}
t->ta_mount = i < ncf_dumpdevs ? cf_dumpdevs[i] : (char *) 0;
/* doubly linked insertion: */
t->ta_next = &tapes_head;
t->ta_prev = tapes_head.ta_prev;
tapes_head.ta_prev->ta_next = t;
tapes_head.ta_prev = t;
tapesfound++;
}
for (t = tapes_head.ta_next, i = 0; t != &tapes_head;
t = t->ta_next, i++) {
if (cf_tapesup == 0 && i >= SCHEDTAPES_DISPLAY)
break;
if (t->ta_mount) {
(void) sprintf(scratchline,
gettext("[%s/%s] MOUNT TAPE %s%c%05.5d ON %s"),
hostname,
filename,
cf_tapelib,
LF_LIBSEP,
t->ta_number,
t->ta_mount);
if (!nswitch)
display(scratchline);
if (t->ta_status == LF_UNLABELD) {
(void) strcat(scratchline, " ");
(void) strcat(scratchline,
gettext("[unlabeled]"));
}
(void) puts(scratchline);
log(gettext("%s: %s%c%05.5d on %s\n"),
"Mount",
cf_tapelib, LF_LIBSEP, t->ta_number,
t->ta_mount);
} else {
(void) sprintf(scratchline, gettext(
"[%s/%s] PREPARE TAPE %s%c%05.5d for mounting"),
hostname,
filename,
cf_tapelib,
LF_LIBSEP,
t->ta_number);
if (!nswitch)
display(scratchline);
if (t->ta_status == LF_UNLABELD) {
(void) strcat(scratchline, " ");
(void) strcat(scratchline,
gettext("[unlabeled]"));
}
(void) puts(scratchline);
log("%s: %s%c%05.5d\n",
"Prepare",
cf_tapelib, LF_LIBSEP, t->ta_number);
}
}
if (cf_tapesup != 0 && tapesfound != schedtapes) {
if (schedtapes - tapesfound == 1)
(void) sprintf(scratchline,
gettext("[%s/%s] MIGHT NEED 1 MORE TAPE"),
hostname, filename);
else
(void) sprintf(scratchline,
gettext("[%s/%s] MIGHT NEED %d MORE TAPES"),
hostname, filename, schedtapes - tapesfound);
if (!nswitch)
display(scratchline);
(void) puts(scratchline);
}
dodump();
clear_tapes();
(void) fclose(infid);
if (nswitch == 0) {
(void) unlink(lfilename);
/* inform log and mail people of problem filesystems: */
nbad = 0;
for (d = cf_tapeset[thisdumpset]->ts_devlist; d; d = d->dc_next)
if ((d->dc_filesys[0] == '*') ||
((d->dc_filesys[0] == '-') &&
d->dc_log->s_string[0] != '\0'))
nbad++;
if (nbad) {
/* log them: */
if (nbad == 1)
log(gettext(
"%s: 1 undumped file system:\n"),
"Notdumped#");
else
log(gettext(
"%s: %d undumped file systems:\n"),
"Notdumped#", nbad);
for (d = cf_tapeset[thisdumpset]->ts_devlist;
d; d = d->dc_next)
if (d->dc_filesys[0] == '*')
log("Notdumped: %s\n",
&d->dc_filesys[1]);
/* mail them out: */
if (ncf_notifypeople) {
char *p = mailcommand;
FILE *cmd;
p[0] = '\0';
p = strappend(p, "/usr/bin/mail");
for (i = 0; i < ncf_notifypeople; i++) {
p = strappend(p, " ");
p = strappend(p, cf_notifypeople[i]);
}
cmd = popen(mailcommand, "w");
if (cmd == NULL) {
log(gettext(
"%s: Cannot execute `%s'\n"),
progname, mailcommand);
} else {
(void) fprintf(cmd, gettext(
"%s: DUMP PROBLEMS FROM %s/%s\n\n"),
"Subject", hostname, filename);
/* show the dumps that failed */
for (d =
cf_tapeset[thisdumpset]->ts_devlist;
d; d = d->dc_next)
if ((d->dc_filesys[0] == '*') ||
((d->dc_filesys[0]
== '-') &&
(d->dc_log->s_string[0]))) {
(void) fprintf(cmd,
gettext(
"Dump of %s failed"),
fullname(hostname,
&d->dc_filesys[1]));
if (d->dc_log->s_string[0])
(void) fprintf(cmd,
"; Reason:\n%s\n",
d->dc_log->s_string);
else
fputs("\n", cmd);
}
/* show the dumps that succeeded */
for (d =
cf_tapeset[thisdumpset]->ts_devlist;
!outofband && d; d = d->dc_next)
if (d->dc_filesys[0] == '+') {
(void) fprintf(cmd,
gettext(
"Dump of %s succeeded\n"),
fullname(hostname,
&d->dc_filesys[1]));
}
if ((int)strlen(sectapes->s_string) > 1)
(void) fprintf(cmd, "%s",
sectapes->s_string);
if (outofband)
mail_tape_table(cmd);
(void) fprintf(cmd, ".\n");
(void) pclose(cmd);
}
}
} else {
if (ncf_notifypeople) {
char *p = mailcommand;
FILE *cmd;
p[0] = '\0';
p = strappend(p, "/usr/bin/mail");
for (i = 0; i < ncf_notifypeople; i++) {
p = strappend(p, " ");
p = strappend(p, cf_notifypeople[i]);
}
cmd = popen(mailcommand, "w");
if (cmd == NULL) {
log(gettext(
"%s: Cannot execute `%s'\n"),
progname, mailcommand);
} else {
(void) fprintf(cmd, gettext(
"%s: DUMP OK: %s/%s\n\n"),
"Subject", hostname, filename);
(void) fprintf(cmd, gettext(
"Successful completion %s/%s\n"),
hostname, filename);
if ((int)strlen(sectapes->s_string) > 1)
(void) fprintf(cmd, "%s",
sectapes->s_string);
if (outofband)
mail_tape_table(cmd);
(void) fprintf(cmd, ".\n");
(void) pclose(cmd);
}
}
}
log(gettext("Finish\n"));
if (logfile)
(void) fclose(logfile);
(void) sprintf(scratchline, gettext("[%s/%s] Finished"),
hostname, filename);
display(scratchline);
}
exit(0);
#ifdef lint
return (0);
#endif
}
/*
* 50 characters in the filesystem field.
* 16 characters in the tape label field.
* 6 characters in the file number field.
*/
static char *single_line =
"+--------------------------------------------------+----------------+------+";
static char *double_line =
"+==================================================+================+======+";
static char *fifty_spaces =
" ";
static char *sixteen_spaces =
" ";
static char *six_spaces =
" ";
mail_tape_table(FILE *m)
{
struct oob_mail *tomp, *comp;
char line[MAXLINELEN];
fprintf(m, "\n%s\n|", single_line);
sprintf(line, "%s", gettext("File system"));
tape_table_field(m, line, 50);
sprintf(line, "%s", gettext("Tape"));
tape_table_field(m, line, 16);
sprintf(line, "%s", gettext("File #"));
tape_table_field(m, line, 6);
fprintf(m, "\n%s\n", double_line);
for (tomp = outofband_mailp; tomp; tomp = tomp->om_next) {
fprintf(m, "|");
tape_table_field(m, tomp->om_fs->s_string, 50);
sprintf(line, "%s:%05.5d", cf_tapelib, tomp->om_tapeid);
tape_table_field(m, line, 16);
fprintf(m, "%6d|\n", tomp->om_file);
fprintf(m, "%s\n", single_line);
for (comp = tomp->om_continue; comp; comp = comp->om_next) {
fprintf(m, "|");
sprintf(line, "%s", gettext(" Continued on:"));
tape_table_field(m, line, 50);
sprintf(line, "%s:%05.5d", cf_tapelib, tomp->om_tapeid);
tape_table_field(m, line, 16);
fprintf(m, "%6d|\n", tomp->om_file);
}
}
}
tape_table_field(FILE *m, char *f, int width)
{
int n;
switch (width) {
case 50:
n = strlen(f);
if (n >= 50) {
fprintf(m, "%50.50s|", f);
} else {
fprintf(m, "%s", f);
fprintf(m, "%s|", &fifty_spaces[n]);
}
break;
case 16:
n = strlen(f);
if (n >= 16) {
fprintf(m, "%16.16s|", f);
} else {
fprintf(m, "%s", f);
fprintf(m, "%s|", &sixteen_spaces[n]);
}
break;
case 6:
n = strlen(f);
if (n >= 6) {
fprintf(m, "%6.6s|", f);
} else {
fprintf(m, "%s", f);
fprintf(m, "%s|", &six_spaces[n]);
}
break;
}
}
void
clear_tapes()
{
struct tapes_f *t;
/* re-scratch those tapes we did not use: */
tl_lock();
for (t = tapes_head.ta_next; t != &tapes_head; t = t->ta_next) {
struct tapedesc_f tapedesc;
if (t->ta_status == LF_UNLABELD ||
t->ta_status == LF_NEWLABELD) {
tl_read(t->ta_number, &tapedesc);
tapedesc.t_status =
(tapedesc.t_status & ~TL_STATMASK) | TL_SCRATCH;
tl_write(t->ta_number, &tapedesc);
}
}
tl_unlock();
}
void
unlinklpfile(void)
{
(void) unlink(auxstatusfile);
}
void
fixtape(dev, what)
char *dev;
char *what; /* e.g., offline, rewind */
{
struct mtget mt;
struct mtop iocmd;
char *device;
int t, remote;
if (strcmp(what, "rewind") == 0)
iocmd.mt_op = MTREW;
else if (strcmp(what, "offline") == 0)
iocmd.mt_op = MTOFFL;
else {
log(gettext("%s: Unknown device command: %s\n"),
progname, what);
return;
}
iocmd.mt_count = (daddr_t) 1;
remote = 0;
split(strdup(dev), ":");
switch (nsplitfields) {
case 2: /* name + drive name */
device = splitfields[1];
if (strcmp(hostname, splitfields[0]) != 0) { /* remote host */
struct passwd *pwd;
remote = 1;
if (cf_rdevuser && cf_rdevuser[0] && (geteuid() == 0 ||
((pwd = getpwnam(cf_rdevuser)) != 0 &&
pwd->pw_uid == geteuid()))) {
char userathost[LINEWID+BCHOSTNAMELEN+2];
/*
* Execute remote command as rdevuser
* if running as root or as that user
* by supplying rmthost() user@host
*/
(void) sprintf(userathost, "%s@%s",
cf_rdevuser,
splitfields[0]);
t = rmthost(userathost, 1024);
} else
/* execute as root */
t = rmthost(splitfields[0], 1024);
if (t == 0) {
log(gettext(
"%s: Cannot connect to remote tape host `%s'\n"),
progname, splitfields[0]);
return;
}
if (rmtopen(device, O_RDONLY) < 0) {
log(gettext(
"%s: Cannot open remote device `%s'\n"),
progname, device);
return;
}
} else { /* local host */
t = open(device, O_RDONLY);
if (t < 0) {
log(gettext(
"%s: Cannot open device `%s'\n"),
progname, device);
return;
}
}
break;
case 1: /* local tape drive */
device = splitfields[0];
t = open(device, O_RDONLY);
if (t < 0) {
log(gettext("%s: Cannot open device `%s'\n"),
progname, device);
return;
}
break;
default:
log(gettext("%s: Cannot parse tape drive name `%s'\n"),
progname, dev);
return;
}
if ((remote ? rmtstatus(&mt) : ioctl(t, MTIOCGET, &mt)) >= 0) {
/*
* Only do next operations if we are
* really talking to a tape device
*/
if ((remote ? rmtioctl((int)iocmd.mt_op, 1) :
ioctl(t, MTIOCTOP, &iocmd)) < 0) {
log(gettext("%s: Cannot %s device `%s'\n"),
progname, what, device);
return;
}
if (remote)
rmtclose();
else
(void) close(t);
if (debug)
(void) fprintf(stderr, gettext("%s: DONE: %s %s\n"),
"fixtape", "mt", what);
} else if (debug)
(void) fprintf(stderr, gettext(
"%s: `%s' is not a tape device\n"), "fixtape", device);
}