#include "dump.h"
#include <math.h>
#include <limits.h>
struct inodesc {
ino_t id_inumber;
long id_gen;
struct inodesc *id_next;
};
char *archivefile;
char *tape;
int active;
int doingactive;
int doposition;
int pipeout;
int tapeout;
int to;
struct fs *sblock;
union u_spcl u_spcl;
static struct inodesc ilist;
static struct inodesc *last;
static struct inodesc *freeinodesc;
static struct inodesc **ialloc;
static int nchunks;
#ifdef ENABLE_MMAP
static jmp_buf truncate_buf;
static void (*savebus)();
static int incopy;
static void onsigbus(int);
#endif
#ifdef DEBUG
extern int xflag;
#endif
#ifdef ENABLE_MMAP
static void
onsigbus(int sig)
{
if (!incopy) {
dumpabort();
}
incopy = 0;
longjmp(truncate_buf, 1);
}
#endif
void
allocino(void)
{
ino_t maxino;
size_t nused;
maxino = (unsigned)(sblock->fs_ipg * sblock->fs_ncg);
if (maxino > ULONG_MAX) {
msg(gettext("allocino: filesystem too large\n"));
dumpabort();
}
nused = maxino - sblock->fs_cstotal.cs_nifree;
freeinodesc = (struct inodesc *)xcalloc(nused, sizeof (*freeinodesc));
if (freeinodesc == (struct inodesc *)0) {
msg(gettext("%s: out of memory\n"), "allocino");
dumpabort();
}
last = &ilist;
ialloc =
(struct inodesc **)xmalloc(2*sizeof (*ialloc));
ialloc[0] = freeinodesc;
ialloc[1] = (struct inodesc *)0;
nchunks = 1;
}
void
freeino(void)
{
int i;
if (ialloc == (struct inodesc **)0)
return;
for (i = 0; i < nchunks; i++)
if (ialloc[i] != 0)
free(ialloc[i]);
free(ialloc);
ialloc = (struct inodesc **)0;
}
void
resetino(ino_t ino)
{
last = ilist.id_next;
while (last && last->id_inumber < ino)
last = last->id_next;
}
char *
unrawname(char *cp)
{
char *dp;
extern char *getfullblkname();
dp = getfullblkname(cp);
if (dp == 0)
return (0);
if (*dp == '\0') {
free(dp);
return (0);
}
if (dp == cp)
dp = strdup(cp);
return (dp);
}
int
lf_ismounted(char *devname, char *dirname)
{
struct stat64 st;
char *blockname;
dev_t dev;
int saverr;
if ((blockname = unrawname(devname)) == NULL) {
msg(gettext("Cannot obtain block name from `%s'\n"), devname);
return (-1);
}
if (stat64(blockname, &st) < 0) {
saverr = errno;
msg(gettext("Cannot obtain status of device `%s': %s\n"),
blockname, strerror(saverr));
free(blockname);
return (-1);
}
free(blockname);
dev = st.st_rdev;
if (stat64(dirname, &st) < 0) {
saverr = errno;
msg(gettext("Cannot obtain status of device `%s': %s\n"),
dirname, strerror(saverr));
return (-1);
}
if (dev == st.st_dev)
return (1);
return (0);
}
#ifdef ENABLE_MMAP
#define MINMAPSIZE 1024*1024
#define MAXMAPSIZE 1024*1024*32
static caddr_t mapbase;
static caddr_t mapend;
static size_t mapsize;
caddr_t
mapfile(int fd, off_t offset, off_t bytes, int fetch)
{
volatile char c, *p;
int stride = (int)sysconf(_SC_PAGESIZE);
extern int caught;
caddr_t mapstart;
off_t mapoffset;
int saverr;
mapbase = mapend = (caddr_t)0;
if (bytes == 0)
return ((caddr_t)0);
mapoffset = offset & ~(stride - 1);
mapsize = bytes + (offset - mapoffset);
if (mapsize > MAXMAPSIZE)
mapsize = MAXMAPSIZE;
while ((mapbase = mmap((caddr_t)0, mapsize, PROT_READ,
MAP_SHARED, fd, mapoffset)) == (caddr_t)-1 &&
errno == ENOMEM && mapsize >= MINMAPSIZE) {
mapsize /= 2;
}
if (mapbase == (caddr_t)-1) {
saverr = errno;
msg(gettext("Cannot map file at inode `%lu' into memory: %s\n"),
ino, strerror(saverr));
if (!query(gettext(
"Do you want to attempt to continue? (\"yes\" or \"no\") "))) {
dumpabort();
}
mapbase = (caddr_t)0;
return ((caddr_t)0);
}
(void) madvise(mapbase, mapsize, MADV_SEQUENTIAL);
mapstart = mapbase + (offset - mapoffset);
mapend = mapbase + (mapsize - 1);
if (!fetch)
return (mapstart);
if (setjmp(truncate_buf) == 0) {
savebus = signal(SIGBUS, onsigbus);
incopy = 1;
for (p = mapbase; !caught && p <= mapend; p += stride) {
c = *p;
}
incopy = 0;
}
#ifdef DEBUG
else
msg(gettext(
"FILE TRUNCATED (fault): Interrupting pre-fetch\n"));
#endif
(void) signal(SIGBUS, savebus);
return (mapstart);
}
void
unmapfile(void)
{
if (mapbase) {
(void) msync(mapbase, mapsize, MS_ASYNC|MS_INVALIDATE);
(void) munmap(mapbase, mapsize);
mapbase = (caddr_t)0;
}
}
#endif
void
activepass(void)
{
static int passno = 1;
char *ext, *old;
char buf[3000];
static char defext[] = ".retry";
if (pipeout) {
msg(gettext("Cannot re-dump active files to `%s'\n"), tape);
dumpabort();
}
if (active > 1)
(void) snprintf(buf, sizeof (buf), gettext(
"%d files were active and will be re-dumped\n"), active);
else
(void) snprintf(buf, sizeof (buf), gettext(
"1 file was active and will be re-dumped\n"));
msg(buf);
doingactive++;
active = 0;
reset();
spcl.c_ddate = spcl.c_date;
if (archivefile) {
old = archivefile;
ext = strstr(old, defext);
if (ext != (char *)NULL)
*ext = '\0';
archivefile = xmalloc(strlen(old) + strlen(defext) +
(int)log10((double)passno) + 2);
(void) sprintf(archivefile, "%s%s%d", old, defext, passno);
free(old);
}
if (tapeout) {
if (isrewind(to)) {
(void) snprintf(buf, sizeof (buf), gettext(
"Warning - cannot dump active files to rewind "
"device `%s'\n"), tape);
msg(buf);
close_rewind();
changevol();
} else {
trewind();
doposition = 0;
filenum++;
}
} else {
close_rewind();
changevol();
}
(void) snprintf(buf, sizeof (buf), gettext(
"Dumping active files (retry pass %d) to `%s'\n"), passno, tape);
msg(buf);
passno++;
}