#include "restore.h"
#include <signal.h>
#include <byteorder.h>
#include <priv_utils.h>
#include <euc.h>
#include <getwidth.h>
#include <sys/mtio.h>
eucwidth_t wp;
int bflag = 0, dflag = 0, vflag = 0, yflag = 0;
int hflag = 1, mflag = 1, paginating = 0, offline = 0, autoload = 0;
int autoload_tries;
int autoload_period;
int cvtflag = 0;
char command = '\0';
long dumpnum = 1;
int volno = 0;
uint_t ntrec;
uint_t saved_ntrec;
ssize_t tape_rec_size = 0;
size_t newtapebuf_size = 0;
char *progname;
char *dumpmap;
char *clrimap;
char *c_label;
ino_t maxino;
time_t dumptime;
time_t dumpdate;
FILE *terminal;
char *tmpdir;
char *pager_catenated;
char **pager_vector;
int pager_len;
int inattrspace = 0;
int savepwd;
int32_t tp_bsize = TP_BSIZE_MIN;
struct byteorder_ctx *byteorder;
static void set_tmpdir(void);
int
main(int argc, char *argv[])
{
static struct arglist alist = { 0, 0, 0, 0, 0 };
int count;
char *cp;
char *fname;
ino_t ino;
char *inputdev;
char *archivefile = 0;
char *symtbl = RESTORESYMTABLE;
char name[MAXPATHLEN];
int fflag = 0;
struct sigaction sa, osa;
int multiplier;
char units;
if ((progname = strrchr(argv[0], '/')) != NULL)
progname++;
else
progname = argv[0];
if (strcmp("hsmrestore", progname) == 0) {
(void) fprintf(stderr,
gettext("hsmrestore emulation is no longer supported.\n"));
done(1);
}
(void) __init_suid_priv(0, PRIV_NET_PRIVADDR, (char *)NULL);
inputdev = DEFTAPE;
(void) setlocale(LC_CTYPE, "");
(void) setlocale(LC_NUMERIC, "");
(void) setlocale(LC_TIME, "");
(void) setlocale(LC_MONETARY, "");
(void) setlocale(LC_MESSAGES, "");
#if !defined(TEXT_DOMAIN)
#define TEXT_DOMAIN "SYS_TEST"
#endif
(void) textdomain(TEXT_DOMAIN);
getwidth(&wp);
if ((byteorder = byteorder_create()) == NULL) {
(void) fprintf(stderr,
gettext("Cannot create byteorder context\n"));
done(1);
}
if ((savepwd = open(".", O_RDONLY)) < 0) {
(void) fprintf(stderr,
gettext("Cannot save current directory context\n"));
done(1);
}
set_tmpdir();
autoload_period = 12;
autoload_tries = 12;
sa.sa_handler = onintr;
sa.sa_flags = SA_RESTART;
(void) sigemptyset(&sa.sa_mask);
(void) sigaction(SIGINT, &sa, &osa);
if (osa.sa_handler == SIG_IGN)
(void) sigaction(SIGINT, &osa, (struct sigaction *)0);
(void) sigaction(SIGTERM, &sa, &osa);
if (osa.sa_handler == SIG_IGN)
(void) sigaction(SIGTERM, &osa, (struct sigaction *)0);
if (argc < 2) {
usage:
(void) fprintf(stderr, gettext("Usage:\n\
\t%s tabcdfhsvyLloT [file file ...]\n\
\t%s xabcdfhmsvyLloT [file file ...]\n\
\t%s iabcdfhmsvyLloT\n\
\t%s rabcdfsvyLloT\n\
\t%s RabcdfsvyLloT\n\n\
a requires an archive file name\n\
b requires a blocking factor\n\
f requires a dump file\n\
s requires a file number\n\
L requires a tape label\n\
If set, the envar TMPDIR selects where temporary files are kept\n"),
progname, progname, progname, progname, progname);
done(1);
}
argv++;
argc -= 2;
command = '\0';
c_label = (char *)NULL;
for (cp = *argv++; *cp; cp++) {
switch (*cp) {
case 'T':
if (argc < 1) {
(void) fprintf(stderr, gettext(
"Missing autoload timeout period\n"));
done(1);
}
count = atoi(*argv);
if (count < 1) {
(void) fprintf(stderr, gettext(
"Unreasonable autoload timeout period `%s'\n"),
*argv);
done(1);
}
units = *(*argv + strlen(*argv) - 1);
switch (units) {
case 's':
multiplier = 1;
break;
case 'h':
multiplier = 3600;
break;
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
case 'm':
multiplier = 60;
break;
default:
(void) fprintf(stderr, gettext(
"Unknown timeout units indicator `%c'\n"),
units);
done(1);
}
autoload_tries = 1 +
((count * multiplier) / autoload_period);
argv++;
argc--;
break;
case 'l':
autoload++;
break;
case 'o':
offline++;
break;
case '-':
break;
case 'a':
if (argc < 1) {
(void) fprintf(stderr,
gettext("missing archive file name\n"));
done(1);
}
archivefile = *argv++;
if (*archivefile == '\0') {
(void) fprintf(stderr,
gettext("empty archive file name\n"));
done(1);
}
argc--;
break;
case 'c':
cvtflag++;
break;
case 'd':
dflag++;
break;
case 'D':
break;
case 'h':
hflag = 0;
break;
case 'm':
mflag = 0;
break;
case 'v':
vflag++;
break;
case 'y':
yflag++;
break;
case 'f':
if (argc < 1) {
(void) fprintf(stderr,
gettext("missing device specifier\n"));
done(1);
}
inputdev = *argv++;
if (*inputdev == '\0') {
(void) fprintf(stderr,
gettext("empty device specifier\n"));
done(1);
}
fflag++;
argc--;
break;
case 'b':
bflag++;
if (argc < 1) {
(void) fprintf(stderr,
gettext("missing block size\n"));
done(1);
}
saved_ntrec = ntrec = atoi(*argv++);
if (ntrec == 0 || (ntrec&1)) {
(void) fprintf(stderr, gettext(
"Block size must be a positive, even integer\n"));
done(1);
}
ntrec /= (tp_bsize/DEV_BSIZE);
argc--;
break;
case 's':
if (argc < 1) {
(void) fprintf(stderr,
gettext("missing dump number\n"));
done(1);
}
dumpnum = atoi(*argv++);
if (dumpnum <= 0) {
(void) fprintf(stderr, gettext(
"Dump number must be a positive integer\n"));
done(1);
}
argc--;
break;
case 't':
case 'R':
case 'r':
case 'x':
case 'i':
if (command != '\0') {
(void) fprintf(stderr, gettext(
"%c and %c are mutually exclusive\n"),
(uchar_t)*cp, (uchar_t)command);
goto usage;
}
command = *cp;
break;
case 'L':
if (argc < 1 || **argv == '\0') {
(void) fprintf(stderr,
gettext("Missing tape label name\n"));
done(1);
}
c_label = *argv++;
if (strlen(c_label) > (sizeof (spcl.c_label) - 1)) {
c_label[sizeof (spcl.c_label) - 1] = '\0';
(void) fprintf(stderr, gettext(
"Truncating label to maximum supported length: `%s'\n"),
c_label);
}
argc--;
break;
default:
(void) fprintf(stderr,
gettext("Bad key character %c\n"), (uchar_t)*cp);
goto usage;
}
}
if (command == '\0') {
(void) fprintf(stderr,
gettext("must specify i, t, r, R, or x\n"));
goto usage;
}
setinput(inputdev, archivefile);
if (argc == 0) {
argc = 1;
*--argv = mflag ? "." : "2";
}
switch (command) {
case 'i':
setup();
extractdirs(1);
initsymtable((char *)0);
initpagercmd();
runcmdshell();
done(0);
case 'r':
setup();
if (dumptime > 0) {
vprintf(stdout, gettext("Begin incremental restore\n"));
initsymtable(symtbl);
extractdirs(1);
removeoldleaves();
vprintf(stdout, gettext("Calculate node updates.\n"));
strcpy(name, ".");
name[2] = '\0';
treescan(name, ROOTINO, nodeupdates);
attrscan(1, nodeupdates);
findunreflinks();
removeoldnodes();
} else {
vprintf(stdout, gettext("Begin level 0 restore\n"));
initsymtable((char *)0);
extractdirs(1);
vprintf(stdout,
gettext("Calculate extraction list.\n"));
strcpy(name, ".");
name[2] = '\0';
treescan(name, ROOTINO, nodeupdates);
attrscan(1, nodeupdates);
}
createleaves(symtbl);
createlinks();
setdirmodes();
checkrestore();
if (dflag) {
vprintf(stdout,
gettext("Verify the directory structure\n"));
strcpy(name, ".");
name[2] = '\0';
treescan(name, ROOTINO, verifyfile);
}
dumpsymtable(symtbl, (long)1);
done(0);
case 'R':
setupR();
initsymtable(symtbl);
skipmaps();
skipdirs();
createleaves(symtbl);
createlinks();
setdirmodes();
checkrestore();
dumpsymtable(symtbl, (long)1);
done(0);
case 't':
setup();
extractdirs(0);
initsymtable((char *)0);
if (vflag)
printdumpinfo();
while (argc--) {
canon(*argv++, name, sizeof (name));
name[strlen(name)+1] = '\0';
ino = dirlookup(name);
if (ino == 0)
continue;
treescan(name, ino, listfile);
}
done(0);
case 'x':
setup();
extractdirs(1);
initsymtable((char *)0);
while (argc--) {
if (mflag) {
canon(*argv++, name, sizeof (name));
if (expand(name, 0, &alist) == 0) {
ino = dirlookup(name);
if (ino == 0)
continue;
pathcheck(name);
} else {
while ((alist.last - alist.head) > 0) {
fname = alist.head->fname;
ino = dirlookup(fname);
if (ino != 0) {
pathcheck(fname);
treescan(fname, ino,
addfile);
}
freename(fname);
alist.head++;
}
alist.head = (struct afile *)NULL;
continue;
}
} else {
ino = (ino_t)atol(*argv);
if ((*(*argv++) == '-') || ino < ROOTINO) {
(void) fprintf(stderr, gettext(
"bad inode number: %ld\n"),
ino);
done(1);
}
name[0] = '\0';
}
treescan(name, ino, addfile);
attrscan(0, addfile);
}
createfiles();
createlinks();
setdirmodes();
if (dflag)
checkrestore();
done(0);
}
return (0);
}
void
set_tmpdir(void)
{
int fd;
char name[MAXPATHLEN];
tmpdir = getenv("TMPDIR");
if ((tmpdir == (char *)NULL) || (*tmpdir == '\0'))
tmpdir = "/tmp";
if (*tmpdir != '/') {
(void) fprintf(stderr,
gettext("TMPDIR is not an absolute path (`%s').\n"),
tmpdir);
done(1);
}
if (strlen(tmpdir) > (MAXPATHLEN - 31)) {
(void) fprintf(stderr, gettext("TMPDIR too long\n"));
done(1);
}
(void) snprintf(name, sizeof (name), "%s/rstdir.%ld", tmpdir, getpid());
fd = open(name, O_CREAT|O_EXCL|O_RDWR, 0600);
if (fd < 0) {
perror(gettext("Can not create temporary file"));
done(1);
}
(void) close(fd);
if (unlink(name) < 0) {
perror(gettext("Can not delete temporary file"));
done(1);
}
}