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

1113 lines
24 KiB
C
Executable File

#ident "@(#)dumpadd.c 1.14 93/06/25"
/*
* Copyright (c) 1990,1991,1992 by Sun Microsystems, Inc.
*/
/*
* Add database entries from existing dumps
*/
#include "defs.h"
#include <sys/stat.h>
#include <sys/mkdev.h>
#include <sys/ioctl.h>
#include <sys/mtio.h>
#include <byteorder.h>
static int newvolume, fulltape;
static struct byteorder_ctx *byteorder = NULL;
static daddr_t tapestart;
extern int t_stdio_remote;
#ifdef __STDC__
static void hostprompt(char **);
static void devprompt(int, char **);
static void alloc_tapebuf(int);
static void free_tapebuf(void);
static void open_tape(const char *);
static void close_tape(void);
static int rewind_tape(void);
static void space_tape(void);
static void free_tapedata(void);
static void dumptape(const char *, const char *, int);
static void error_exit(void);
static void nextvol(void);
static void read_header(int, int);
static char *prompt(int);
static void read_data(FILE *);
static void garbage(void);
static void dirdata(struct s_spcl *, FILE *);
static void linkdata(struct s_spcl *, FILE *);
static int addentries(FILE *);
static void taperead(char *);
static int dnodedata(struct s_spcl *, FILE *);
static void dnode_span(FILE *);
static void outputtapes(FILE *);
#else
static void hostprompt();
static void devprompt();
static void alloc_tapebuf();
static void free_tapebuf();
static void open_tape();
static void close_tape();
static int rewind_tape();
static void space_tape();
static void free_tapedata();
static void dumptape();
static void error_exit();
static void nextvol();
static void read_header();
static char *prompt();
static void read_data();
static void garbage();
static void dirdata();
static void linkdata();
static int addentries();
static void taperead();
static int dnodedata();
static void dnode_span();
static void outputtapes();
#endif
/*
* add an entire tape's worth of dumps to the database.
*/
void
#ifdef __STDC__
tapeadd(char *dbhost,
char *dumpdev,
const char *tdir,
int tpbsize)
#else
tapeadd(dbhost, dumpdev, tdir, tpbsize)
char *dbhost;
char *dumpdev;
char *tdir;
int tpbsize;
#endif
{
int num;
char buf[256];
char *yes = gettext("yY");
if (dbhost == NULL) {
hostprompt(&dbhost);
}
devprompt(1, &dumpdev);
alloc_tapebuf(tpbsize);
open_tape(dumpdev);
if (rewind_tape())
exit(1);
fulltape = 1;
num = 1;
/*CONSTCOND*/
while (1) { /* XXX: while dumps on tape */
(void) printf(gettext("File %d:\n"), num);
dumptape(dbhost, tdir, num);
if (newvolume) {
newvolume = 0;
num = 1;
(void) fprintf(stderr, gettext(
"Continue adding dumps from new volume? "));
if (gets(buf) == NULL ||
(buf[0] != yes[0] && buf[0] != yes[1]))
break;
}
space_tape();
num++;
}
close_tape();
free_tapebuf();
}
void
#ifdef __STDC__
dumpadd(char *dbhost,
char *dumpdev,
const char *tdir,
int tpbsize)
#else
dumpadd(dbhost, dumpdev, tdir, tpbsize)
char *dbhost;
char *dumpdev;
char *tdir;
int tpbsize;
#endif
{
if (dbhost == NULL) {
hostprompt(&dbhost);
}
if (dumpdev == NULL) {
devprompt(0, &dumpdev);
}
alloc_tapebuf(tpbsize);
open_tape(dumpdev);
dumptape(dbhost, tdir, -1);
space_tape();
close_tape();
free_tapebuf();
}
static void
hostprompt(host)
char **host;
{
static char dbhost[256];
for (;;) {
(void) fputs(gettext(
"Name of database server where dump data will be added: "),
stderr);
if (gets(dbhost) == NULL)
exit(1);
if (gethostbyname(dbhost))
break;
(void) fprintf(stderr, gettext("Unknown host: `%s'\n"), dbhost);
}
*host = dbhost;
}
static void
devprompt(fulltape, dev)
int fulltape;
char **dev;
{
static char dumpfile[256];
struct stat stbuf;
again:
if (*dev == NULL) {
(void) fputs(gettext(
"Device from which to read dump: "), stderr);
if (gets(dumpfile) == NULL)
exit(1);
*dev = dumpfile;
}
if (strchr(*dev, ':')) /* t_stdio_remote not set yet! */
return;
else if (fulltape) {
if (stat(*dev, &stbuf) == -1) {
perror(*dev);
*dev = NULL;
goto again;
}
if ((!S_ISBLK(stbuf.st_mode) && !S_ISCHR(stbuf.st_mode)) ||
(minor(stbuf.st_rdev) & MT_NOREWIND) == 0) {
(void) fprintf(stderr, gettext(
"You must specify a no-rewind tape device\n"));
*dev = NULL;
goto again;
}
}
}
/*
* rebuild database entries for a dump. A dump has the following format:
*
* header
* maps
* directory inode
* directory data
* directory data
* .
* .
* directory inode
* directory data
* .
* .
* .
* file inode
* file data
* file inode
* .
* .
* .
*
* We take this data and turn it into a batch_update file as defined
* in "batchfile.h". This file is then processed by the database
* server...
*/
/*
* XXX: make sure everything gets re-initialized for multiple
* invocations.
*/
static struct dheader dumphead;
static struct tape_data {
struct bu_tape bu_tape;
struct tape_data *nxt;
} *tapes, *curtape;
static int dnodecnt, namecnt, tapecnt;
static int firstinode = -1;
static u_long volnum;
/*
* stream pointer to the dump or tape file to be
* added to the database. Reading an Exabyte
* drive using 5.0 stdio package fail because
* the read gets done using sub-record size reads.
* All operations on tfp must be done using
* stdio routines prepended with t_ found in the
* file t_stdio.c. This package is a simple
* buffering package that maintains semantics with
* stdio, but is by no means complete.
*/
static FILE *tfp;
FILE *t_fopen(const char *, const char *);
int t_setvbuf(FILE *, char *, int, size_t);
int t_fclose(FILE *);
int t_fileno(FILE *);
void t_rewind(FILE *);
int t_feof(FILE *);
size_t t_fread(void *, size_t, size_t, FILE *);
static char *prompt();
static char *tapedev;
static char *outdir = "/tmp";
static char *tfilename = "taperebuild";
static char outfile[MAXPATHLEN];
/*
* buffer that we read into. This is allocated by alloc_tapebuf().
* User may over-ride the 63KB default size.
* Note that 1/4" cartridge tapes may not behave correctly
* when a read size of > 63K is specified.
*/
#define DEFBSIZE 63
static int bufsize;
static char *mybuf;
static int volchange;
#define MNTPOINT 1
#define TAPELABEL 2
static void
alloc_tapebuf(bsiz)
int bsiz;
{
if (!bsiz)
bsiz = DEFBSIZE;
bufsize = bsiz*TP_BSIZE;
mybuf = malloc((unsigned)bufsize);
if (mybuf == NULL) {
(void) fprintf(stderr,
gettext("%s: out of memory\n"), "alloc_tapebuf");
exit(1);
}
if ((byteorder == NULL) &&
((byteorder = byteorder_create()) == NULL)) {
(void) fprintf(stderr,
gettext("Cannot allocate byte order status\n"));
exit(1);
}
}
static void
#ifdef __STDC__
free_tapebuf(void)
#else
free_tapebuf()
#endif
{
free(mybuf);
byteorder_destroy(byteorder);
byteorder = NULL;
}
static void
#ifdef __STDC__
open_tape(const char *dev)
#else
open_tape(dev)
char *dev;
#endif
{
if ((tfp = t_fopen(dev, "r")) == NULL) {
(void) fprintf(stderr, gettext("cannot open `%s'\n"), dev);
exit(1);
}
tapedev = (char *)dev;
if (t_setvbuf(tfp, mybuf, _IOFBF, bufsize) != 0) {
(void) fprintf(stderr, gettext("cannot setvbuf `%s'\n"), dev);
exit(1);
}
}
static void
#ifdef __STDC__
close_tape(void)
#else
close_tape()
#endif
{
if (fulltape)
(void) rewind_tape();
(void) t_fclose(tfp);
}
static int
#ifdef __STDC__
rewind_tape(void)
#else
rewind_tape()
#endif
{
struct mtop tcom;
if (t_stdio_remote) {
if (rmtioctl(MTREW, 1) != 1) {
perror("rewind");
return (1);
}
} else {
tcom.mt_op = MTREW;
tcom.mt_count = 0;
if (ioctl(t_fileno(tfp), (int)MTIOCTOP, (char *)&tcom) < 0) {
perror("rewind");
return (1);
}
}
return (0);
}
static void
#ifdef __STDC__
space_tape(void)
#else
space_tape()
#endif
{
struct mtop tcom;
if (t_stdio_remote) {
if (rmtioctl(MTFSF, 1) != 1) {
perror("ioctl MTFSF");
exit(1);
}
} else {
tcom.mt_op = MTFSF;
tcom.mt_count = 1;
if (ioctl(t_fileno(tfp), (int)MTIOCTOP, (char *)&tcom) < 0) {
perror("ioctl MTFSF");
exit(1);
}
}
t_rewind(tfp);
}
static void
#ifdef __STDC__
free_tapedata(void)
#else
free_tapedata()
#endif
{
register struct tape_data *t, *tt;
t = tapes;
while (t) {
tt = t;
t = t->nxt;
free((char *)tt);
}
tapes = curtape = (struct tape_data *)0;
}
static void
#ifdef __STDC__
dumptape(const char *dbhost,
const char *tdir,
int filenum)
#else
dumptape(dbhost, tdir, filenum)
char *dbhost;
char *tdir;
int filenum;
#endif
{
FILE *outfp;
struct bu_header buh;
int tapepos = 1;
int handle;
char response[256];
unsigned sleeptime;
int doprompts = 0;
volchange = dnodecnt = namecnt = tapecnt = volnum = 0;
firstinode = -1;
free_tapedata();
if (filenum == -1) {
doprompts = 1;
(void) fprintf(stderr, gettext(
"Defaulting to file 1 of the tape. OK? (yes or no) "));
if (gets(response) == NULL)
exit(1);
else if (strcmp(response, gettext("yes"))) {
for (;;) {
(void) fprintf(stderr, gettext(
"Enter desired file number: "));
if (gets(response) == NULL)
exit(1);
if (sscanf(response, "%d", &tapepos) != 1)
exit(1);
if (tapepos >= 1 && tapepos < 500) {
(void) fprintf(stderr, gettext(
"Using file number %d\n"),
tapepos);
break;
} else {
(void) fprintf(stderr, gettext(
"ridiculous file number %d\n"),
tapepos);
}
}
}
} else {
tapepos = filenum;
}
if (tdir)
outdir = (char *)tdir;
(void) sprintf(outfile, "%s/%s.%lu",
outdir, tfilename, (u_long)getpid());
if ((outfp = fopen(outfile, "w")) == NULL) {
(void) fprintf(stderr, gettext("cannot open `%s'\n"), outfile);
exit(1);
}
read_header(tapepos, doprompts);
buh.name_cnt = 0;
buh.dnode_cnt = 0;
buh.tape_cnt = 0;
/*
* write dummy batchfile header - we update this later when
* we know what the values should be.
*/
if (fwrite((char *)&buh, sizeof (struct bu_header), 1, outfp) != 1) {
(void) fprintf(stderr,
gettext("cannot write update file header\n"));
(void) fclose(outfp);
(void) unlink(outfile);
exit(1);
}
/* write dump header */
if (fwrite((char *)&dumphead, sizeof (struct dheader), 1, outfp) != 1) {
(void) fprintf(stderr, gettext("cannot write dump header\n"));
(void) fclose(outfp);
(void) unlink(outfile);
exit(1);
}
/* write filename and dnode data */
read_data(outfp);
/* write tape data */
outputtapes(outfp);
/* write updated batchfile header at the end */
buh.name_cnt = namecnt;
buh.dnode_cnt = dnodecnt;
buh.tape_cnt = tapecnt;
if (namecnt == 0 || dnodecnt == 0 || tapecnt == 0) {
#if 0
(void) fprintf(stderr, gettext("no data read?\n"));
(void) fclose(outfp);
(void) unlink(outfile);
exit(1);
#else
(void) fprintf(stderr, gettext("empty dump\n"));
#endif
}
if (fwrite((char *)&buh, sizeof (struct bu_header), 1, outfp) != 1) {
(void) fprintf(stderr,
gettext("cannot write update file header\n"));
(void) fclose(outfp);
(void) unlink(outfile);
exit(1);
}
/* and rewrite the one at the beginning */
rewind(outfp);
if (fwrite((char *)&buh, sizeof (struct bu_header), 1, outfp) != 1) {
(void) fprintf(stderr,
gettext("cannot write update file header\n"));
exit(1);
}
(void) fclose(outfp);
/*
* send update file to database.
*/
sleeptime = 0;
/*CONSTCOND*/
while (1) {
if (sleeptime) {
(void) sleep(sleeptime);
(void) fprintf(stderr,
gettext("retrying database update at `%s'\n"),
dbhost);
}
if ((handle = update_start(dbhost, dumphead.dh_host)) == -1) {
(void) fprintf(stderr, gettext(
"cannot start update at database server `%s'\n"),
dbhost);
} else if (update_data(handle, outfile)) {
(void) fprintf(stderr, gettext(
"cannot send update file to database server `%s'\n"),
dbhost);
} else if (update_process(handle)) {
(void) fprintf(stderr, gettext(
"database server `%s' cannot process update\n"),
dbhost);
} else {
(void) fprintf(stderr, gettext(
"update file transmitted to database server `%s'\n"),
dbhost);
break;
}
sleeptime += 5;
}
(void) unlink(outfile);
}
static void
#ifdef __STDC__
error_exit(void)
#else
error_exit()
#endif
{
(void) unlink(outfile);
close_tape();
exit(1);
}
static void
#ifdef __STDC__
nextvol(void)
#else
nextvol()
#endif
{
char buffer[TP_BSIZE];
char response[100];
struct s_spcl *p;
struct tape_data *tp;
char *pp;
close_tape();
(void) fprintf(stderr, gettext("Mount next volume (yes or no): "));
if (gets(response) == NULL)
error_exit();
else if (strcmp(response, gettext("yes")))
error_exit();
open_tape(tapedev);
if (t_fread(buffer, TP_BSIZE, 1, tfp) != 1) {
(void) fprintf(stderr,
gettext("%s: cannot read header\n"), "nextvol");
error_exit();
}
/*LINTED [buffer properly aligned]*/
p = (struct s_spcl *)buffer;
if ((normspcl(byteorder, p, (int *) p, NFS_MAGIC) != 0) ||
(p->c_type != TS_TAPE)) {
(void) fprintf(stderr,
gettext("%s: not in dump format!\n"), "nextvol");
error_exit();
}
volnum++;
if (p->c_volume != volnum) {
(void) fprintf(stderr, gettext(
"expected volume %lu, got %lu\n"), volnum, p->c_volume);
error_exit();
}
if (p->c_date != dumphead.dh_time) {
(void) fprintf(stderr, gettext("first volume had dumpdate %s"),
lctime(&dumphead.dh_time));
(void) fprintf(stderr, gettext("this volume has dumpdate %s"),
lctime(&p->c_date));
error_exit();
}
tp = (struct tape_data *)malloc(sizeof (struct tape_data));
if (tp == (struct tape_data *)0) {
(void) fprintf(stderr,
gettext("%s: out of memory\n"), "nextvol");
error_exit();
}
tapestart = p->c_tapea;
tp->nxt = (struct tape_data *)0;
tp->bu_tape.first_inode = tp->bu_tape.last_inode = 0;
tp->bu_tape.filenum = 1; /* XXX */
curtape->nxt = tp;
if (strcmp(p->c_label, "none") == 0) {
pp = prompt(TAPELABEL);
if (pp)
(void) bcopy(pp, tp->bu_tape.label, LBLSIZE);
else
(void) bcopy(p->c_label, tp->bu_tape.label, LBLSIZE);
} else {
(void) bcopy(p->c_label, tp->bu_tape.label, LBLSIZE);
}
tapecnt++;
curtape = tp;
volchange = 1;
newvolume = 1;
}
static void
read_header(tapepos, doprompt)
int tapepos;
int doprompt;
{
char buffer[TP_BSIZE];
struct s_spcl *p;
struct hostent *hp;
char *tp;
if (t_fread(buffer, TP_BSIZE, 1, tfp) != 1) {
if (t_feof(tfp)) {
(void) fprintf(stderr,
gettext("no more dumps on this media\n"));
} else {
(void) fprintf(stderr,
gettext("cannot read dump header\n"));
}
error_exit();
}
/*LINTED [buffer properly aligned]*/
p = (struct s_spcl *)buffer;
if ((normspcl(byteorder, p, (int *) p, NFS_MAGIC) != 0) ||
(p->c_type != TS_TAPE)) {
(void) fprintf(stderr,
gettext("%s: not in dump format!\n"), "read_header");
error_exit();
}
if (p->c_volume != 1) {
(void) fprintf(stderr, gettext(
"%s: not first volume of dump\n"), "read_header");
error_exit();
}
volnum = p->c_volume;
(void) strcpy(dumphead.dh_host, p->c_host);
if ((hp = gethostbyname(p->c_host)) == NULL) {
(void) fprintf(stderr,
gettext("cannot get host `%s'\n"), p->c_host);
error_exit();
}
dumphead.dh_netid = **(u_long **)(hp->h_addr_list);
(void) strcpy(dumphead.dh_dev, p->c_dev);
dumphead.dh_time = p->c_date;
dumphead.dh_prvdumptime = p->c_ddate;
dumphead.dh_level = p->c_level;
dumphead.dh_flags = 0;
if (p->c_flags & DR_REDUMP)
dumphead.dh_flags |= DH_ACTIVE;
if (p->c_flags & DR_TRUEINC)
dumphead.dh_flags |= DH_TRUEINC;
if (strstr(p->c_filesys, "a partial"))
dumphead.dh_flags |= DH_PARTIAL;
dumphead.dh_position = tapepos;
dumphead.dh_ntapes = 1;
(void) bcopy(p->c_label, dumphead.dh_label[0], LBLSIZE);
if (strstr(p->c_filesys, "file system")) {
(void) strcpy(dumphead.dh_mnt, "/");
} else {
(void) strcpy(dumphead.dh_mnt, p->c_filesys);
}
if (doprompt || (strcmp(p->c_label, "none") == 0)) {
tp = prompt(MNTPOINT);
if (tp)
(void) strcpy(dumphead.dh_mnt, tp);
else
(void) strcpy(dumphead.dh_mnt, "/");
}
/*
* first tape record
*/
tapes = (struct tape_data *)malloc(sizeof (struct tape_data));
if (tapes == (struct tape_data *)0) {
(void) fprintf(stderr,
gettext("%s: out of memory\n"), "read_header");
error_exit();
}
tapes->nxt = (struct tape_data *)0;
tapes->bu_tape.first_inode = tapes->bu_tape.last_inode = 0;
tapes->bu_tape.filenum = tapepos;
if (strcmp(p->c_label, "none") == 0) {
tp = prompt(TAPELABEL);
if (tp)
(void) bcopy(tp, tapes->bu_tape.label, LBLSIZE);
else
(void) bcopy(p->c_label, tapes->bu_tape.label, LBLSIZE);
} else {
(void) bcopy(p->c_label, tapes->bu_tape.label, LBLSIZE);
}
tapecnt = 1;
curtape = tapes;
(void) printf(gettext("level %lu dump of %s:%s on %s"),
dumphead.dh_level,
dumphead.dh_host,
dumphead.dh_mnt,
lctime(&dumphead.dh_time));
}
static char *
prompt(msg)
int msg;
{
static char buffer[256];
for (;;) {
switch (msg) {
case MNTPOINT:
(void) fprintf(stderr, gettext(
"Specify the `real' mount point of this\n\
\tfilesystem -- no symlinks! (default `%s'): "),
dumphead.dh_mnt);
break;
case TAPELABEL:
(void) bzero(buffer, LBLSIZE);
(void) fprintf(stderr, gettext(
"Specify tape label for tape mount prompts: "));
break;
}
if (gets(buffer) == NULL) {
exit(1);
} else if (buffer[0] == '\0') {
if (msg == MNTPOINT)
return (dumphead.dh_mnt);
} else if (msg == MNTPOINT && buffer[0] != '/') {
(void) fprintf(stderr, gettext(
"mount point must begin with '/'\n\n"));
} else {
return (buffer);
}
}
}
static void
read_data(fp)
FILE *fp;
{
char buffer[TP_BSIZE];
struct s_spcl *p;
mode_t mode;
int doingdir;
register int i;
doingdir = 0;
/*LINTED [buffer properly aligned]*/
p = (struct s_spcl *)buffer;
p->c_type = TS_BITS; /* anything but end */
while (p->c_type != TS_END) {
int skipping = 0;
taperead(buffer);
if (normspcl(byteorder, p, (int *) p, NFS_MAGIC) != 0) {
if (! skipping)
(void) fprintf(stderr,
gettext("Dump format error: Attempting to resync: skipping..."));
(void) fflush(stderr);
skipping = 1;
continue;
} else if (skipping)
(void) fprintf(stderr, gettext(" done.\n"));
skipping = 0;
switch (p->c_type) {
case TS_INODE:
volchange = 0;
if (firstinode == -1) {
firstinode = p->c_inumber;
curtape->bu_tape.first_inode =
firstinode;
}
curtape->bu_tape.last_inode = p->c_inumber;
doingdir = 0;
mode = p->c_dinode.di_mode;
if (S_ISDIR(mode)) {
doingdir = 1;
dirdata(p, fp);
} else if (S_ISLNK(mode)) {
linkdata(p, fp);
} else {
(void) dnodedata(p, fp);
for (i = 0; i < p->c_count; i++)
if (p->c_addr[i])
garbage();
if (volchange)
dnode_span(fp);
}
break;
case TS_ADDR:
volchange = 0;
for (i = 0; i < p->c_count; i++) {
if (p->c_addr[i]) {
if (doingdir)
(void) addentries(fp);
else
garbage();
}
}
if (volchange) {
curtape->bu_tape.first_inode =
p->c_inumber;
dnode_span(fp);
}
curtape->bu_tape.last_inode = p->c_inumber;
break;
case TS_BITS:
case TS_CLRI:
doingdir = 0;
for (i = 0; i < p->c_count; i++)
/*
* XXX: does c_addr map these??
*/
garbage();
break;
case TS_END:
doingdir = 0;
break;
default:
(void) fprintf(stderr,
gettext("unknown record type %ld\n"),
p->c_type);
break;
}
}
}
static void
#ifdef __STDC__
garbage(void)
#else
garbage()
#endif
{
char buffer[TP_BSIZE];
taperead(buffer);
}
static void
dirdata(p, fp)
struct s_spcl *p; /* already passed through normspcl() */
FILE *fp;
{
struct bu_name bun;
register int i;
bun.inode = p->c_inumber;
bun.type = DIRECTORY;
bun.namelen = 0;
if (fwrite((char *)&bun, sizeof (struct bu_name), 1, fp) != 1) {
(void) fprintf(stderr,
gettext("%s: cannot write directory\n"), "dirdata");
error_exit();
}
(void) dnodedata(p, fp);
namecnt++;
for (i = 0; i < p->c_count; i++) {
if (p->c_addr[i])
(void) addentries(fp);
}
}
static int linklen; /* used in linkdata() and dnodedata() */
void
linkdata(p, fp)
struct s_spcl *p; /* already passed through normspcl() */
FILE *fp;
{
char buffer[TP_BSIZE];
register int i;
/*
* A zero-length symlink does not put any link data into the database
* temporary file, for compatibility with the XDR routines and the
* "dump" command. Nor does it bother to read any data from the tape.
*/
if (p->c_dinode.di_size <= 0) {
linklen = 1;
(void) dnodedata(p, fp);
return;
}
if (p->c_addr[0] == 0) {
(void) fprintf(stderr,
gettext("%s: c_addr error?\n"), "linkdata");
}
taperead(buffer);
linklen = strlen(buffer)+1;
(void) dnodedata(p, fp);
if (fwrite((char *)buffer, linklen, 1, fp) != 1) {
(void) fprintf(stderr, gettext("cannot write link data!\n"));
error_exit();
}
for (i = 1; i < p->c_count; i++) {
if (p->c_addr[i])
garbage();
}
}
addentries(fp)
FILE *fp;
{
struct bu_name bun;
struct direct *d, *end;
char buffer[TP_BSIZE];
/*
* next block read from tape should contain directory data
*/
taperead(buffer);
/*LINTED [buffer properly aligned]*/
d = (struct direct *)buffer;
/*LINTED [buffer properly aligned]*/
end = (struct direct *)(buffer+TP_BSIZE);
while (d < end) {
normdirect(byteorder, d);
if (d->d_reclen == 0)
break;
if (d->d_ino && strcmp(d->d_name, ".") &&
strcmp(d->d_name, "..")) {
bun.inode = d->d_ino;
bun.namelen = d->d_namlen+1;
bun.type = 0;
if (fwrite((char *)&bun,
sizeof (struct bu_name), 1, fp) != 1) {
(void) fprintf(stderr,
gettext("%s: %s error\n"),
"addentries", "fwrite1");
return (-1);
}
if (fwrite((char *)d->d_name, (int)bun.namelen,
1, fp) != 1) {
(void) fprintf(stderr,
gettext("%s: %s error\n"),
"addentries", "fwrite2");
return (-1);
}
namecnt++;
}
d = (struct direct *)((unsigned)d+d->d_reclen);
}
return (0);
}
void
taperead(buffer)
char *buffer;
{
if (t_fread(buffer, TP_BSIZE, 1, tfp) != 1) {
if (t_feof(tfp)) {
nextvol();
if (t_fread(buffer, TP_BSIZE, 1, tfp) != 1) {
(void) fprintf(stderr, gettext(
"%s: %s error\n"), "taperead", "fread");
error_exit();
}
firstinode = -1;
} else {
(void) fprintf(stderr, gettext("%s: %s error\n"),
"taperead", "fread");
error_exit();
}
}
}
static struct dnode lastdnode;
dnodedata(p, fp)
struct s_spcl *p; /* already passed through normspcl() */
FILE *fp;
{
struct dinode *ip;
mode_t mode;
ip = &p->c_dinode;
lastdnode.dn_mode = ip->di_mode;
lastdnode.dn_uid = ip->di_uid;
lastdnode.dn_gid = ip->di_gid;
mode = p->c_dinode.di_mode;
if (S_ISBLK(mode) || S_ISCHR(mode)) {
lastdnode.dn_size = p->c_dinode.di_rdev;
} else {
lastdnode.dn_size = p->c_dinode.di_size;
}
lastdnode.dn_atime = ip->di_atime;
lastdnode.dn_mtime = ip->di_mtime;
lastdnode.dn_ctime = ip->di_ctime;
if (S_ISLNK(mode))
lastdnode.dn_symlink = linklen;
else
lastdnode.dn_blocks = ip->di_blocks;
/* XXX: no way to get active file data back from here? */
lastdnode.dn_flags = DN_OFFSET;
lastdnode.dn_vol_position = p->c_tapea - tapestart;
lastdnode.dn_inode = p->c_inumber;
if (fwrite((char *)&lastdnode, sizeof (struct dnode), 1, fp) != 1) {
(void) fprintf(stderr, gettext("%s: %s error\n"),
"dnodedata", "write");
return (-1);
}
dnodecnt++;
return (0);
}
void
dnode_span(fp)
FILE *fp;
{
long curpos;
/*
* re-write the last dnode to indicate that its file
* spans tapes.
*/
lastdnode.dn_flags |= DN_MULTITAPE;
curpos = ftell(fp);
if (fseek(fp, curpos - sizeof (struct dnode), 0) == -1) {
(void) fprintf(stderr, gettext("%s: %s error\n"),
"dnode_span", "fseek");
return;
}
if (fwrite((char *)&lastdnode, sizeof (struct dnode), 1, fp) != 1) {
(void) fprintf(stderr,
gettext("%s: cannot rewrite dnode\n"), "dnode_span");
return;
}
}
void
outputtapes(fp)
FILE *fp;
{
struct tape_data *tp;
int cnt;
for (cnt = 0, tp = tapes; tp; cnt++, tp = tp->nxt) {
if (cnt > tapecnt) {
(void) fprintf(stderr, gettext("tape count error\n"));
exit(1);
}
if (fwrite((char *)&tp->bu_tape,
sizeof (struct bu_tape), 1, fp) != 1) {
(void) fprintf(stderr, gettext("tape write error\n"));
exit(1);
}
}
}