--- /dev/null
+
+Changes between versions 0.4b3 and 0.4b4
+========================================
+
+1. Dump now runs correctly on kernels 2.1.x
+ Fix made by Gerald Peters <gapeters@worldnet.att.net>
+
+Changes between versions 0.4b2 and 0.4b3
+========================================
+
+1. Use realpath() if available
+
+2. Report statistics
+
+Changes between versions 0.4b1 and 0.4b2
+========================================
+
+1. Fixed the bug fix from Greg Lutz (I had made a mistake when integrating
+ the patch)
+
+2. Fixed restore to make it able to read FreeBSD 2.x dumps again
+
+3. Fixed configure.in to correctly handle --enable-rmt
+
+Changes between versions 0.3 and 0.4b1
+======================================
+
+1. Integrated the changes from 4.4BSD-Lite2
+
+2. Integrated the patches from Debian and Red Hat
+
+3. Portability changes: use the __u32, __u16, __s32, and __s16 types
+
+4. Changed dump to use the Ext2fs library to get block addresses. This
+ should solve the endianness problem on SparcLinux.
+
+5. Created a configure.in file (shamelessly stolen from the e2fsprogs
+ distribution's one) to use autoconf
+
+6. Fixed a few minor bugs
+
+Changes between versions 0.2e and 0.2f
+======================================
+
+1. Added the creation of named pipes (fifos) in restore.
+
+2. Added the -N flag in the restore manual page.
+
+3. Added the file kernel.patch which contains the llseek() optimization
+ patch for 1.2.x kernels.
+
+4. Fixed a bug in the restoration of symbolic links: owner and group were
+ not restored.
+
+5. Integrated some changes from FreeBSD 2.2.
+
+6. Added a call to ftruncate() after restoring each file to restore
+ correctly files ending by a hole.
+
+Changes between versions 0.2d and 0.2e
+======================================
+
+1. Fixed a bug in the "set owner/mode" process. Every file was restored
+ with owner = root (0) and group = root/wheel/whatever (0).
+
+Changes between versions 0.2c and 0.2d
+======================================
+
+1. Dump is now able to backup 2GB+ filesystems.
+
+2. Dump and restore can now be linked as static binaries.
+
+Changes between versions 0.2b and 0.2c
+======================================
+
+1. Fixed a bug when dumping ``slow'' (i.e. normal) symbolic links.
+
+Changes between versions 0.2a and 0.2b
+======================================
+
+1. Really fixed the bug that I should have corrected in 0.2a.
+
+2. Enabled optimization again.
+
+Changes between versions 0.2 and 0.2a
+=====================================
+
+1. Disabled the optimization during compilation.
+
+Changes between versions 0.1 and 0.2
+====================================
+
+1. Fixed a bug in fstab.c which caused a null pointer to be stored in
+ the fs_type field (actually, I modified the file fstab.c to make it
+ use the mntent functions).
+
+2. Dump and restore now use a 4.3 BSD compatible dump format. Backups
+ made by dump should be readable by the BSD restore and backups made
+ by the BSD dump should be readable by restore. Unfortunately, this
+ means that the dump format has changed between version 0.1 and version
+ 0.2 :-(
+
+3. Dump is now able to backup a subtree, it is no longer limited to whole
+ filesystems like the BSD version.
+
+4. Dump now uses ext2_llseek() so it is able to backup filesystems bigger
+ than 2 GB.
+
+Changes between versions 0.0 and 0.1
+====================================
+
+1. Now create links rdump and rrestore during the `make install' step.
+
+2. Linux port specific bugs added to the manual pages
+
+3. Incorrect estimation of the number of tapes blocks fixed when doing
+ incremental backups.
+
+4. Better ls-like format in restore in interactive mode.
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
--- /dev/null
+
+ Installation of the dump/restore port should be quite easy, since
+a configure script is now provided.
+
+ Configuration is made by running the configure script. Run
+`configure --help' to get a list of options.
+
+ After configuring the package, you can type `make' to compile the
+programs, and `make install' to install the binaries in /sbin and the
+manual pages in `/usr/man/man8'.
+
+ You need to have the latest Ext2fs programs installed on your system
+since this version of dump uses the Ext2fs library written by Theodore T'so.
+The Ext2fs programs distribution is available from tsx-11.mit.edu in the
+directory /pub/linux/packages/ext2fs.
--- /dev/null
+Known bugs and limitations of the dump/restore port
+===================================================
+
+1. Multi-volume does not work: restore does not succeeds in
+ resynchronizing itself on a multi-volume dump. Thus, some files are
+ not restored.
+
+2. I have tried to minimize changes in the BSD source and some parts
+ may look ugly. dump/tape.c is really awfull but this is pure BSD
+ code :-) Maybe, I should replace it with a simpler and cleaner
+ version.
--- /dev/null
+VPATH= $(srcdir)
+
+top_builddir= @top_builddir@
+
+AR= @AR@
+CC= @CC@
+INSTALL= @INSTALL@
+LD= @LD@
+LN_S= @LN_S@
+MV= @MV@
+RANLIB= @RANLIB@
+RM= @RM@
+
+BINOWNER= @BINOWNER@
+BINGRP= @BINGRP@
+BINMODE= @BINMODE@
+MANOWNER= @MANOWNER@
+MANGRP= @MANGRP@
+MANMODE= @MANMODE@
+
+INSTALLBIN= $(INSTALL) -o $(BINOWNER) -g $(BINGRP) -m $(BINMODE)
+INSTALLMAN= $(INSTALL) -o $(MANOWNER) -g $(MANGRP) -m $(MANMODE)
+
+BINDIR= /sbin
+MANDIR= /usr/man/man8
+
+#
+# Global include directories
+#
+GINC= -I/usr/include/bsd -I$(top_builddir) -I$(top_srcdir)/compat/include
+# indicate where the ext2fs library can be found (this is not needed if you
+# have run `make install-libs' in the e2fsprogs source directory).
+#GINC+= -I/usr/src/e2fsprogs-0.5c/lib
+
+#
+# Global libraries
+#
+# indicate where the ext2fs library can be found (this is not needed if you
+# have run `make install-libs' in the e2fsprogs source directory).
+#GLIBDIR= -L/usr/src/e2fsprogs-0.5c/lib
+GLIBS= -lbsd $(GLIBDIR) -L../compat/lib -lcompat -lext2fs -lcom_err
+
+#
+# Definitions (don't change them unless you know what you are doing)
+#
+DEFS= -DRDUMP -DRRESTORE -D_BSD_SOURCE -D_USE_BSD_SIGNAL -DLINUX_FORK_BUG
+
+all::
+
+#
+# Autoconf magic
+#
+
+$(top_builddir)/config.status: $(top_srcdir)/configure
+ (cd $(top_builddir); ./config.status --recheck)
+
+$(top_builddir)/MCONFIG: $(top_srcdir)/MCONFIG.in \
+ $(top_builddir)/config.status
+ (cd $(top_builddir); ./config.status)
+
+$(top_builddir)/config.h: $(top_srcdir)/config.h.in \
+ $(top_builddir)/config.status
+ (cd $(top_builddir); ./config.status)
+
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/MCONFIG \
+ $(top_builddir)/config.status
+ (cd $(top_builddir); ./config.status)
+
+$(top_srcdir)/configure: $(top_srcdir)/configure.in
+ cd $(top_srcdir) && autoconf
+
+$(top_srcdir)/config.h.in: $(top_srcdir)/configure.in
+ cd $(top_srcdir) && autoheader
+
+#
+# Make depend magic
+#
+
+.depend: Makefile $(SRCS) $(top_srcdir)/depfix.sed
+ if test -n "$(SRCS)" ; then \
+ $(CC) -M $(CFLAGS) $(SRCS) | \
+ sed -f $(top_srcdir)/depfix.sed \
+ -e 's; $(srcdir)/; $$(srcdir)/;g' \
+ -e 's; $(top_srcdir)/; $$(top_srcdir)/;g' \
+ -e 's; $(top_builddir)/; $$(top_builddir)/;g' \
+ -e 's; \./; ;g' \
+ -e '/^ *\\$$/d' > .depend; \
+ else :; fi
+
+depend:: .depend
+ if test -n "$(SRCS)" ; then \
+ sed -e '/^# +++ Dependency line eater +++/,$$d' \
+ < Makefile | cat - .depend \
+ > Makefile.new; \
+ $(MV) Makefile Makefile.old; \
+ $(MV) Makefile.new Makefile; \
+ else :; fi
--- /dev/null
+srcdir= @srcdir@
+top_srcdir= @top_srcdir@
+
+@MCONFIG@
+
+RM= @RM@
+SUBDIRS= compat/lib common dump restore @RMTDIR@
+
+all clean install dep depend realclean distclean::
+ for i in $(SUBDIRS); do \
+ (cd $$i && $(MAKE) $@) || exit 1; \
+ done
+
+distclean::
+ $(RM) -f config.status config.log config.cache
+ $(RM) -f MCONFIG Makefile config.h
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+
--- /dev/null
+
+ This is a test release of dump 0.4.
+
+ See the file CHANGES for a list of changes from the previous version.
+
+ See the file INSTALL for installation instructions.
+
+ If you encounter problems with the dump and restore backup suite,
+please contact me (card@Linux.EU.Org) and send me a detailled bug report.
--- /dev/null
+Dump and restore were written by the people of the CSRG at the University
+of California, Berkeley.
+
+They were ported to Linux by Remy Card <card@Linux.EU.Org>, by using
+the Ext2fs library, written by Theodore Ts'o <tytso@mit.edu>.
+
+Kevin Layer <layer@Franz.COM> added the comparison code in restore.
+
+Doug Paul <dbp@dragonsys.com> helped me to make dump able to backup 2GB+
+filesystems.
+
+David Frey <david@eos.lugs.ch> (the Debian dump maintainer) and the people
+from Red Hat Software provided lots of patches.
+
+Thanks to people who reported problems with the port, sent patches, and
+suggested various improvements.
+Here is a partial list of them (if I have forgotten someone, please complain):
+
+Henry Katz hkatz@hkatz.dialup.access.net
+Klaus Kudielka kkudielk@cacofonix.nt.tuwien.ac.at
+Florian La Roche florian@jurix.jura.uni-sb.de
+Greg Lutz greglutz@ix.netcom.com
+David Miller davem@caip.rutgers.edu
+David Monro davidm@cs.su.oz.au
+Lukas Nellen L.Nellen@ThPhys.Uni-Heidelberg.DE
+Brent Olson night@halcyon.com
+Bob Snyder rsnyder@janet.advsys.com
+Stephen Tweedie sct@dcs.ed.ac.uk
+Daniel Veillard Daniel.Veillard@imag.fr
+Jason Venner jason@idiom.com
--- /dev/null
+1. Fix the multi-volume problem (is there one after all?, I could not
+ reproduce it and some people told me that multi-volume dumps were Ok).
+
+2. Make dump honor the no-dump attribute on directories. Currently, it
+ honours it only on files. This means that a directory flagged with
+ the no-dump attribute will be dumped if it contains a file without
+ the no-dump flag.
+
+3. Change the way rdump and rrestore call rmt. Currently, rcmd() is used
+ but it may be better to call rsh. I have to look at the GNU tar code.
+
+4. Make dump able to backup several directories and/or files in one
+ invocation, like the SunOS version.
--- /dev/null
+/* Define to __s64 if <sys/types.h> does not define */
+#undef quad_t
+
+/* Define to __u64 if <sys/types.h> does not define */
+#undef u_quad_t
--- /dev/null
+top_srcdir= @top_srcdir@
+srcdir= @srcdir@
+
+@MCONFIG@
+
+INC= -I$(top_srcdir)/dump
+CFLAGS= @CCOPTS@ -pipe $(GINC) $(INC) $(DEFS)
+SRCS= dumprmt.c
+OBJS= dumprmt.o
+
+all:: $(OBJS)
+
+install::
+
+clean::
+ $(RM) -f \#* *.s *.o *.a *~ core
+
+distclean:: clean
+ $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)dumprmt.c 8.2 (Berkeley) 4/28/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/mtio.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else
+#ifdef sunos
+#include <sys/vnode.h>
+
+#include <ufs/inode.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+#endif
+
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+
+#include <protocols/dumprestore.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <netdb.h>
+#include <pwd.h>
+#include <signal.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "pathnames.h"
+#include "dump.h"
+
+#define TS_CLOSED 0
+#define TS_OPEN 1
+
+static int rmtstate = TS_CLOSED;
+static int rmtape;
+static char *rmtpeer;
+
+static int okname __P((char *));
+static int rmtcall __P((char *, char *));
+static void rmtconnaborted __P((/* int, int */));
+static int rmtgetb __P((void));
+static void rmtgetconn __P((void));
+static void rmtgets __P((char *, int));
+static int rmtreply __P((char *));
+
+extern int ntrec; /* blocking factor on tape */
+
+int
+rmthost(host)
+ char *host;
+{
+
+ rmtpeer = malloc(strlen(host) + 1);
+ if (rmtpeer)
+ strcpy(rmtpeer, host);
+ else
+ rmtpeer = host;
+ signal(SIGPIPE, rmtconnaborted);
+ rmtgetconn();
+ if (rmtape < 0)
+ return (0);
+ return (1);
+}
+
+static void
+rmtconnaborted()
+{
+
+ errx(1, "Lost connection to remote host.");
+}
+
+void
+rmtgetconn()
+{
+ register char *cp;
+ static struct servent *sp = NULL;
+ static struct passwd *pwd = NULL;
+#ifdef notdef
+ static int on = 1;
+#endif
+ char *tuser;
+ int size;
+ int maxseg;
+
+ if (sp == NULL) {
+ sp = getservbyname("shell", "tcp");
+ if (sp == NULL)
+ errx(1, "shell/tcp: unknown service");
+ pwd = getpwuid(getuid());
+ if (pwd == NULL)
+ errx(1, "who are you?");
+ }
+ if ((cp = strchr(rmtpeer, '@')) != NULL) {
+ tuser = rmtpeer;
+ *cp = '\0';
+ if (!okname(tuser))
+ exit(1);
+ rmtpeer = ++cp;
+ } else
+ tuser = pwd->pw_name;
+ rmtape = rcmd(&rmtpeer, (u_short)sp->s_port, pwd->pw_name, tuser,
+ _PATH_RMT, (int *)0);
+ size = ntrec * TP_BSIZE;
+ if (size > 60 * 1024) /* XXX */
+ size = 60 * 1024;
+ /* Leave some space for rmt request/response protocol */
+ size += 2 * 1024;
+ while (size > TP_BSIZE &&
+ setsockopt(rmtape, SOL_SOCKET, SO_SNDBUF, &size, sizeof (size)) < 0)
+ size -= TP_BSIZE;
+ (void)setsockopt(rmtape, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size));
+ maxseg = 1024;
+ if (setsockopt(rmtape, IPPROTO_TCP, TCP_MAXSEG,
+ &maxseg, sizeof (maxseg)) < 0)
+ perror("TCP_MAXSEG setsockopt");
+
+#ifdef notdef
+ if (setsockopt(rmtape, IPPROTO_TCP, TCP_NODELAY, &on, sizeof (on)) < 0)
+ perror("TCP_NODELAY setsockopt");
+#endif
+}
+
+static int
+okname(cp0)
+ char *cp0;
+{
+ register char *cp;
+ register int c;
+
+ for (cp = cp0; *cp; cp++) {
+ c = *cp;
+ if (!isascii(c) || !(isalnum(c) || c == '_' || c == '-')) {
+ warnx("invalid user name: %s", cp0);
+ return (0);
+ }
+ }
+ return (1);
+}
+
+int
+rmtopen(tape, mode)
+ char *tape;
+ int mode;
+{
+ char buf[256];
+
+ (void)sprintf(buf, "O%s\n%d\n", tape, mode);
+ rmtstate = TS_OPEN;
+ return (rmtcall(tape, buf));
+}
+
+void
+rmtclose()
+{
+
+ if (rmtstate != TS_OPEN)
+ return;
+ rmtcall("close", "C\n");
+ rmtstate = TS_CLOSED;
+}
+
+int
+rmtread(buf, count)
+ char *buf;
+ int count;
+{
+ char line[30];
+ int n, i, cc;
+ extern errno;
+
+ (void)sprintf(line, "R%d\n", count);
+ n = rmtcall("read", line);
+ if (n < 0) {
+ errno = n;
+ return (-1);
+ }
+ for (i = 0; i < n; i += cc) {
+ cc = read(rmtape, buf+i, n - i);
+ if (cc <= 0) {
+ rmtconnaborted();
+ }
+ }
+ return (n);
+}
+
+int
+rmtwrite(buf, count)
+ char *buf;
+ int count;
+{
+ char line[30];
+
+ (void)sprintf(line, "W%d\n", count);
+ write(rmtape, line, strlen(line));
+ write(rmtape, buf, count);
+ return (rmtreply("write"));
+}
+
+void
+rmtwrite0(count)
+ int count;
+{
+ char line[30];
+
+ (void)sprintf(line, "W%d\n", count);
+ write(rmtape, line, strlen(line));
+}
+
+void
+rmtwrite1(buf, count)
+ char *buf;
+ int count;
+{
+
+ write(rmtape, buf, count);
+}
+
+int
+rmtwrite2()
+{
+
+ return (rmtreply("write"));
+}
+
+int
+rmtseek(offset, pos)
+ int offset, pos;
+{
+ char line[80];
+
+ (void)sprintf(line, "L%d\n%d\n", offset, pos);
+ return (rmtcall("seek", line));
+}
+
+struct mtget mts;
+
+struct mtget *
+rmtstatus()
+{
+ register int i;
+ register char *cp;
+
+ if (rmtstate != TS_OPEN)
+ return (NULL);
+ rmtcall("status", "S\n");
+ for (i = 0, cp = (char *)&mts; i < sizeof(mts); i++)
+ *cp++ = rmtgetb();
+ return (&mts);
+}
+
+int
+rmtioctl(cmd, count)
+ int cmd, count;
+{
+ char buf[256];
+
+ if (count < 0)
+ return (-1);
+ (void)sprintf(buf, "I%d\n%d\n", cmd, count);
+ return (rmtcall("ioctl", buf));
+}
+
+static int
+rmtcall(cmd, buf)
+ char *cmd, *buf;
+{
+
+ if (write(rmtape, buf, strlen(buf)) != strlen(buf))
+ rmtconnaborted();
+ return (rmtreply(cmd));
+}
+
+static int
+rmtreply(cmd)
+ char *cmd;
+{
+ register char *cp;
+ char code[30], emsg[BUFSIZ];
+
+ rmtgets(code, sizeof (code));
+ if (*code == 'E' || *code == 'F') {
+ rmtgets(emsg, sizeof (emsg));
+ msg("%s: %s", cmd, emsg);
+ if (*code == 'F') {
+ rmtstate = TS_CLOSED;
+ return (-1);
+ }
+ return (-1);
+ }
+ if (*code != 'A') {
+ /* Kill trailing newline */
+ cp = code + strlen(code);
+ if (cp > code && *--cp == '\n')
+ *cp = '\0';
+
+ msg("Protocol to remote tape server botched (code \"%s\").\n",
+ code);
+ rmtconnaborted();
+ }
+ return (atoi(code + 1));
+}
+
+int
+rmtgetb()
+{
+ char c;
+
+ if (read(rmtape, &c, 1) != 1)
+ rmtconnaborted();
+ return (c);
+}
+
+/* Get a line (guaranteed to have a trailing newline). */
+void
+rmtgets(line, len)
+ char *line;
+ int len;
+{
+ register char *cp = line;
+
+ while (len > 1) {
+ *cp = rmtgetb();
+ if (*cp == '\n') {
+ cp[1] = '\0';
+ return;
+ }
+ cp++;
+ len--;
+ }
+ *cp = '\0';
+ msg("Protocol to remote tape server botched.\n");
+ msg("(rmtgets got \"%s\").\n", line);
+ rmtconnaborted();
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+#include <config.h>
+
+#define __dead volatile
+
+#ifndef NBBY
+#define NBBY 8
+#endif
+
+#ifndef MIN
+#define MIN(a,b) ((a < b) ? a : b)
+#endif
+
+#define WINO ((ino_t)1)
+#define DEV_BSIZE 512
+#define DEV_BSHIFT 9
+#define MAXBSIZE EXT2_MAX_BLOCK_SIZE
+#define ROOTINO EXT2_ROOT_INO
+#ifdef EXT2_NODUMP_FL
+#define UF_NODUMP EXT2_NODUMP_FL
+#endif
+
+#define howmany(x,y) (((x)+((y)-1))/(y))
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+#define powerof2(x) ((((x)-1)&(x))==0)
+
+#define dbtob(b) ((unsigned)(b) << DEV_BSHIFT)
+#define fsbtodb(sb,b) ((int)(((long long)b * EXT2_BLOCK_SIZE(sb->super)) / DEV_BSIZE))
+
+#define sblock fs
+#define fs_fsize fragsize
+#define fs_bsize blocksize
+#define fs_size super->s_blocks_count
+
+#define IFMT S_IFMT
+#define IFLNK S_IFLNK
+#define IFREG S_IFREG
+#define IFDIR S_IFDIR
+#define IFCHR S_IFCHR
+#define IFBLK S_IFBLK
+#define IFSOCK S_IFSOCK
+#define IFIFO S_IFIFO
+
+#if 0
+typedef __s64 quad_t;
+typedef __u64 u_quad_t;
+#endif
+
+/*
+ * The BSD dump format reserves 4 bytes for a time_t, but other architectures
+ * (notably axp) have larger time_t. ctime4() is a modified ctime() which
+ * always accepts short 4-byte times. time4() is a similarly modified time().
+ */
+#define ctime4(timep) ({ time_t t = *(timep); ctime(&t); })
+#define time4(timep) ({time_t t; t = time(0); if (timep) *timep=t; t; })
+
+/*
+ * This is the ext2_inode structure but the fields have been renamed
+ * to match 4.4BSD's names
+ */
+#define NDADDR 12
+#define NIADDR 3
+
+#define NINDIR(fs) EXT2_ADDR_PER_BLOCK(fs->super)
+
+struct dinode {
+ __u16 di_mode;
+ __u16 di_uid;
+ __u32 di_size;
+ __u32 di_atime;
+ __u32 di_ctime;
+ __u32 di_mtime;
+ __u32 di_dtime;
+ __u16 di_gid;
+ __u16 di_nlink;
+ __u32 di_blocks;
+ __u32 di_flags;
+ __u32 di_reserved1;
+ daddr_t di_db[NDADDR];
+ daddr_t di_ib[NIADDR];
+ __u32 di_gen;
+ __u32 di_file_acl;
+ __u32 di_dir_acl;
+ __u32 di_faddr;
+ __u8 di_frag;
+ __u8 di_fsize;
+ __u16 di_pad1;
+ __u32 di_spare[2];
+};
+
+#define di_rdev di_db[0]
+/* #define di_ouid di_uid */
+/* #define di_ogid di_gid */
+
+/*
+ * This is the ext2_dir_entry structure but the fields have been renamed
+ * to match 4.4BSD's names
+ *
+ * This is the 4.4BSD directory entry structure
+ */
+#define DIRBLKSIZ DEV_BSIZE
+#define MAXNAMLEN 255
+
+struct direct {
+ __u32 d_ino;
+ __u16 d_reclen;
+#if 1
+ __u8 d_namlen;
+ __u8 d_type;
+#else
+ __u16 d_namlen;
+#endif
+ char d_name[MAXNAMLEN + 1];
+};
+
+/*
+ * File types
+ */
+#define DT_UNKNOWN 0
+#define DT_FIFO 1
+#define DT_CHR 2
+#define DT_DIR 4
+#define DT_BLK 6
+#define DT_REG 8
+#define DT_LNK 10
+#define DT_SOCK 12
+#define DT_WHT 14
+
+/*
+ * Convert between stat structure types and directory types.
+ */
+#define IFTODT(mode) (((mode) & 0170000) >> 12)
+#define DTTOIF(dirtype) ((dirtype) << 12)
+
+/*
+ * The DIRSIZ macro gives the minimum record length which will hold
+ * the directory entry. This requires the amount of space in struct direct
+ * without the d_name field, plus enough space for the name with a terminating
+ * null byte (dp->d_namlen+1), rounded up to a 4 byte boundary.
+ */
+#if 0
+#if (BYTE_ORDER == LITTLE_ENDIAN)
+#define DIRSIZ(oldfmt, dp) \
+ ((oldfmt) ? \
+ ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_type+1 + 3) &~ 3)) : \
+ ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3)))
+#else
+#define DIRSIZ(oldfmt, dp) \
+ ((sizeof (struct direct) - (MAXNAMLEN+1)) + (((dp)->d_namlen+1 + 3) &~ 3))
+#endif
+#else
+
+#define DIRSIZ(oldfmt,dp) EXT2_DIR_REC_LEN(((dp)->d_namlen & 0xff) + 1)
+
+#endif
+
+/*
+ * This is the old (Net/2) BSD inode structure
+ * copied from the FreeBSD 1.1.5.1 <ufs/dinode.h> include file
+ */
+#define MAXFASTLINK (((NDADDR + NIADDR) * sizeof(unsigned long)) - 1)
+
+struct old_bsd_inode {
+ __u16 di_mode;
+ __s16 di_nlink;
+ __u16 di_uid;
+ __u16 di_gid;
+#if 1
+ union {
+ u_quad_t v;
+ __u32 val[2];
+ } di_qsize;
+#else
+ u_quad_t di_size;
+#endif
+ __u32 di_atime;
+ __s32 di_atspare;
+ __u32 di_mtime;
+ __s32 di_mtspare;
+ __u32 di_ctime;
+ __s32 di_ctspare;
+#if 0
+ union {
+ struct {
+ daddr_t di_udb[NDADDR];
+ daddr_t di_uib[NIADDR];
+ } di_addr;
+ char di_usymlink[MAXFASTLINK + 1];
+ } di_un;
+#else
+ daddr_t di_db[NDADDR];
+ daddr_t di_ib[NIADDR];
+#endif
+ __s32 di_flags;
+ __s32 di_blocks;
+ __s32 di_gen;
+ __u32 di_spare[4];
+};
+
+/*
+ * This is the new (4.4) BSD inode structure
+ * copied from the FreeBSD 2.0 <ufs/ufs/dinode.h> include file
+ */
+struct new_bsd_inode {
+ __u16 di_mode;
+ __s16 di_nlink;
+ union {
+ __u16 oldids[2];
+ __u32 inumber;
+ } di_u;
+ u_quad_t di_size;
+ struct timeval di_atime;
+ struct timeval di_mtime;
+ struct timeval di_ctime;
+ daddr_t di_db[NDADDR];
+ daddr_t di_ib[NIADDR];
+ __u32 di_flags;
+ __s32 di_blocks;
+ __s32 di_gen;
+ __u32 di_uid;
+ __u32 di_gid;
+ __s32 di_spare[2];
+};
+
+#define di_ouid di_u.oldids[0]
+#define di_ogid di_u.oldids[1]
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)err.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _ERR_H_
+#define _ERR_H_
+
+#include <sys/cdefs.h>
+
+#include <stdarg.h>
+
+#ifndef _BSD_VA_LIST_
+#define _BSD_VA_LIST_ va_list
+#endif
+
+#ifndef __dead
+#define __dead volatile
+#endif
+
+__BEGIN_DECLS
+__dead void err __P((int, const char *, ...));
+__dead void verr __P((int, const char *, _BSD_VA_LIST_));
+__dead void errx __P((int, const char *, ...));
+__dead void verrx __P((int, const char *, _BSD_VA_LIST_));
+void warn __P((const char *, ...));
+void vwarn __P((const char *, _BSD_VA_LIST_));
+void warnx __P((const char *, ...));
+void vwarnx __P((const char *, _BSD_VA_LIST_));
+__END_DECLS
+
+#endif /* !_ERR_H_ */
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)fstab.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _FSTAB_H_
+#define _FSTAB_H_
+
+/*
+ * File system table, see fstab(5).
+ *
+ * Used by dump, mount, umount, swapon, fsck, df, ...
+ *
+ * For ufs fs_spec field is the block special name. Programs that want to
+ * use the character special name must create that name by prepending a 'r'
+ * after the right most slash. Quota files are always named "quotas", so
+ * if type is "rq", then use concatenation of fs_file and "quotas" to locate
+ * quota file.
+ */
+#define _PATH_FSTAB "/etc/fstab"
+#define FSTAB "/etc/fstab" /* deprecated */
+
+#define FSTAB_DEF "defaults" /* default mount option */
+#define FSTAB_RW "rw" /* read/write device */
+#define FSTAB_RQ "rq" /* read/write with quotas */
+#define FSTAB_RO "ro" /* read-only device */
+#define FSTAB_SW "sw" /* swap device */
+#define FSTAB_XX "ignore" /* ignore totally */
+
+struct fstab {
+ char *fs_spec; /* block special device name */
+ char *fs_file; /* file system path prefix */
+ char *fs_vfstype; /* File system type, ufs, nfs */
+ char *fs_mntops; /* Mount options ala -o */
+ char *fs_type; /* FSTAB_* from fs_mntops */
+ int fs_freq; /* dump frequency, in days */
+ int fs_passno; /* pass number on parallel dump */
+};
+
+#include <sys/cdefs.h>
+
+__BEGIN_DECLS
+struct fstab *getfsent __P((void));
+struct fstab *getfsspec __P((const char *));
+struct fstab *getfsfile __P((const char *));
+int setfsent __P((void));
+void endfsent __P((void));
+__END_DECLS
+
+#endif /* !_FSTAB_H_ */
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)glob.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _GLOB_H_
+#define _GLOB_H_
+
+#include <sys/cdefs.h>
+
+struct stat;
+typedef struct {
+ int gl_pathc; /* Count of total paths so far. */
+ int gl_matchc; /* Count of paths matching pattern. */
+ int gl_offs; /* Reserved at beginning of gl_pathv. */
+ int gl_flags; /* Copy of flags parameter to glob. */
+ char **gl_pathv; /* List of paths matching pattern. */
+ /* Copy of errfunc parameter to glob. */
+ int (*gl_errfunc) __P((const char *, int));
+
+ /*
+ * Alternate filesystem access methods for glob; replacement
+ * versions of closedir(3), readdir(3), opendir(3), stat(2)
+ * and lstat(2).
+ */
+ void (*gl_closedir) __P((void *));
+ struct dirent *(*gl_readdir) __P((void *));
+ void *(*gl_opendir) __P((const char *));
+ int (*gl_lstat) __P((const char *, struct stat *));
+ int (*gl_stat) __P((const char *, struct stat *));
+} glob_t;
+
+#define GLOB_APPEND 0x0001 /* Append to output from previous call. */
+#define GLOB_DOOFFS 0x0002 /* Use gl_offs. */
+#define GLOB_ERR 0x0004 /* Return on error. */
+#define GLOB_MARK 0x0008 /* Append / to matching directories. */
+#define GLOB_NOCHECK 0x0010 /* Return pattern itself if nothing matches. */
+#define GLOB_NOSORT 0x0020 /* Don't sort. */
+
+/* #ifndef _POSIX_SOURCE */
+#define GLOB_ALTDIRFUNC 0x0040 /* Use alternately specified directory funcs. */
+#define GLOB_BRACE 0x0080 /* Expand braces ala csh. */
+#define GLOB_MAGCHAR 0x0100 /* Pattern had globbing characters. */
+#define GLOB_NOMAGIC 0x0200 /* GLOB_NOCHECK without magic chars (csh). */
+#define GLOB_QUOTE 0x0400 /* Quote special chars with \. */
+#define GLOB_TILDE 0x0800 /* Expand tilde names from the passwd file. */
+/* #endif */
+
+#define GLOB_NOSPACE (-1) /* Malloc call failed. */
+#define GLOB_ABEND (-2) /* Unignored error. */
+
+__BEGIN_DECLS
+int glob __P((const char *, int, int (*)(const char *, int), glob_t *));
+void globfree __P((glob_t *));
+__END_DECLS
+
+#endif /* !_GLOB_H_ */
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)pathnames.h 8.1 (Berkeley) 6/5/93
+ */
+
+#include <paths.h>
+
+#define _PATH_DEFTAPE "/dev/rmt8"
+#define _PATH_DTMP "/etc/dtmp"
+#define _PATH_DUMPDATES "/etc/dumpdates"
+#define _PATH_LOCK "/tmp/dumplockXXXXXX"
+#define _PATH_RMT "rmt"
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dumprestore.h 8.2 (Berkeley) 1/21/94
+ */
+
+#ifndef _DUMPRESTORE_H_
+#define _DUMPRESTORE_H_
+
+/*
+ * TP_BSIZE is the size of file blocks on the dump tapes.
+ * Note that TP_BSIZE must be a multiple of DEV_BSIZE.
+ *
+ * NTREC is the number of TP_BSIZE blocks that are written
+ * in each tape record. HIGHDENSITYTREC is the number of
+ * TP_BSIZE blocks that are written in each tape record on
+ * 6250 BPI or higher density tapes.
+ *
+ * TP_NINDIR is the number of indirect pointers in a TS_INODE
+ * or TS_ADDR record. Note that it must be a power of two.
+ */
+#define TP_BSIZE 1024
+#define NTREC 10
+#define HIGHDENSITYTREC 32
+#define TP_NINDIR (TP_BSIZE/2)
+#define LBLSIZE 16
+#define NAMELEN 64
+
+#define OFS_MAGIC (int)60011
+#define NFS_MAGIC (int)60012
+#define CHECKSUM (int)84446
+
+union u_spcl {
+ char dummy[TP_BSIZE];
+ struct s_spcl {
+ __s32 c_type; /* record type (see below) */
+ __u32 c_date; /* date of this dump */
+ __u32 c_ddate; /* date of previous dump */
+ __s32 c_volume; /* dump volume number */
+ daddr_t c_tapea; /* logical block of this record */
+ ino_t c_inumber; /* number of inode */
+ __s32 c_magic; /* magic number (see above) */
+ __s32 c_checksum; /* record checksum */
+#ifdef __linux__
+ struct new_bsd_inode c_dinode;
+#else
+ struct dinode c_dinode; /* ownership and mode of inode */
+#endif
+ __s32 c_count; /* number of valid c_addr entries */
+ char c_addr[TP_NINDIR]; /* 1 => data; 0 => hole in inode */
+ char c_label[LBLSIZE]; /* dump label */
+ __s32 c_level; /* level of this dump */
+ char c_filesys[NAMELEN]; /* name of dumpped file system */
+ char c_dev[NAMELEN]; /* name of dumpped device */
+ char c_host[NAMELEN]; /* name of dumpped host */
+ __s32 c_flags; /* additional information */
+ __s32 c_firstrec; /* first record on volume */
+ __s32 c_spare[32]; /* reserved for future uses */
+ } s_spcl;
+} u_spcl;
+#define spcl u_spcl.s_spcl
+/*
+ * special record types
+ */
+#define TS_TAPE 1 /* dump tape header */
+#define TS_INODE 2 /* beginning of file record */
+#define TS_ADDR 4 /* continuation of file record */
+#define TS_BITS 3 /* map of inodes on tape */
+#define TS_CLRI 6 /* map of inodes deleted since last dump */
+#define TS_END 5 /* end of volume marker */
+
+/*
+ * flag values
+ */
+#define DR_NEWHEADER 0x0001 /* new format tape header */
+#define DR_NEWINODEFMT 0x0002 /* new format inodes on tape */
+
+#define DUMPOUTFMT "%-16s %c %s" /* for printf */
+ /* name, level, ctime(date) */
+#define DUMPINFMT "%16s %c %[^\n]\n" /* inverse for scanf */
+
+#endif /* !_DUMPRESTORE_H_ */
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Arthur David Olson of the National Cancer Institute.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)tzfile.h 8.1 (Berkeley) 6/2/93
+ */
+
+#ifndef _TZFILE_H_
+#define _TZFILE_H_
+
+/*
+ * Information about time zone files.
+ */
+ /* Time zone object file directory */
+#define TZDIR "/usr/share/zoneinfo"
+#define TZDEFAULT "/etc/localtime"
+#define TZDEFRULES "posixrules"
+
+/*
+** Each file begins with. . .
+*/
+
+struct tzhead {
+ char tzh_reserved[24]; /* reserved for future use */
+ char tzh_ttisstdcnt[4]; /* coded number of trans. time flags */
+ char tzh_leapcnt[4]; /* coded number of leap seconds */
+ char tzh_timecnt[4]; /* coded number of transition times */
+ char tzh_typecnt[4]; /* coded number of local time types */
+ char tzh_charcnt[4]; /* coded number of abbr. chars */
+};
+
+/*
+** . . .followed by. . .
+**
+** tzh_timecnt (char [4])s coded transition times a la time(2)
+** tzh_timecnt (unsigned char)s types of local time starting at above
+** tzh_typecnt repetitions of
+** one (char [4]) coded GMT offset in seconds
+** one (unsigned char) used to set tm_isdst
+** one (unsigned char) that's an abbreviation list index
+** tzh_charcnt (char)s '\0'-terminated zone abbreviations
+** tzh_leapcnt repetitions of
+** one (char [4]) coded leap second transition times
+** one (char [4]) total correction after above
+** tzh_ttisstdcnt (char)s indexed by type; if TRUE, transition
+** time is standard time, if FALSE,
+** transition time is wall clock time
+** if absent, transition times are
+** assumed to be wall clock time
+*/
+
+/*
+** In the current implementation, "tzset()" refuses to deal with files that
+** exceed any of the limits below.
+*/
+
+/*
+** The TZ_MAX_TIMES value below is enough to handle a bit more than a
+** year's worth of solar time (corrected daily to the nearest second) or
+** 138 years of Pacific Presidential Election time
+** (where there are three time zone transitions every fourth year).
+*/
+#define TZ_MAX_TIMES 370
+
+#define NOSOLAR /* 4BSD doesn't currently handle solar time */
+
+#ifndef NOSOLAR
+#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */
+#else
+#define TZ_MAX_TYPES 10 /* Maximum number of local time types */
+#endif
+
+#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */
+
+#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */
+
+#define SECSPERMIN 60
+#define MINSPERHOUR 60
+#define HOURSPERDAY 24
+#define DAYSPERWEEK 7
+#define DAYSPERNYEAR 365
+#define DAYSPERLYEAR 366
+#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR)
+#define SECSPERDAY ((long) SECSPERHOUR * HOURSPERDAY)
+#define MONSPERYEAR 12
+
+#define TM_SUNDAY 0
+#define TM_MONDAY 1
+#define TM_TUESDAY 2
+#define TM_WEDNESDAY 3
+#define TM_THURSDAY 4
+#define TM_FRIDAY 5
+#define TM_SATURDAY 6
+
+#define TM_JANUARY 0
+#define TM_FEBRUARY 1
+#define TM_MARCH 2
+#define TM_APRIL 3
+#define TM_MAY 4
+#define TM_JUNE 5
+#define TM_JULY 6
+#define TM_AUGUST 7
+#define TM_SEPTEMBER 8
+#define TM_OCTOBER 9
+#define TM_NOVEMBER 10
+#define TM_DECEMBER 11
+
+#define TM_YEAR_BASE 1900
+
+#define EPOCH_YEAR 1970
+#define EPOCH_WDAY TM_THURSDAY
+
+/*
+** Accurate only for the past couple of centuries;
+** that will probably do.
+*/
+
+#define isleap(y) (((y) % 4) == 0 && ((y) % 100) != 0 || ((y) % 400) == 0)
+
+#endif /* !_TZFILE_H_ */
--- /dev/null
+top_srcdir= @top_srcdir@
+srcdir= @srcdir@
+
+@MCONFIG@
+
+INC= -I$(top_srcdir)/compat/include
+CFLAGS= @CCOPTS@ -pipe $(GINC) $(INC) $(DEFS)
+SRCS= err.c fstab.c glob.c
+OBJS= err.o fstab.o glob.o
+LIB= libcompat.a
+
+all:: $(LIB)
+
+$(LIB): $(OBJS)
+ $(AR) r $(LIB) $(OBJS)
+ $(RANLIB) $(LIB)
+
+install::
+
+clean::
+ $(RM) -f \#* *.s *.o *.a *~ core
+
+distclean:: clean
+ $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)err.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <err.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+#include <config.h>
+
+extern char *__progname; /* Program name, from crt0. */
+
+#ifndef HAVE_ERR
+__dead void
+#ifdef __STDC__
+err(int eval, const char *fmt, ...)
+#else
+err(eval, fmt, va_alist)
+ int eval;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ verr(eval, fmt, ap);
+ va_end(ap);
+}
+#endif
+
+#ifndef HAVE_VERR
+__dead void
+verr(eval, fmt, ap)
+ int eval;
+ const char *fmt;
+ va_list ap;
+{
+ int sverrno;
+
+ sverrno = errno;
+ (void)fprintf(stderr, "%s: ", __progname);
+ if (fmt != NULL) {
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, ": ");
+ }
+ (void)fprintf(stderr, "%s\n", strerror(sverrno));
+ exit(eval);
+}
+#endif
+
+#ifndef HAVE_ERRX
+__dead void
+#if __STDC__
+errx(int eval, const char *fmt, ...)
+#else
+errx(eval, fmt, va_alist)
+ int eval;
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ verrx(eval, fmt, ap);
+ va_end(ap);
+}
+#endif
+
+#ifndef HAVE_VERRX
+__dead void
+verrx(eval, fmt, ap)
+ int eval;
+ const char *fmt;
+ va_list ap;
+{
+ (void)fprintf(stderr, "%s: ", __progname);
+ if (fmt != NULL)
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, "\n");
+ exit(eval);
+}
+#endif
+
+#ifndef HAVE_WARN
+void
+#if __STDC__
+warn(const char *fmt, ...)
+#else
+warn(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vwarn(fmt, ap);
+ va_end(ap);
+}
+#endif
+
+#ifndef HAVE_VWARN
+void
+vwarn(fmt, ap)
+ const char *fmt;
+ va_list ap;
+{
+ int sverrno;
+
+ sverrno = errno;
+ (void)fprintf(stderr, "%s: ", __progname);
+ if (fmt != NULL) {
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, ": ");
+ }
+ (void)fprintf(stderr, "%s\n", strerror(sverrno));
+}
+#endif
+
+#ifndef HAVE_WARNX
+void
+#ifdef __STDC__
+warnx(const char *fmt, ...)
+#else
+warnx(fmt, va_alist)
+ const char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#ifdef __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ vwarnx(fmt, ap);
+ va_end(ap);
+}
+#endif
+
+#ifndef HAVE_VWARNX
+void
+vwarnx(fmt, ap)
+ const char *fmt;
+ va_list ap;
+{
+ (void)fprintf(stderr, "%s: ", __progname);
+ if (fmt != NULL)
+ (void)vfprintf(stderr, fmt, ap);
+ (void)fprintf(stderr, "\n");
+}
+#endif
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)fstab.c 8.1 (Berkeley) 6/4/93";
+#endif /* LIBC_SCCS and not lint */
+
+#include <errno.h>
+#include <fstab.h>
+#include <mntent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+static FILE *_fs_fp;
+static struct fstab _fs_fstab;
+
+static void error __P((int));
+static int fstabscan __P((void));
+
+static
+int fstabscan()
+{
+ struct mntent *mnt;
+ register char *cp;
+ int typexx;
+#define MAXLINELENGTH 1024
+ char subline[MAXLINELENGTH];
+
+ for (;;) {
+ if (!(mnt = getmntent(_fs_fp)))
+ return 0;
+
+ _fs_fstab.fs_spec = mnt->mnt_fsname;
+ _fs_fstab.fs_file = mnt->mnt_dir;
+ _fs_fstab.fs_vfstype = mnt->mnt_type;
+ _fs_fstab.fs_mntops = mnt->mnt_opts;
+ _fs_fstab.fs_type = FSTAB_RW; /* rw by default under Linux */
+ _fs_fstab.fs_freq = mnt->mnt_freq;
+ _fs_fstab.fs_passno = mnt->mnt_passno;
+
+ strcpy(subline, _fs_fstab.fs_mntops);
+ for (typexx = 0, cp = strtok(subline, ","); cp;
+ cp = strtok((char *)NULL, ",")) {
+ if (!strcmp(cp, FSTAB_RW)) {
+ _fs_fstab.fs_type = FSTAB_RW;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_RQ)) {
+ _fs_fstab.fs_type = FSTAB_RQ;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_RO)) {
+ _fs_fstab.fs_type = FSTAB_RO;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_SW)) {
+ _fs_fstab.fs_type = FSTAB_SW;
+ break;
+ }
+ if (!strcmp(cp, FSTAB_XX)) {
+ _fs_fstab.fs_type = FSTAB_XX;
+ typexx++;
+ break;
+ }
+ }
+ if (typexx)
+ continue;
+
+ return 1;
+ }
+}
+
+struct fstab *
+getfsent()
+{
+ if (!_fs_fp && !setfsent() || !fstabscan())
+ return((struct fstab *)NULL);
+ return(&_fs_fstab);
+}
+
+struct fstab *
+getfsspec(name)
+ register const char *name;
+{
+ if (setfsent())
+ while (fstabscan())
+ if (!strcmp(_fs_fstab.fs_spec, name))
+ return(&_fs_fstab);
+ return((struct fstab *)NULL);
+}
+
+struct fstab *
+getfsfile(name)
+ register const char *name;
+{
+ if (setfsent())
+ while (fstabscan())
+ if (!strcmp(_fs_fstab.fs_file, name))
+ return(&_fs_fstab);
+ return((struct fstab *)NULL);
+}
+
+int setfsent()
+{
+ if (_fs_fp) {
+ rewind(_fs_fp);
+ return(1);
+ }
+ if ((_fs_fp = setmntent(_PATH_FSTAB, "r")))
+ return(1);
+ error(errno);
+ return(0);
+}
+
+void
+endfsent()
+{
+ if (_fs_fp) {
+ (void)endmntent(_fs_fp);
+ _fs_fp = NULL;
+ }
+}
+
+static
+void error(err)
+ int err;
+{
+ char *p;
+
+ (void)write(STDERR_FILENO, "fstab: ", 7);
+ (void)write(STDERR_FILENO, _PATH_FSTAB, sizeof(_PATH_FSTAB) - 1);
+ (void)write(STDERR_FILENO, ": ", 1);
+ p = strerror(err);
+ (void)write(STDERR_FILENO, p, strlen(p));
+ (void)write(STDERR_FILENO, "\n", 1);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1989, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Guido van Rossum.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#if defined(LIBC_SCCS) && !defined(lint)
+static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93";
+#endif /* LIBC_SCCS and not lint */
+
+/*
+ * glob(3) -- a superset of the one defined in POSIX 1003.2.
+ *
+ * The [!...] convention to negate a range is supported (SysV, Posix, ksh).
+ *
+ * Optional extra services, controlled by flags not defined by POSIX:
+ *
+ * GLOB_QUOTE:
+ * Escaping convention: \ inhibits any special meaning the following
+ * character might have (except \ at end of string is retained).
+ * GLOB_MAGCHAR:
+ * Set in gl_flags if pattern contained a globbing character.
+ * GLOB_NOMAGIC:
+ * Same as GLOB_NOCHECK, but it will only append pattern if it did
+ * not contain any magic characters. [Used in csh style globbing]
+ * GLOB_ALTDIRFUNC:
+ * Use alternately specified directory access functions.
+ * GLOB_TILDE:
+ * expand ~user/foo to the /home/dir/of/user/foo
+ * GLOB_BRACE:
+ * expand {1,2}{a,b} to 1a 1b 2a 2b
+ * gl_matchc:
+ * Number of matches in the current invocation of glob.
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <glob.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#define DOLLAR '$'
+#define DOT '.'
+#define EOS '\0'
+#define LBRACKET '['
+#define NOT '!'
+#define QUESTION '?'
+#define QUOTE '\\'
+#define RANGE '-'
+#define RBRACKET ']'
+#define SEP '/'
+#define STAR '*'
+#define TILDE '~'
+#define UNDERSCORE '_'
+#define LBRACE '{'
+#define RBRACE '}'
+#define SLASH '/'
+#define COMMA ','
+
+#ifndef DEBUG
+
+#define M_QUOTE 0x8000
+#define M_PROTECT 0x4000
+#define M_MASK 0xffff
+#define M_ASCII 0x00ff
+
+typedef u_short Char;
+
+#else
+
+#define M_QUOTE 0x80
+#define M_PROTECT 0x40
+#define M_MASK 0xff
+#define M_ASCII 0x7f
+
+typedef char Char;
+
+#endif
+
+
+#define CHAR(c) ((Char)((c)&M_ASCII))
+#define META(c) ((Char)((c)|M_QUOTE))
+#define M_ALL META('*')
+#define M_END META(']')
+#define M_NOT META('!')
+#define M_ONE META('?')
+#define M_RNG META('-')
+#define M_SET META('[')
+#define ismeta(c) (((c)&M_QUOTE) != 0)
+
+
+static int compare __P((const void *, const void *));
+static void g_Ctoc __P((const Char *, char *));
+static int g_lstat __P((Char *, struct stat *, glob_t *));
+static DIR *g_opendir __P((Char *, glob_t *));
+static Char *g_strchr __P((Char *, int));
+#ifdef notdef
+static Char *g_strcat __P((Char *, const Char *));
+#endif
+static int g_stat __P((Char *, struct stat *, glob_t *));
+static int glob0 __P((const Char *, glob_t *));
+static int glob1 __P((Char *, glob_t *));
+static int glob2 __P((Char *, Char *, Char *, glob_t *));
+static int glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
+static int globextend __P((const Char *, glob_t *));
+static const Char * globtilde __P((const Char *, Char *, glob_t *));
+static int globexp1 __P((const Char *, glob_t *));
+static int globexp2 __P((const Char *, const Char *, glob_t *, int *));
+static int match __P((Char *, Char *, Char *));
+#ifdef DEBUG
+static void qprintf __P((const char *, Char *));
+#endif
+
+int
+glob(pattern, flags, errfunc, pglob)
+ const char *pattern;
+ int flags, (*errfunc) __P((const char *, int));
+ glob_t *pglob;
+{
+ const u_char *patnext;
+ int c;
+ Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
+
+ patnext = (u_char *) pattern;
+ if (!(flags & GLOB_APPEND)) {
+ pglob->gl_pathc = 0;
+ pglob->gl_pathv = NULL;
+ if (!(flags & GLOB_DOOFFS))
+ pglob->gl_offs = 0;
+ }
+ pglob->gl_flags = flags & ~GLOB_MAGCHAR;
+ pglob->gl_errfunc = errfunc;
+ pglob->gl_matchc = 0;
+
+ bufnext = patbuf;
+ bufend = bufnext + MAXPATHLEN;
+ if (flags & GLOB_QUOTE) {
+ /* Protect the quoted characters. */
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ if (c == QUOTE) {
+ if ((c = *patnext++) == EOS) {
+ c = QUOTE;
+ --patnext;
+ }
+ *bufnext++ = c | M_PROTECT;
+ }
+ else
+ *bufnext++ = c;
+ }
+ else
+ while (bufnext < bufend && (c = *patnext++) != EOS)
+ *bufnext++ = c;
+ *bufnext = EOS;
+
+ if (flags & GLOB_BRACE)
+ return globexp1(patbuf, pglob);
+ else
+ return glob0(patbuf, pglob);
+}
+
+/*
+ * Expand recursively a glob {} pattern. When there is no more expansion
+ * invoke the standard globbing routine to glob the rest of the magic
+ * characters
+ */
+static int globexp1(pattern, pglob)
+ const Char *pattern;
+ glob_t *pglob;
+{
+ const Char* ptr = pattern;
+ int rv;
+
+ /* Protect a single {}, for find(1), like csh */
+ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS)
+ return glob0(pattern, pglob);
+
+ while ((ptr = (const Char *) g_strchr((Char *) ptr, LBRACE)) != NULL)
+ if (!globexp2(ptr, pattern, pglob, &rv))
+ return rv;
+
+ return glob0(pattern, pglob);
+}
+
+
+/*
+ * Recursive brace globbing helper. Tries to expand a single brace.
+ * If it succeeds then it invokes globexp1 with the new pattern.
+ * If it fails then it tries to glob the rest of the pattern and returns.
+ */
+static int globexp2(ptr, pattern, pglob, rv)
+ const Char *ptr, *pattern;
+ glob_t *pglob;
+ int *rv;
+{
+ int i;
+ Char *lm, *ls;
+ const Char *pe, *pm, *pl;
+ Char patbuf[MAXPATHLEN + 1];
+
+ /* copy part up to the brace */
+ for (lm = patbuf, pm = pattern; pm != ptr; *lm++ = *pm++)
+ continue;
+ ls = lm;
+
+ /* Find the balanced brace */
+ for (i = 0, pe = ++ptr; *pe; pe++)
+ if (*pe == LBRACKET) {
+ /* Ignore everything between [] */
+ for (pm = pe++; *pe != RBRACKET && *pe != EOS; pe++)
+ continue;
+ if (*pe == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pe = pm;
+ }
+ }
+ else if (*pe == LBRACE)
+ i++;
+ else if (*pe == RBRACE) {
+ if (i == 0)
+ break;
+ i--;
+ }
+
+ /* Non matching braces; just glob the pattern */
+ if (i != 0 || *pe == EOS) {
+ *rv = glob0(patbuf, pglob);
+ return 0;
+ }
+
+ for (i = 0, pl = pm = ptr; pm <= pe; pm++)
+ switch (*pm) {
+ case LBRACKET:
+ /* Ignore everything between [] */
+ for (pl = pm++; *pm != RBRACKET && *pm != EOS; pm++)
+ continue;
+ if (*pm == EOS) {
+ /*
+ * We could not find a matching RBRACKET.
+ * Ignore and just look for RBRACE
+ */
+ pm = pl;
+ }
+ break;
+
+ case LBRACE:
+ i++;
+ break;
+
+ case RBRACE:
+ if (i) {
+ i--;
+ break;
+ }
+ /* FALLTHROUGH */
+ case COMMA:
+ if (i && *pm == COMMA)
+ break;
+ else {
+ /* Append the current string */
+ for (lm = ls; (pl < pm); *lm++ = *pl++)
+ continue;
+ /*
+ * Append the rest of the pattern after the
+ * closing brace
+ */
+ for (pl = pe + 1; (*lm++ = *pl++) != EOS;)
+ continue;
+
+ /* Expand the current pattern */
+#ifdef DEBUG
+ qprintf("globexp2:", patbuf);
+#endif
+ *rv = globexp1(patbuf, pglob);
+
+ /* move after the comma, to the next string */
+ pl = pm + 1;
+ }
+ break;
+
+ default:
+ break;
+ }
+ *rv = 0;
+ return 0;
+}
+
+
+
+/*
+ * expand tilde from the passwd file.
+ */
+static const Char *
+globtilde(pattern, patbuf, pglob)
+ const Char *pattern;
+ Char *patbuf;
+ glob_t *pglob;
+{
+ struct passwd *pwd;
+ char *h;
+ const Char *p;
+ Char *b;
+
+ if (*pattern != TILDE || !(pglob->gl_flags & GLOB_TILDE))
+ return pattern;
+
+ /* Copy up to the end of the string or / */
+ for (p = pattern + 1, h = (char *) patbuf; *p && *p != SLASH;
+ *h++ = *p++)
+ continue;
+
+ *h = EOS;
+
+ if (((char *) patbuf)[0] == EOS) {
+ /*
+ * handle a plain ~ or ~/ by expanding $HOME
+ * first and then trying the password file
+ */
+ if ((h = getenv("HOME")) == NULL) {
+ if ((pwd = getpwuid(getuid())) == NULL)
+ return pattern;
+ else
+ h = pwd->pw_dir;
+ }
+ }
+ else {
+ /*
+ * Expand a ~user
+ */
+ if ((pwd = getpwnam((char*) patbuf)) == NULL)
+ return pattern;
+ else
+ h = pwd->pw_dir;
+ }
+
+ /* Copy the home directory */
+ for (b = patbuf; *h; *b++ = *h++)
+ continue;
+
+ /* Append the rest of the pattern */
+ while ((*b++ = *p++) != EOS)
+ continue;
+
+ return patbuf;
+}
+
+
+/*
+ * The main glob() routine: compiles the pattern (optionally processing
+ * quotes), calls glob1() to do the real pattern matching, and finally
+ * sorts the list (unless unsorted operation is requested). Returns 0
+ * if things went well, nonzero if errors occurred. It is not an error
+ * to find no matches.
+ */
+static int
+glob0(pattern, pglob)
+ const Char *pattern;
+ glob_t *pglob;
+{
+ const Char *qpatnext;
+ int c, err, oldpathc;
+ Char *bufnext, patbuf[MAXPATHLEN+1];
+
+ qpatnext = globtilde(pattern, patbuf, pglob);
+ oldpathc = pglob->gl_pathc;
+ bufnext = patbuf;
+
+ /* We don't need to check for buffer overflow any more. */
+ while ((c = *qpatnext++) != EOS) {
+ switch (c) {
+ case LBRACKET:
+ c = *qpatnext;
+ if (c == NOT)
+ ++qpatnext;
+ if (*qpatnext == EOS ||
+ g_strchr((Char *) qpatnext+1, RBRACKET) == NULL) {
+ *bufnext++ = LBRACKET;
+ if (c == NOT)
+ --qpatnext;
+ break;
+ }
+ *bufnext++ = M_SET;
+ if (c == NOT)
+ *bufnext++ = M_NOT;
+ c = *qpatnext++;
+ do {
+ *bufnext++ = CHAR(c);
+ if (*qpatnext == RANGE &&
+ (c = qpatnext[1]) != RBRACKET) {
+ *bufnext++ = M_RNG;
+ *bufnext++ = CHAR(c);
+ qpatnext += 2;
+ }
+ } while ((c = *qpatnext++) != RBRACKET);
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_END;
+ break;
+ case QUESTION:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ *bufnext++ = M_ONE;
+ break;
+ case STAR:
+ pglob->gl_flags |= GLOB_MAGCHAR;
+ /* collapse adjacent stars to one,
+ * to avoid exponential behavior
+ */
+ if (bufnext == patbuf || bufnext[-1] != M_ALL)
+ *bufnext++ = M_ALL;
+ break;
+ default:
+ *bufnext++ = CHAR(c);
+ break;
+ }
+ }
+ *bufnext = EOS;
+#ifdef DEBUG
+ qprintf("glob0:", patbuf);
+#endif
+
+ if ((err = glob1(patbuf, pglob)) != 0)
+ return(err);
+
+ /*
+ * If there was no match we are going to append the pattern
+ * if GLOB_NOCHECK was specified or if GLOB_NOMAGIC was specified
+ * and the pattern did not contain any magic characters
+ * GLOB_NOMAGIC is there just for compatibility with csh.
+ */
+ if (pglob->gl_pathc == oldpathc &&
+ ((pglob->gl_flags & GLOB_NOCHECK) ||
+ ((pglob->gl_flags & GLOB_NOMAGIC) &&
+ !(pglob->gl_flags & GLOB_MAGCHAR))))
+ return(globextend(pattern, pglob));
+ else if (!(pglob->gl_flags & GLOB_NOSORT))
+ qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
+ pglob->gl_pathc - oldpathc, sizeof(char *), compare);
+ return(0);
+}
+
+static int
+compare(p, q)
+ const void *p, *q;
+{
+ return(strcmp(*(char **)p, *(char **)q));
+}
+
+static int
+glob1(pattern, pglob)
+ Char *pattern;
+ glob_t *pglob;
+{
+ Char pathbuf[MAXPATHLEN+1];
+
+ /* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
+ if (*pattern == EOS)
+ return(0);
+ return(glob2(pathbuf, pathbuf, pattern, pglob));
+}
+
+/*
+ * The functions glob2 and glob3 are mutually recursive; there is one level
+ * of recursion for each segment in the pattern that contains one or more
+ * meta characters.
+ */
+static int
+glob2(pathbuf, pathend, pattern, pglob)
+ Char *pathbuf, *pathend, *pattern;
+ glob_t *pglob;
+{
+ struct stat sb;
+ Char *p, *q;
+ int anymeta;
+
+ /*
+ * Loop over pattern segments until end of pattern or until
+ * segment with meta character found.
+ */
+ for (anymeta = 0;;) {
+ if (*pattern == EOS) { /* End of pattern? */
+ *pathend = EOS;
+ if (g_lstat(pathbuf, &sb, pglob))
+ return(0);
+
+ if (((pglob->gl_flags & GLOB_MARK) &&
+ pathend[-1] != SEP) && (S_ISDIR(sb.st_mode)
+ || (S_ISLNK(sb.st_mode) &&
+ (g_stat(pathbuf, &sb, pglob) == 0) &&
+ S_ISDIR(sb.st_mode)))) {
+ *pathend++ = SEP;
+ *pathend = EOS;
+ }
+ ++pglob->gl_matchc;
+ return(globextend(pathbuf, pglob));
+ }
+
+ /* Find end of next segment, copy tentatively to pathend. */
+ q = pathend;
+ p = pattern;
+ while (*p != EOS && *p != SEP) {
+ if (ismeta(*p))
+ anymeta = 1;
+ *q++ = *p++;
+ }
+
+ if (!anymeta) { /* No expansion, do next segment. */
+ pathend = q;
+ pattern = p;
+ while (*pattern == SEP)
+ *pathend++ = *pattern++;
+ } else /* Need expansion, recurse. */
+ return(glob3(pathbuf, pathend, pattern, p, pglob));
+ }
+ /* NOTREACHED */
+}
+
+static int
+glob3(pathbuf, pathend, pattern, restpattern, pglob)
+ Char *pathbuf, *pathend, *pattern, *restpattern;
+ glob_t *pglob;
+{
+ register struct dirent *dp;
+ DIR *dirp;
+ int err;
+ char buf[MAXPATHLEN];
+
+ /*
+ * The readdirfunc declaration can't be prototyped, because it is
+ * assigned, below, to two functions which are prototyped in glob.h
+ * and dirent.h as taking pointers to differently typed opaque
+ * structures.
+ */
+ struct dirent *(*readdirfunc)();
+
+ *pathend = EOS;
+ errno = 0;
+
+ if ((dirp = g_opendir(pathbuf, pglob)) == NULL) {
+ /* TODO: don't call for ENOENT or ENOTDIR? */
+ if (pglob->gl_errfunc) {
+ g_Ctoc(pathbuf, buf);
+ if (pglob->gl_errfunc(buf, errno) ||
+ pglob->gl_flags & GLOB_ERR)
+ return (GLOB_ABEND);
+ }
+ return(0);
+ }
+
+ err = 0;
+
+ /* Search directory for matching names. */
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ readdirfunc = pglob->gl_readdir;
+ else
+ readdirfunc = readdir;
+ while ((dp = (*readdirfunc)(dirp))) {
+ register u_char *sc;
+ register Char *dc;
+
+ /* Initial DOT must be matched literally. */
+ if (dp->d_name[0] == DOT && *pattern != DOT)
+ continue;
+ for (sc = (u_char *) dp->d_name, dc = pathend;
+ (*dc++ = *sc++) != EOS;)
+ continue;
+ if (!match(pathend, pattern, restpattern)) {
+ *pathend = EOS;
+ continue;
+ }
+ err = glob2(pathbuf, --dc, restpattern, pglob);
+ if (err)
+ break;
+ }
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ (*pglob->gl_closedir)(dirp);
+ else
+ closedir(dirp);
+ return(err);
+}
+
+
+/*
+ * Extend the gl_pathv member of a glob_t structure to accomodate a new item,
+ * add the new item, and update gl_pathc.
+ *
+ * This assumes the BSD realloc, which only copies the block when its size
+ * crosses a power-of-two boundary; for v7 realloc, this would cause quadratic
+ * behavior.
+ *
+ * Return 0 if new item added, error code if memory couldn't be allocated.
+ *
+ * Invariant of the glob_t structure:
+ * Either gl_pathc is zero and gl_pathv is NULL; or gl_pathc > 0 and
+ * gl_pathv points to (gl_offs + gl_pathc + 1) items.
+ */
+static int
+globextend(path, pglob)
+ const Char *path;
+ glob_t *pglob;
+{
+ register char **pathv;
+ register int i;
+ u_int newsize;
+ char *copy;
+ const Char *p;
+
+ newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
+ pathv = pglob->gl_pathv ?
+ realloc((char *)pglob->gl_pathv, newsize) :
+ malloc(newsize);
+ if (pathv == NULL)
+ return(GLOB_NOSPACE);
+
+ if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) {
+ /* first time around -- clear initial gl_offs items */
+ pathv += pglob->gl_offs;
+ for (i = pglob->gl_offs; --i >= 0; )
+ *--pathv = NULL;
+ }
+ pglob->gl_pathv = pathv;
+
+ for (p = path; *p++;)
+ continue;
+ if ((copy = malloc(p - path)) != NULL) {
+ g_Ctoc(path, copy);
+ pathv[pglob->gl_offs + pglob->gl_pathc++] = copy;
+ }
+ pathv[pglob->gl_offs + pglob->gl_pathc] = NULL;
+ return(copy == NULL ? GLOB_NOSPACE : 0);
+}
+
+
+/*
+ * pattern matching function for filenames. Each occurrence of the *
+ * pattern causes a recursion level.
+ */
+static int
+match(name, pat, patend)
+ register Char *name, *pat, *patend;
+{
+ int ok, negate_range;
+ Char c, k;
+
+ while (pat < patend) {
+ c = *pat++;
+ switch (c & M_MASK) {
+ case M_ALL:
+ if (pat == patend)
+ return(1);
+ do
+ if (match(name, pat, patend))
+ return(1);
+ while (*name++ != EOS);
+ return(0);
+ case M_ONE:
+ if (*name++ == EOS)
+ return(0);
+ break;
+ case M_SET:
+ ok = 0;
+ if ((k = *name++) == EOS)
+ return(0);
+ if ((negate_range = ((*pat & M_MASK) == M_NOT)) != EOS)
+ ++pat;
+ while (((c = *pat++) & M_MASK) != M_END)
+ if ((*pat & M_MASK) == M_RNG) {
+ if (c <= k && k <= pat[1])
+ ok = 1;
+ pat += 2;
+ } else if (c == k)
+ ok = 1;
+ if (ok == negate_range)
+ return(0);
+ break;
+ default:
+ if (*name++ != c)
+ return(0);
+ break;
+ }
+ }
+ return(*name == EOS);
+}
+
+/* Free allocated data belonging to a glob_t structure. */
+void
+globfree(pglob)
+ glob_t *pglob;
+{
+ register int i;
+ register char **pp;
+
+ if (pglob->gl_pathv != NULL) {
+ pp = pglob->gl_pathv + pglob->gl_offs;
+ for (i = pglob->gl_pathc; i--; ++pp)
+ if (*pp)
+ free(*pp);
+ free(pglob->gl_pathv);
+ }
+}
+
+static DIR *
+g_opendir(str, pglob)
+ register Char *str;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ if (!*str)
+ strcpy(buf, ".");
+ else
+ g_Ctoc(str, buf);
+
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_opendir)(buf));
+
+ return(opendir(buf));
+}
+
+static int
+g_lstat(fn, sb, pglob)
+ register Char *fn;
+ struct stat *sb;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ g_Ctoc(fn, buf);
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_lstat)(buf, sb));
+ return(lstat(buf, sb));
+}
+
+static int
+g_stat(fn, sb, pglob)
+ register Char *fn;
+ struct stat *sb;
+ glob_t *pglob;
+{
+ char buf[MAXPATHLEN];
+
+ g_Ctoc(fn, buf);
+ if (pglob->gl_flags & GLOB_ALTDIRFUNC)
+ return((*pglob->gl_stat)(buf, sb));
+ return(stat(buf, sb));
+}
+
+static Char *
+g_strchr(str, ch)
+ Char *str;
+ int ch;
+{
+ do {
+ if (*str == ch)
+ return (str);
+ } while (*str++);
+ return (NULL);
+}
+
+#ifdef notdef
+static Char *
+g_strcat(dst, src)
+ Char *dst;
+ const Char* src;
+{
+ Char *sdst = dst;
+
+ while (*dst++)
+ continue;
+ --dst;
+ while((*dst++ = *src++) != EOS)
+ continue;
+
+ return (sdst);
+}
+#endif
+
+static void
+g_Ctoc(str, buf)
+ register const Char *str;
+ char *buf;
+{
+ register char *dc;
+
+ for (dc = buf; (*dc++ = *str++) != EOS;)
+ continue;
+}
+
+#ifdef DEBUG
+static void
+qprintf(str, s)
+ const char *str;
+ register Char *s;
+{
+ register Char *p;
+
+ (void)printf("%s:\n", str);
+ for (p = s; *p; p++)
+ (void)printf("%c", CHAR(*p));
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", *p & M_PROTECT ? '"' : ' ');
+ (void)printf("\n");
+ for (p = s; *p; p++)
+ (void)printf("%c", ismeta(*p) ? '_' : ' ');
+ (void)printf("\n");
+}
+#endif
--- /dev/null
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright (C) 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+#
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Written by Per Bothner <bothner@cygnus.com>.
+# The master version of this file is at the FSF in /home/gd/gnu/lib.
+#
+# This script attempts to guess a canonical system name similar to
+# config.sub. If it succeeds, it prints the system name on stdout, and
+# exits with 0. Otherwise, it exits with 1.
+#
+# The plan is that this can be called by configure scripts if you
+# don't specify an explicit system type (host/target name).
+#
+# Only a few systems have been added to this list; please add others
+# (but try to keep the structure clean).
+#
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 8/24/94.)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+trap 'rm -f dummy.c dummy.o dummy; exit 1' 1 2 15
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ alpha:OSF1:V*:*)
+ # After 1.2, OSF1 uses "V1.3" for uname -r.
+ echo alpha-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^V//'`
+ exit 0 ;;
+ alpha:OSF1:*:*)
+ # 1.2 uses "1.2" for uname -r.
+ echo alpha-dec-osf${UNAME_RELEASE}
+ exit 0 ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit 0 ;;
+ amiga:NetBSD:*:*)
+ echo m68k-cbm-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit 0;;
+ Pyramid*:OSx*:*:*)
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit 0 ;;
+ sun4*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ i86pc:SunOS:5.*:*)
+ echo i386-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit 0 ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit 0 ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit 0 ;;
+ atari*:NetBSD:*:*)
+ echo m68k-atari-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ sun3*:NetBSD:*:*)
+ echo m68k-sun-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ mac68k:NetBSD:*:*)
+ echo m68k-apple-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit 0 ;;
+ mips:*:4*:UMIPS)
+ echo mips-mips-riscos4sysv
+ exit 0 ;;
+ mips:*:5*:RISCos)
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit 0 ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit 0 ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit 0 ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ AViiON:dgux:*:*)
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx \
+ -o ${TARGET_BINARY_INTERFACE}x = x ] ; then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit 0 ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit 0 ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit 0 ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit 0 ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit 0 ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit 0 ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i[34]86:AIX:*:*)
+ echo i386-ibm-aix
+ exit 0 ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ sed 's/^ //' << EOF >dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo rs6000-ibm-aix3.2.5
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit 0 ;;
+ *:AIX:*:4)
+ if /usr/sbin/lsattr -EHl proc0 | grep POWER >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=4.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit 0 ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit 0 ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit 0 ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC NetBSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit 0 ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit 0 ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit 0 ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit 0 ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit 0 ;;
+ 9000/[3478]??:HP-UX:*:*)
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/7?? | 9000/8?[79] ) HP_ARCH=hppa1.1 ;;
+ 9000/8?? ) HP_ARCH=hppa1.0 ;;
+ esac
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit 0 ;;
+ 3050*:HI-UX:*:*)
+ sed 's/^ //' << EOF >dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ ${CC-cc} dummy.c -o dummy && ./dummy && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ echo unknown-hitachi-hiuxwe2
+ exit 0 ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit 0 ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit 0 ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit 0 ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit 0 ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit 0 ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ CRAY*X-MP:*:*:*)
+ echo xmp-cray-unicos
+ exit 0 ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY*C90:*:*:*)
+ echo c90-cray-unicos${UNAME_RELEASE}
+ exit 0 ;;
+ CRAY-2:*:*:*)
+ echo cray2-cray-unicos
+ exit 0 ;;
+ hp3[0-9][05]:NetBSD:*:*)
+ echo m68k-hp-netbsd${UNAME_RELEASE}
+ exit 0 ;;
+ i[34]86:BSD/386:*:* | *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit 0 ;;
+ *:FreeBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit 0 ;;
+ *:NetBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-netbsd`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ exit 0 ;;
+ *:GNU:*:*)
+ echo `echo ${UNAME_MACHINE}|sed -e 's,/.*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit 0 ;;
+ *:Linux:*:*)
+ # The BFD linker knows what the default object file format is, so
+ # first see if it will tell us.
+ ld_help_string=`ld --help 2>&1`
+ if echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: elf_i[345]86"; then
+ echo "${UNAME_MACHINE}-unknown-linux" ; exit 0
+ elif echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86linux"; then
+ echo "${UNAME_MACHINE}-unknown-linuxaout" ; exit 0
+ elif echo $ld_help_string | grep >/dev/null 2>&1 "supported emulations: i[345]86coff"; then
+ echo "${UNAME_MACHINE}-unknown-linuxcoff" ; exit 0
+ elif test "${UNAME_MACHINE}" = "alpha" ; then
+ echo alpha-unknown-linux ; exit 0
+ else
+ # Either a pre-BFD a.out linker (linuxoldld) or one that does not give us
+ # useful --help. Gcc wants to distinguish between linuxoldld and linuxaout.
+ test ! -d /usr/lib/ldscripts/. \
+ && echo "${UNAME_MACHINE}-unknown-linuxoldld" && exit 0
+ # Determine whether the default compiler is a.out or elf
+ cat >dummy.c <<EOF
+main(argc, argv)
+int argc;
+char *argv[];
+{
+#ifdef __ELF__
+ printf ("%s-unknown-linux\n", argv[1]);
+#else
+ printf ("%s-unknown-linuxaout\n", argv[1]);
+#endif
+ return 0;
+}
+EOF
+ ${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy "${UNAME_MACHINE}" && rm dummy.c dummy && exit 0
+ rm -f dummy.c dummy
+ fi ;;
+# ptx 4.0 does uname -s correctly, with DYNIX/ptx in there. earlier versions
+# are messed up and put the nodename in both sysname and nodename.
+ i[34]86:DYNIX/ptx:4*:*)
+ echo i386-sequent-sysv4
+ exit 0 ;;
+ i[34]86:*:4.*:* | i[34]86:SYSTEM_V:4.*:*)
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_RELEASE}
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit 0 ;;
+ i[34]86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-unknown-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|egrep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|egrep i80486 >/dev/null) && UNAME_MACHINE=i486
+ echo ${UNAME_MACHINE}-unknown-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-unknown-sysv32
+ fi
+ exit 0 ;;
+ Intel:Mach:3*:*)
+ echo i386-unknown-mach3
+ exit 0 ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit 0 ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit 0 ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit 0 ;;
+ M680[234]0:*:R3V[567]*:*)
+ test -r /sysV68 && echo 'm68k-motorola-sysv' && exit 0 ;;
+ 3[34]??:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4.3 && exit 0 ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ uname -p 2>/dev/null | grep 86 >/dev/null \
+ && echo i486-ncr-sysv4 && exit 0 ;;
+ m680[234]0:LynxOS:2.[23]*:*)
+ echo m68k-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit 0 ;;
+ i[34]86:LynxOS:2.[23]*:*)
+ echo i386-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ TSUNAMI:LynxOS:2.[23]*:*)
+ echo sparc-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ rs6000:LynxOS:2.[23]*:*)
+ echo rs6000-lynx-lynxos${UNAME_RELEASE}
+ exit 0 ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit 0 ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit 0 ;;
+esac
+
+#echo '(No uname command or uname output not recognized.)' 1>&2
+#echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2
+
+cat >dummy.c <<EOF
+#ifdef _SEQUENT_
+# include <sys/types.h>
+# include <sys/utsname.h>
+#endif
+main ()
+{
+#if defined (sony)
+#if defined (MIPSEB)
+ /* BFD wants "bsd" instead of "newsos". Perhaps BFD should be changed,
+ I don't know.... */
+ printf ("mips-sony-bsd\n"); exit (0);
+#else
+#include <sys/param.h>
+ printf ("m68k-sony-newsos%s\n",
+#ifdef NEWSOS4
+ "4"
+#else
+ ""
+#endif
+ ); exit (0);
+#endif
+#endif
+
+#if defined (__arm) && defined (__acorn) && defined (__unix)
+ printf ("arm-acorn-riscix"); exit (0);
+#endif
+
+#if defined (hp300) && !defined (hpux)
+ printf ("m68k-hp-bsd\n"); exit (0);
+#endif
+
+#if defined (NeXT)
+#if !defined (__ARCHITECTURE__)
+#define __ARCHITECTURE__ "m68k"
+#endif
+ int version;
+ version=`(hostinfo | sed -n 's/.*NeXT Mach \([0-9]*\).*/\1/p') 2>/dev/null`;
+ printf ("%s-next-nextstep%s\n", __ARCHITECTURE__, version==2 ? "2" : "3");
+ exit (0);
+#endif
+
+#if defined (MULTIMAX) || defined (n16)
+#if defined (UMAXV)
+ printf ("ns32k-encore-sysv\n"); exit (0);
+#else
+#if defined (CMU)
+ printf ("ns32k-encore-mach\n"); exit (0);
+#else
+ printf ("ns32k-encore-bsd\n"); exit (0);
+#endif
+#endif
+#endif
+
+#if defined (__386BSD__)
+ printf ("i386-unknown-bsd\n"); exit (0);
+#endif
+
+#if defined (sequent)
+#if defined (i386)
+ printf ("i386-sequent-dynix\n"); exit (0);
+#endif
+#if defined (ns32000)
+ printf ("ns32k-sequent-dynix\n"); exit (0);
+#endif
+#endif
+
+#if defined (_SEQUENT_)
+ struct utsname un;
+
+ uname(&un);
+
+ if (strncmp(un.version, "V2", 2) == 0) {
+ printf ("i386-sequent-ptx2\n"); exit (0);
+ }
+ if (strncmp(un.version, "V1", 2) == 0) { /* XXX is V1 correct? */
+ printf ("i386-sequent-ptx1\n"); exit (0);
+ }
+ printf ("i386-sequent-ptx\n"); exit (0);
+
+#endif
+
+#if defined (vax)
+#if !defined (ultrix)
+ printf ("vax-dec-bsd\n"); exit (0);
+#else
+ printf ("vax-dec-ultrix\n"); exit (0);
+#endif
+#endif
+
+#if defined (alliant) && defined (i860)
+ printf ("i860-alliant-bsd\n"); exit (0);
+#endif
+
+ exit (1);
+}
+EOF
+
+${CC-cc} dummy.c -o dummy 2>/dev/null && ./dummy && rm dummy.c dummy && exit 0
+rm -f dummy.c dummy
+
+# Apollos put the system type in the environment.
+
+test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit 0; }
+
+# Convex versions that predate uname can use getsysinfo(1)
+
+if [ -x /usr/convex/getsysinfo ]
+then
+ case `getsysinfo -f cpu_type` in
+ c1*)
+ echo c1-convex-bsd
+ exit 0 ;;
+ c2*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit 0 ;;
+ c34*)
+ echo c34-convex-bsd
+ exit 0 ;;
+ c38*)
+ echo c38-convex-bsd
+ exit 0 ;;
+ c4*)
+ echo c4-convex-bsd
+ exit 0 ;;
+ esac
+fi
+
+#echo '(Unable to guess system type)' 1>&2
+
+exit 1
--- /dev/null
+/* config.h.in. Generated automatically from configure.in by autoheader. */
+
+/* Define if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to __s64 if <sys/types.h> does not define */
+#undef quad_t
+
+/* Define to __u64 if <sys/types.h> does not define */
+#undef u_quad_t
+
+/* Define if you have the err function. */
+#undef HAVE_ERR
+
+/* Define if you have the errx function. */
+#undef HAVE_ERRX
+
+/* Define if you have the realpath function. */
+#undef HAVE_REALPATH
+
+/* Define if you have the verr function. */
+#undef HAVE_VERR
+
+/* Define if you have the verrx function. */
+#undef HAVE_VERRX
+
+/* Define if you have the vwarn function. */
+#undef HAVE_VWARN
+
+/* Define if you have the vwarnx function. */
+#undef HAVE_VWARNX
+
+/* Define if you have the warn function. */
+#undef HAVE_WARN
+
+/* Define if you have the warnx function. */
+#undef HAVE_WARNX
--- /dev/null
+#! /bin/sh
+# Configuration validation subroutine script, version 1.1.
+# Copyright (C) 1991, 1992, 1993, 1994, 1995 Free Software Foundation, Inc.
+# This file is (in principle) common to ALL GNU software.
+# The presence of a machine in this file suggests that SOME GNU software
+# can handle that machine. It does not imply ALL GNU software can.
+#
+# This file is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+if [ x$1 = x ]
+then
+ echo Configuration name missing. 1>&2
+ echo "Usage: $0 CPU-MFR-OPSYS" 1>&2
+ echo "or $0 ALIAS" 1>&2
+ echo where ALIAS is a recognized configuration type. 1>&2
+ exit 1
+fi
+
+# First pass through any local machine types.
+case $1 in
+ *local*)
+ echo $1
+ exit 0
+ ;;
+ *)
+ ;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS (if any).
+basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+if [ $basic_machine != $1 ]
+then os=`echo $1 | sed 's/.*-/-/'`
+else os=; fi
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp )
+ os=
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-unknown/'`
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ tahoe | i[345]86 | i860 | m68k | m68000 | m88k | ns32k | arm \
+ | arme[lb] | pyramid \
+ | tron | a29k | 580 | i960 | h8300 | hppa1.0 | hppa1.1 \
+ | alpha | we32k | ns16k | clipper | sparclite | i370 | sh \
+ | powerpc | powerpcle | sparc64 | 1750a | dsp16xx | mips64 | mipsel \
+ | pdp11 | mips64el | mips64orion | mips64orionel \
+ | sparc)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ vax-* | tahoe-* | i[345]86-* | i860-* | m68k-* | m68000-* | m88k-* \
+ | sparc-* | ns32k-* | fx80-* | arm-* | c[123]* \
+ | mips-* | pyramid-* | tron-* | a29k-* | romp-* | rs6000-* | power-* \
+ | none-* | 580-* | cray2-* | h8300-* | i960-* | xmp-* | ymp-* \
+ | hppa1.0-* | hppa1.1-* | alpha-* | we32k-* | cydra-* | ns16k-* \
+ | pn-* | np1-* | xps100-* | clipper-* | orion-* | sparclite-* \
+ | pdp11-* | sh-* | powerpc-* | powerpcle-* | sparc64-* | mips64-* | mipsel-* \
+ | mips64el-* | mips64orion-* | mips64orionel-*)
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-cbm
+ ;;
+ amigados)
+ basic_machine=m68k-cbm
+ os=-amigados
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-cbm
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ cray2)
+ basic_machine=cray2-cray
+ os=-unicos
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k7[0-9][0-9] | hp7[0-9][0-9] | hp9k8[0-9]7 | hp8[0-9]7)
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+# I'm not sure what "Sysv32" means. Should this be sysv3.2?
+ i[345]86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv32
+ ;;
+ i[345]86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv4
+ ;;
+ i[345]86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-sysv
+ ;;
+ i[345]86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-unknown/'`
+ os=-solaris2
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pentium | p5 | p6)
+ # We don't have specific support for the Intel Pentium (p6) followon yet, so just call it a Pentium
+ basic_machine=i586-intel
+ ;;
+ pentium-* | p5-* | p6-*)
+ # We don't have specific support for the Intel Pentium (p6) followon yet, so just call it a Pentium
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ k5)
+ # We don't have specific support for AMD's K5 yet, so just call it a Pentium
+ basic_machine=i586-amd
+ ;;
+ nexen)
+ # We don't have specific support for Nexgen yet, so just call it a Pentium
+ basic_machine=i586-nexgen
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=rs6000-ibm
+ ;;
+ ppc) basic_machine=powerpc-unknown
+ ;;
+ ppc-*) basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ xmp)
+ basic_machine=xmp-cray
+ os=-unicos
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ mips)
+ basic_machine=mips-mips
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sparc)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # -solaris* is a basic system type, with this one exception.
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -unixware* | svr4*)
+ os=-sysv4
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -vms* | -sco* | -esix* | -isc* | -aix* | -sunos | -sunos[345]* \
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \
+ | -amigados* | -msdos* | -newsos* | -unicos* | -aos* \
+ | -nindy* | -vxworks* | -ebmon* | -hms* | -mvs* | -clix* \
+ | -riscos* | -linux* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -netbsd* | -freebsd* | -riscix* \
+ | -lynxos* | -bosx* | -nextstep* | -cxux* | -aout* | -elf* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* )
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ # This also exists in the configure program, but was not the
+ # default.
+ # os=-sunos4
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigados
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -lynxos*)
+ vendor=lynx
+ ;;
+ -aix*)
+ vendor=ibm
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -vxworks*)
+ vendor=wrs
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
--- /dev/null
+#! /bin/sh
+
+# Guess values for system-dependent variables and create Makefiles.
+# Generated automatically using autoconf version 2.12
+# Copyright (C) 1992, 93, 94, 95, 96 Free Software Foundation, Inc.
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+
+# Defaults:
+ac_help=
+ac_default_prefix=/usr/local
+# Any additions from configure.in:
+ac_help="$ac_help
+ --enable-dumpdates-patch apply the dumpdates patch from Debian"
+ac_help="$ac_help
+ --enable-debug include debugging code"
+ac_help="$ac_help
+ --enable-static link dump and restore statically"
+ac_help="$ac_help
+ --enable-rmt compile and install rmt"
+ac_help="$ac_help
+ --with-cc=COMPILER select compiler to use"
+ac_help="$ac_help
+ --with-linker=LINKER select linker to use"
+ac_help="$ac_help
+ --with-ccopts=CCOPTS select compiler command line options"
+ac_help="$ac_help
+ --with-ldopts=LDOPTS select linker command line options"
+ac_help="$ac_help
+ --with-binowner=USER select owner for binaries"
+ac_help="$ac_help
+ --with-bingrp=GROUP select group for binaries"
+ac_help="$ac_help
+ --with-binmode=MODE select mode for binaries"
+ac_help="$ac_help
+ --with-manowner=USER select owner for manual pages"
+ac_help="$ac_help
+ --with-mangrp=group select group for manual pages"
+ac_help="$ac_help
+ --with-manmode=MODE select mode for manual pages"
+
+# Initialize some variables set by options.
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+build=NONE
+cache_file=./config.cache
+exec_prefix=NONE
+host=NONE
+no_create=
+nonopt=NONE
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+target=NONE
+verbose=
+x_includes=NONE
+x_libraries=NONE
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datadir='${prefix}/share'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+libdir='${exec_prefix}/lib'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+infodir='${prefix}/info'
+mandir='${prefix}/man'
+
+# Initialize some other variables.
+subdirs=
+MFLAGS= MAKEFLAGS=
+# Maximum number of lines to put in a shell here document.
+ac_max_here_lines=12
+
+ac_prev=
+for ac_option
+do
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval "$ac_prev=\$ac_option"
+ ac_prev=
+ continue
+ fi
+
+ case "$ac_option" in
+ -*=*) ac_optarg=`echo "$ac_option" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) ac_optarg= ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case "$ac_option" in
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir="$ac_optarg" ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build="$ac_optarg" ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file="$ac_optarg" ;;
+
+ -datadir | --datadir | --datadi | --datad | --data | --dat | --da)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=* | --data=* | --dat=* \
+ | --da=*)
+ datadir="$ac_optarg" ;;
+
+ -disable-* | --disable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*disable-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ eval "enable_${ac_feature}=no" ;;
+
+ -enable-* | --enable-*)
+ ac_feature=`echo $ac_option|sed -e 's/-*enable-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_feature| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_feature: invalid feature name" 1>&2; exit 1; }
+ fi
+ ac_feature=`echo $ac_feature| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "enable_${ac_feature}='$ac_optarg'" ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix="$ac_optarg" ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he)
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat << EOF
+Usage: configure [options] [host]
+Options: [defaults in brackets after descriptions]
+Configuration:
+ --cache-file=FILE cache test results in FILE
+ --help print this message
+ --no-create do not create output files
+ --quiet, --silent do not print \`checking...' messages
+ --version print the version of autoconf that created configure
+Directory and file names:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [same as prefix]
+ --bindir=DIR user executables in DIR [EPREFIX/bin]
+ --sbindir=DIR system admin executables in DIR [EPREFIX/sbin]
+ --libexecdir=DIR program executables in DIR [EPREFIX/libexec]
+ --datadir=DIR read-only architecture-independent data in DIR
+ [PREFIX/share]
+ --sysconfdir=DIR read-only single-machine data in DIR [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data in DIR
+ [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data in DIR [PREFIX/var]
+ --libdir=DIR object code libraries in DIR [EPREFIX/lib]
+ --includedir=DIR C header files in DIR [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc in DIR [/usr/include]
+ --infodir=DIR info documentation in DIR [PREFIX/info]
+ --mandir=DIR man documentation in DIR [PREFIX/man]
+ --srcdir=DIR find the sources in DIR [configure dir or ..]
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM
+ run sed PROGRAM on installed program names
+EOF
+ cat << EOF
+Host type:
+ --build=BUILD configure for building on BUILD [BUILD=HOST]
+ --host=HOST configure for HOST [guessed]
+ --target=TARGET configure for TARGET [TARGET=HOST]
+Features and packages:
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --x-includes=DIR X include files are in DIR
+ --x-libraries=DIR X library files are in DIR
+EOF
+ if test -n "$ac_help"; then
+ echo "--enable and --with options recognized:$ac_help"
+ fi
+ exit 0 ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host="$ac_optarg" ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir="$ac_optarg" ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir="$ac_optarg" ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir="$ac_optarg" ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir="$ac_optarg" ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst \
+ | --locals | --local | --loca | --loc | --lo)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* \
+ | --locals=* | --local=* | --loca=* | --loc=* | --lo=*)
+ localstatedir="$ac_optarg" ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir="$ac_optarg" ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir="$ac_optarg" ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix="$ac_optarg" ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix="$ac_optarg" ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix="$ac_optarg" ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name="$ac_optarg" ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir="$ac_optarg" ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir="$ac_optarg" ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site="$ac_optarg" ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir="$ac_optarg" ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir="$ac_optarg" ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target="$ac_optarg" ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers)
+ echo "configure generated by autoconf version 2.12"
+ exit 0 ;;
+
+ -with-* | --with-*)
+ ac_package=`echo $ac_option|sed -e 's/-*with-//' -e 's/=.*//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-_a-zA-Z0-9]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ case "$ac_option" in
+ *=*) ;;
+ *) ac_optarg=yes ;;
+ esac
+ eval "with_${ac_package}='$ac_optarg'" ;;
+
+ -without-* | --without-*)
+ ac_package=`echo $ac_option|sed -e 's/-*without-//'`
+ # Reject names that are not valid shell variable names.
+ if test -n "`echo $ac_package| sed 's/[-a-zA-Z0-9_]//g'`"; then
+ { echo "configure: error: $ac_package: invalid package name" 1>&2; exit 1; }
+ fi
+ ac_package=`echo $ac_package| sed 's/-/_/g'`
+ eval "with_${ac_package}=no" ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes="$ac_optarg" ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries="$ac_optarg" ;;
+
+ -*) { echo "configure: error: $ac_option: invalid option; use --help to show usage" 1>&2; exit 1; }
+ ;;
+
+ *)
+ if test -n "`echo $ac_option| sed 's/[-a-z0-9.]//g'`"; then
+ echo "configure: warning: $ac_option: invalid host type" 1>&2
+ fi
+ if test "x$nonopt" != xNONE; then
+ { echo "configure: error: can only configure for one host and one target at a time" 1>&2; exit 1; }
+ fi
+ nonopt="$ac_option"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ { echo "configure: error: missing argument to --`echo $ac_prev | sed 's/_/-/g'`" 1>&2; exit 1; }
+fi
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+# File descriptor usage:
+# 0 standard input
+# 1 file creation
+# 2 errors and warnings
+# 3 some systems may open it to /dev/tty
+# 4 used on the Kubota Titan
+# 6 checking for... messages and results
+# 5 compiler messages saved in config.log
+if test "$silent" = yes; then
+ exec 6>/dev/null
+else
+ exec 6>&1
+fi
+exec 5>./config.log
+
+echo "\
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+" 1>&5
+
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Also quote any args containing shell metacharacters.
+ac_configure_args=
+for ac_arg
+do
+ case "$ac_arg" in
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c) ;;
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r) ;;
+ *" "*|*" "*|*[\[\]\~\#\$\^\&\*\(\)\{\}\\\|\;\<\>\?]*)
+ ac_configure_args="$ac_configure_args '$ac_arg'" ;;
+ *) ac_configure_args="$ac_configure_args $ac_arg" ;;
+ esac
+done
+
+# NLS nuisances.
+# Only set these to C if already set. These must not be set unconditionally
+# because not all systems understand e.g. LANG=C (notably SCO).
+# Fixing LC_MESSAGES prevents Solaris sh from translating var values in `set'!
+# Non-C LC_CTYPE values break the ctype check.
+if test "${LANG+set}" = set; then LANG=C; export LANG; fi
+if test "${LC_ALL+set}" = set; then LC_ALL=C; export LC_ALL; fi
+if test "${LC_MESSAGES+set}" = set; then LC_MESSAGES=C; export LC_MESSAGES; fi
+if test "${LC_CTYPE+set}" = set; then LC_CTYPE=C; export LC_CTYPE; fi
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -rf conftest* confdefs.h
+# AIX cpp loses on an empty file, so make sure it contains at least a newline.
+echo > confdefs.h
+
+# A filename unique to this package, relative to the directory that
+# configure is in, which we can look for to find out if srcdir is correct.
+ac_unique_file=dump/dump.h
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then its parent.
+ ac_prog=$0
+ ac_confdir=`echo $ac_prog|sed 's%/[^/][^/]*$%%'`
+ test "x$ac_confdir" = "x$ac_prog" && ac_confdir=.
+ srcdir=$ac_confdir
+ if test ! -r $srcdir/$ac_unique_file; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r $srcdir/$ac_unique_file; then
+ if test "$ac_srcdir_defaulted" = yes; then
+ { echo "configure: error: can not find sources in $ac_confdir or .." 1>&2; exit 1; }
+ else
+ { echo "configure: error: can not find sources in $srcdir" 1>&2; exit 1; }
+ fi
+fi
+srcdir=`echo "${srcdir}" | sed 's%\([^/]\)/*$%\1%'`
+
+# Prefer explicitly selected file to automatically selected ones.
+if test -z "$CONFIG_SITE"; then
+ if test "x$prefix" != xNONE; then
+ CONFIG_SITE="$prefix/share/config.site $prefix/etc/config.site"
+ else
+ CONFIG_SITE="$ac_default_prefix/share/config.site $ac_default_prefix/etc/config.site"
+ fi
+fi
+for ac_site_file in $CONFIG_SITE; do
+ if test -r "$ac_site_file"; then
+ echo "loading site script $ac_site_file"
+ . "$ac_site_file"
+ fi
+done
+
+if test -r "$cache_file"; then
+ echo "loading cache $cache_file"
+ . $cache_file
+else
+ echo "creating cache $cache_file"
+ > $cache_file
+fi
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+if (echo "testing\c"; echo 1,2,3) | grep c >/dev/null; then
+ # Stardent Vistra SVR4 grep lacks -e, says ghazi@caip.rutgers.edu.
+ if (echo -n testing; echo 1,2,3) | sed s/-n/xn/ | grep xn >/dev/null; then
+ ac_n= ac_c='
+' ac_t=' '
+ else
+ ac_n=-n ac_c= ac_t=
+ fi
+else
+ ac_n= ac_c='\c' ac_t=
+fi
+
+
+
+MCONFIG=./MCONFIG
+
+
+
+
+echo $ac_n "checking whether ${MAKE-make} sets \${MAKE}""... $ac_c" 1>&6
+echo "configure:557: checking whether ${MAKE-make} sets \${MAKE}" >&5
+set dummy ${MAKE-make}; ac_make=`echo "$2" | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_prog_make_${ac_make}_set'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftestmake <<\EOF
+all:
+ @echo 'ac_maketemp="${MAKE}"'
+EOF
+# GNU make sometimes prints "make[1]: Entering...", which would confuse us.
+eval `${MAKE-make} -f conftestmake 2>/dev/null | grep temp=`
+if test -n "$ac_maketemp"; then
+ eval ac_cv_prog_make_${ac_make}_set=yes
+else
+ eval ac_cv_prog_make_${ac_make}_set=no
+fi
+rm -f conftestmake
+fi
+if eval "test \"`echo '$ac_cv_prog_make_'${ac_make}_set`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ SET_MAKE=
+else
+ echo "$ac_t""no" 1>&6
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+echo $ac_n "checking whether ln -s works""... $ac_c" 1>&6
+echo "configure:584: checking whether ln -s works" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_LN_S'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ rm -f conftestdata
+if ln -s X conftestdata 2>/dev/null
+then
+ rm -f conftestdata
+ ac_cv_prog_LN_S="ln -s"
+else
+ ac_cv_prog_LN_S=ln
+fi
+fi
+LN_S="$ac_cv_prog_LN_S"
+if test "$ac_cv_prog_LN_S" = "ln -s"; then
+ echo "$ac_t""yes" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "cp", so it can be a program name with args.
+set dummy cp; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:607: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_CP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$CP" in
+ /*)
+ ac_cv_path_CP="$CP" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_CP="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_CP" && ac_cv_path_CP="cp"
+ ;;
+esac
+fi
+CP="$ac_cv_path_CP"
+if test -n "$CP"; then
+ echo "$ac_t""$CP" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "mv", so it can be a program name with args.
+set dummy mv; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:639: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_MV'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$MV" in
+ /*)
+ ac_cv_path_MV="$MV" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_MV="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_MV" && ac_cv_path_MV="mv"
+ ;;
+esac
+fi
+MV="$ac_cv_path_MV"
+if test -n "$MV"; then
+ echo "$ac_t""$MV" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+# Extract the first word of "rm", so it can be a program name with args.
+set dummy rm; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:671: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_path_RM'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ case "$RM" in
+ /*)
+ ac_cv_path_RM="$RM" # Let the user override the test with a path.
+ ;;
+ *)
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_path_RM="$ac_dir/$ac_word"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_path_RM" && ac_cv_path_RM="rm"
+ ;;
+esac
+fi
+RM="$ac_cv_path_RM"
+if test -n "$RM"; then
+ echo "$ac_t""$RM" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ac_aux_dir=
+for ac_dir in $srcdir $srcdir/.. $srcdir/../..; do
+ if test -f $ac_dir/install-sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f $ac_dir/install.sh; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ { echo "configure: error: can not find install-sh or install.sh in $srcdir $srcdir/.. $srcdir/../.." 1>&2; exit 1; }
+fi
+ac_config_guess=$ac_aux_dir/config.guess
+ac_config_sub=$ac_aux_dir/config.sub
+ac_configure=$ac_aux_dir/configure # This should be Cygnus configure.
+
+
+# Make sure we can run config.sub.
+if $ac_config_sub sun4 >/dev/null 2>&1; then :
+else { echo "configure: error: can not run $ac_config_sub" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking host system type""... $ac_c" 1>&6
+echo "configure:726: checking host system type" >&5
+
+host_alias=$host
+case "$host_alias" in
+NONE)
+ case $nonopt in
+ NONE)
+ if host_alias=`$ac_config_guess`; then :
+ else { echo "configure: error: can not guess host type; you must specify one" 1>&2; exit 1; }
+ fi ;;
+ *) host_alias=$nonopt ;;
+ esac ;;
+esac
+
+host=`$ac_config_sub $host_alias`
+host_cpu=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+host_vendor=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+host_os=`echo $host | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$host" 1>&6
+
+echo $ac_n "checking build system type""... $ac_c" 1>&6
+echo "configure:747: checking build system type" >&5
+
+build_alias=$build
+case "$build_alias" in
+NONE)
+ case $nonopt in
+ NONE) build_alias=$host_alias ;;
+ *) build_alias=$nonopt ;;
+ esac ;;
+esac
+
+build=`$ac_config_sub $build_alias`
+build_cpu=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\1/'`
+build_vendor=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\2/'`
+build_os=`echo $build | sed 's/^\([^-]*\)-\([^-]*\)-\(.*\)$/\3/'`
+echo "$ac_t""$build" 1>&6
+
+if test $host != $build; then
+ ac_tool_prefix=${host_alias}-
+else
+ ac_tool_prefix=
+fi
+
+# Extract the first word of "${ac_tool_prefix}ar", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ar; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:773: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AR="${ac_tool_prefix}ar"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+ echo "$ac_t""$AR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+if test -z "$ac_cv_prog_AR"; then
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "ar", so it can be a program name with args.
+set dummy ar; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:804: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_AR'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_AR="ar"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_AR" && ac_cv_prog_AR="ar"
+fi
+fi
+AR="$ac_cv_prog_AR"
+if test -n "$AR"; then
+ echo "$ac_t""$AR" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+ AR="ar"
+fi
+fi
+
+# Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:838: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+if test -z "$ac_cv_prog_RANLIB"; then
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:869: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_RANLIB'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_RANLIB="ranlib"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_RANLIB" && ac_cv_prog_RANLIB=":"
+fi
+fi
+RANLIB="$ac_cv_prog_RANLIB"
+if test -n "$RANLIB"; then
+ echo "$ac_t""$RANLIB" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+ RANLIB=":"
+fi
+fi
+
+# Extract the first word of "${ac_tool_prefix}patch", so it can be a program name with args.
+set dummy ${ac_tool_prefix}patch; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:903: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_PATCH'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$PATCH"; then
+ ac_cv_prog_PATCH="$PATCH" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_PATCH="${ac_tool_prefix}patch"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+PATCH="$ac_cv_prog_PATCH"
+if test -n "$PATCH"; then
+ echo "$ac_t""$PATCH" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+
+if test -z "$ac_cv_prog_PATCH"; then
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "patch", so it can be a program name with args.
+set dummy patch; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:934: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_PATCH'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$PATCH"; then
+ ac_cv_prog_PATCH="$PATCH" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_PATCH="patch"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+ test -z "$ac_cv_prog_PATCH" && ac_cv_prog_PATCH=":"
+fi
+fi
+PATCH="$ac_cv_prog_PATCH"
+if test -n "$PATCH"; then
+ echo "$ac_t""$PATCH" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+else
+ PATCH=":"
+fi
+fi
+
+# Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:968: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ ac_cv_prog_CC="gcc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+echo $ac_n "checking for $ac_word""... $ac_c" 1>&6
+echo "configure:997: checking for $ac_word" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_CC'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ IFS="${IFS= }"; ac_save_ifs="$IFS"; IFS="${IFS}:"
+ ac_prog_rejected=no
+ for ac_dir in $PATH; do
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$ac_word; then
+ if test "$ac_dir/$ac_word" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ break
+ fi
+ done
+ IFS="$ac_save_ifs"
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# -gt 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ set dummy "$ac_dir/$ac_word" "$@"
+ shift
+ ac_cv_prog_CC="$@"
+ fi
+fi
+fi
+fi
+CC="$ac_cv_prog_CC"
+if test -n "$CC"; then
+ echo "$ac_t""$CC" 1>&6
+else
+ echo "$ac_t""no" 1>&6
+fi
+
+ test -z "$CC" && { echo "configure: error: no acceptable cc found in \$PATH" 1>&2; exit 1; }
+fi
+
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works""... $ac_c" 1>&6
+echo "configure:1045: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) works" >&5
+
+ac_ext=c
+# CFLAGS is not in ac_cpp because -g, -O, etc. are not valid cpp options.
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='${CC-cc} -c $CFLAGS $CPPFLAGS conftest.$ac_ext 1>&5'
+ac_link='${CC-cc} -o conftest $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS 1>&5'
+cross_compiling=$ac_cv_prog_cc_cross
+
+cat > conftest.$ac_ext <<EOF
+#line 1055 "configure"
+#include "confdefs.h"
+main(){return(0);}
+EOF
+if { (eval echo configure:1059: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ ac_cv_prog_cc_works=yes
+ # If we can't run a trivial program, we are probably using a cross compiler.
+ if (./conftest; exit) 2>/dev/null; then
+ ac_cv_prog_cc_cross=no
+ else
+ ac_cv_prog_cc_cross=yes
+ fi
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ ac_cv_prog_cc_works=no
+fi
+rm -fr conftest*
+
+echo "$ac_t""$ac_cv_prog_cc_works" 1>&6
+if test $ac_cv_prog_cc_works = no; then
+ { echo "configure: error: installation or configuration problem: C compiler cannot create executables." 1>&2; exit 1; }
+fi
+echo $ac_n "checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler""... $ac_c" 1>&6
+echo "configure:1079: checking whether the C compiler ($CC $CFLAGS $LDFLAGS) is a cross-compiler" >&5
+echo "$ac_t""$ac_cv_prog_cc_cross" 1>&6
+cross_compiling=$ac_cv_prog_cc_cross
+
+echo $ac_n "checking whether we are using GNU C""... $ac_c" 1>&6
+echo "configure:1084: checking whether we are using GNU C" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_gcc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.c <<EOF
+#ifdef __GNUC__
+ yes;
+#endif
+EOF
+if { ac_try='${CC-cc} -E conftest.c'; { (eval echo configure:1093: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }; } | egrep yes >/dev/null 2>&1; then
+ ac_cv_prog_gcc=yes
+else
+ ac_cv_prog_gcc=no
+fi
+fi
+
+echo "$ac_t""$ac_cv_prog_gcc" 1>&6
+
+if test $ac_cv_prog_gcc = yes; then
+ GCC=yes
+ ac_test_CFLAGS="${CFLAGS+set}"
+ ac_save_CFLAGS="$CFLAGS"
+ CFLAGS=
+ echo $ac_n "checking whether ${CC-cc} accepts -g""... $ac_c" 1>&6
+echo "configure:1108: checking whether ${CC-cc} accepts -g" >&5
+if eval "test \"`echo '$''{'ac_cv_prog_cc_g'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ echo 'void f(){}' > conftest.c
+if test -z "`${CC-cc} -g -c conftest.c 2>&1`"; then
+ ac_cv_prog_cc_g=yes
+else
+ ac_cv_prog_cc_g=no
+fi
+rm -f conftest*
+
+fi
+
+echo "$ac_t""$ac_cv_prog_cc_g" 1>&6
+ if test "$ac_test_CFLAGS" = set; then
+ CFLAGS="$ac_save_CFLAGS"
+ elif test $ac_cv_prog_cc_g = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-O2"
+ fi
+else
+ GCC=
+ test "${CFLAGS+set}" = set || CFLAGS="-g"
+fi
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# ./install, which can be erroneously created by make from ./install.sh.
+echo $ac_n "checking for a BSD compatible install""... $ac_c" 1>&6
+echo "configure:1146: checking for a BSD compatible install" >&5
+if test -z "$INSTALL"; then
+if eval "test \"`echo '$''{'ac_cv_path_install'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ IFS="${IFS= }"; ac_save_IFS="$IFS"; IFS="${IFS}:"
+ for ac_dir in $PATH; do
+ # Account for people who put trailing slashes in PATH elements.
+ case "$ac_dir/" in
+ /|./|.//|/etc/*|/usr/sbin/*|/usr/etc/*|/sbin/*|/usr/afsws/bin/*|/usr/ucb/*) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ for ac_prog in ginstall installbsd scoinst install; do
+ if test -f $ac_dir/$ac_prog; then
+ if test $ac_prog = install &&
+ grep dspmsg $ac_dir/$ac_prog >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ # OSF/1 installbsd also uses dspmsg, but is usable.
+ :
+ else
+ ac_cv_path_install="$ac_dir/$ac_prog -c"
+ break 2
+ fi
+ fi
+ done
+ ;;
+ esac
+ done
+ IFS="$ac_save_IFS"
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL="$ac_cv_path_install"
+ else
+ # As a last resort, use the slow shell script. We don't cache a
+ # path for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the path is relative.
+ INSTALL="$ac_install_sh"
+ fi
+fi
+echo "$ac_t""$INSTALL" 1>&6
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+
+# Check whether --enable-dumpdates-patch or --disable-dumpdates-patch was given.
+if test "${enable_dumpdates_patch+set}" = set; then
+ enableval="$enable_dumpdates_patch"
+ if test "$enableval" = "yes"
+then
+ if test "$PATCH" = ":"
+ then
+ { echo "configure: error: The patch program was not found on your system" 1>&2; exit 1; }
+ fi
+ (cd $srcdir; $PATCH -p < debian-patch)
+fi
+
+fi
+
+
+# Check whether --enable-debug or --disable-debug was given.
+if test "${enable_debug+set}" = set; then
+ enableval="$enable_debug"
+ if test "$enableval" = "no"
+then
+ DUMPDEBUG=""
+ RESTOREDEBUG=""
+else
+ DUMPDEBUG="-DFDEBUG -DTDEBUG -DWRITEDEBUG -DDIRDEBUG"
+ RESTOREDEBUG="-DDIRDEBUG"
+fi
+else
+ DUMPDEBUG=""
+RESTOREDEBUG=""
+
+fi
+
+
+
+
+# Check whether --enable-static or --disable-static was given.
+if test "${enable_static+set}" = set; then
+ enableval="$enable_static"
+ if test "$enableval" = "no"
+then
+ STATIC=""
+else
+ STATIC="-static"
+fi
+
+else
+ STATIC=""
+echo "Linking dump and restore dynamically by default"
+
+fi
+
+
+
+# Check whether --enable-rmt or --disable-rmt was given.
+if test "${enable_rmt+set}" = set; then
+ enableval="$enable_rmt"
+ if test "$enableval" = "no"
+then
+ RMTDIR=""
+ RMTMAKEFILE=""
+else
+ RMTDIR="rmt"
+ RMTMAKEFILE="rmt/Makefile"
+fi
+
+else
+ RMTDIR=""
+echo "Not compiling rmt by default"
+
+fi
+
+
+
+# Check whether --with-cc or --without-cc was given.
+if test "${with_cc+set}" = set; then
+ withval="$with_cc"
+ echo "$ac_t""CC=$withval" 1>&6
+CC=$withval
+else
+ if test -z "$CC" ; then CC=cc; fi
+echo "$ac_t""CC defaults to $CC" 1>&6
+fi
+export CC
+
+
+# Check whether --with-linker or --without-linker was given.
+if test "${with_linker+set}" = set; then
+ withval="$with_linker"
+ echo "$ac_t""LD=$withval" 1>&6
+LD=$withval
+else
+ if test -z "$LD" ; then LD=$CC; fi
+echo "$ac_t""LD defaults to $LD" 1>&6
+fi
+export LD
+
+
+# Check whether --with-ccopts or --without-ccopts was given.
+if test "${with_ccopts+set}" = set; then
+ withval="$with_ccopts"
+ echo "$ac_t""CCOPTS is $withval" 1>&6
+CCOPTS=$withval
+CFLAGS="$CFLAGS $withval"
+else
+ CCOPTS=
+fi
+
+
+# Check whether --with-ldopts or --without-ldopts was given.
+if test "${with_ldopts+set}" = set; then
+ withval="$with_ldopts"
+ echo "$ac_t""LDFLAGS is $withval" 1>&6
+LDFLAGS=$withval
+else
+ LDFLAGS=
+fi
+
+
+# Check whether --with-binowner or --without-binowner was given.
+if test "${with_binowner+set}" = set; then
+ withval="$with_binowner"
+ echo "$ac_t""BINOWNER is $withval" 1>&6
+BINOWNER=$withval
+else
+ BINOWNER=root
+echo "BINOWNER defaults to $BINOWNER"
+
+fi
+
+
+# Check whether --with-bingrp or --without-bingrp was given.
+if test "${with_bingrp+set}" = set; then
+ withval="$with_bingrp"
+ echo "$ac_t""BINGRP is $withval" 1>&6
+BINGRP=$withval
+else
+ BINGRP=tty
+echo "BINGRP defaults to $BINGRP"
+
+fi
+
+
+# Check whether --with-binmode or --without-binmode was given.
+if test "${with_binmode+set}" = set; then
+ withval="$with_binmode"
+ echo "$ac_t""BINMODE is $withval" 1>&6
+BINMODE=$withval
+else
+ BINMODE=6555
+echo "BINMODE defaults to $BINMODE"
+
+fi
+
+
+# Check whether --with-manowner or --without-manowner was given.
+if test "${with_manowner+set}" = set; then
+ withval="$with_manowner"
+ echo "$ac_t""MANOWNER is $withval" 1>&6
+MANOWNER=$withval
+else
+ MANOWNER=man
+echo "MANOWNER defaults to $MANOWNER"
+
+fi
+
+
+# Check whether --with-mangrp or --without-mangrp was given.
+if test "${with_mangrp+set}" = set; then
+ withval="$with_mangrp"
+ echo "$ac_t""MANGRP is $withval" 1>&6
+MANGRP=$withval
+else
+ MANGRP=tty
+echo "MANGRP defaults to $MANGRP"
+
+fi
+
+
+# Check whether --with-manmode or --without-manmode was given.
+if test "${with_manmode+set}" = set; then
+ withval="$with_manmode"
+ echo "$ac_t""MANMODE is $withval" 1>&6
+MANMODE=$withval
+else
+ MANMODE=0444
+echo "MANMODE defaults to $MANMODE"
+
+fi
+
+
+echo $ac_n "checking how to run the C preprocessor""... $ac_c" 1>&6
+echo "configure:1387: checking how to run the C preprocessor" >&5
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+ CPP=
+fi
+if test -z "$CPP"; then
+if eval "test \"`echo '$''{'ac_cv_prog_CPP'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ # This must be in double quotes, not single quotes, because CPP may get
+ # substituted into the Makefile and "${CC-cc}" will confuse make.
+ CPP="${CC-cc} -E"
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp.
+ cat > conftest.$ac_ext <<EOF
+#line 1402 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1408: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP="${CC-cc} -E -traditional-cpp"
+ cat > conftest.$ac_ext <<EOF
+#line 1419 "configure"
+#include "confdefs.h"
+#include <assert.h>
+Syntax Error
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1425: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ :
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ CPP=/lib/cpp
+fi
+rm -f conftest*
+fi
+rm -f conftest*
+ ac_cv_prog_CPP="$CPP"
+fi
+ CPP="$ac_cv_prog_CPP"
+else
+ ac_cv_prog_CPP="$CPP"
+fi
+echo "$ac_t""$CPP" 1>&6
+
+ac_safe=`echo "ext2fs/ext2fs.h" | sed 'y%./+-%__p_%'`
+echo $ac_n "checking for ext2fs/ext2fs.h""... $ac_c" 1>&6
+echo "configure:1449: checking for ext2fs/ext2fs.h" >&5
+if eval "test \"`echo '$''{'ac_cv_header_$ac_safe'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1454 "configure"
+#include "confdefs.h"
+#include <ext2fs/ext2fs.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1459: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=yes"
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_header_$ac_safe=no"
+fi
+rm -f conftest*
+fi
+if eval "test \"`echo '$ac_cv_header_'$ac_safe`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ext2fs_h=yes
+else
+ echo "$ac_t""no" 1>&6
+ext2fs_h=no
+fi
+
+echo $ac_n "checking for ext2fs_open in -lext2fs""... $ac_c" 1>&6
+echo "configure:1482: checking for ext2fs_open in -lext2fs" >&5
+ac_lib_var=`echo ext2fs'_'ext2fs_open | sed 'y%./+-%__p_%'`
+if eval "test \"`echo '$''{'ac_cv_lib_$ac_lib_var'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ ac_save_LIBS="$LIBS"
+LIBS="-lext2fs -lcom_err $LIBS"
+cat > conftest.$ac_ext <<EOF
+#line 1490 "configure"
+#include "confdefs.h"
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char ext2fs_open();
+
+int main() {
+ext2fs_open()
+; return 0; }
+EOF
+if { (eval echo configure:1501: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_lib_$ac_lib_var=no"
+fi
+rm -f conftest*
+LIBS="$ac_save_LIBS"
+
+fi
+if eval "test \"`echo '$ac_cv_lib_'$ac_lib_var`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ext2fs_lib=yes
+else
+ echo "$ac_t""no" 1>&6
+ext2fs_lib=no
+fi
+
+if test "$ext2fs_h" = no -o "$ext2fs_lib" = no; then
+ { echo "configure: error: You need to install the Ext2fs libraries from the E2fsprogs distribution first" 1>&2; exit 1; }
+fi
+
+for ac_func in err errx verr verrx vwarn vwarnx warn warnx realpath
+do
+echo $ac_n "checking for $ac_func""... $ac_c" 1>&6
+echo "configure:1529: checking for $ac_func" >&5
+if eval "test \"`echo '$''{'ac_cv_func_$ac_func'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1534 "configure"
+#include "confdefs.h"
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $ac_func(); below. */
+#include <assert.h>
+/* Override any gcc2 internal prototype to avoid an error. */
+/* We use char because int might match the return type of a gcc2
+ builtin and then its argument prototype would still apply. */
+char $ac_func();
+
+int main() {
+
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined (__stub_$ac_func) || defined (__stub___$ac_func)
+choke me
+#else
+$ac_func();
+#endif
+
+; return 0; }
+EOF
+if { (eval echo configure:1557: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest; then
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=yes"
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ eval "ac_cv_func_$ac_func=no"
+fi
+rm -f conftest*
+fi
+
+if eval "test \"`echo '$ac_cv_func_'$ac_func`\" = yes"; then
+ echo "$ac_t""yes" 1>&6
+ ac_tr_func=HAVE_`echo $ac_func | tr 'abcdefghijklmnopqrstuvwxyz' 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'`
+ cat >> confdefs.h <<EOF
+#define $ac_tr_func 1
+EOF
+
+else
+ echo "$ac_t""no" 1>&6
+fi
+done
+
+
+echo $ac_n "checking for ANSI C header files""... $ac_c" 1>&6
+echo "configure:1583: checking for ANSI C header files" >&5
+if eval "test \"`echo '$''{'ac_cv_header_stdc'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1588 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+EOF
+ac_try="$ac_cpp conftest.$ac_ext >/dev/null 2>conftest.out"
+{ (eval echo configure:1596: \"$ac_try\") 1>&5; (eval $ac_try) 2>&5; }
+ac_err=`grep -v '^ *+' conftest.out`
+if test -z "$ac_err"; then
+ rm -rf conftest*
+ ac_cv_header_stdc=yes
+else
+ echo "$ac_err" >&5
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1613 "configure"
+#include "confdefs.h"
+#include <string.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "memchr" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+cat > conftest.$ac_ext <<EOF
+#line 1631 "configure"
+#include "confdefs.h"
+#include <stdlib.h>
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "free" >/dev/null 2>&1; then
+ :
+else
+ rm -rf conftest*
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+if test "$cross_compiling" = yes; then
+ :
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1652 "configure"
+#include "confdefs.h"
+#include <ctype.h>
+#define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+#define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int main () { int i; for (i = 0; i < 256; i++)
+if (XOR (islower (i), ISLOWER (i)) || toupper (i) != TOUPPER (i)) exit(2);
+exit (0); }
+
+EOF
+if { (eval echo configure:1663: \"$ac_link\") 1>&5; (eval $ac_link) 2>&5; } && test -s conftest && (./conftest; exit) 2>/dev/null
+then
+ :
+else
+ echo "configure: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ rm -fr conftest*
+ ac_cv_header_stdc=no
+fi
+rm -fr conftest*
+fi
+
+fi
+fi
+
+echo "$ac_t""$ac_cv_header_stdc" 1>&6
+if test $ac_cv_header_stdc = yes; then
+ cat >> confdefs.h <<\EOF
+#define STDC_HEADERS 1
+EOF
+
+fi
+
+echo $ac_n "checking for quad_t""... $ac_c" 1>&6
+echo "configure:1687: checking for quad_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_quad_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1692 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "quad_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_quad_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_quad_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_quad_t" 1>&6
+if test $ac_cv_type_quad_t = no; then
+ cat >> confdefs.h <<\EOF
+#define quad_t __s64
+EOF
+
+fi
+
+echo $ac_n "checking for u_quad_t""... $ac_c" 1>&6
+echo "configure:1720: checking for u_quad_t" >&5
+if eval "test \"`echo '$''{'ac_cv_type_u_quad_t'+set}'`\" = set"; then
+ echo $ac_n "(cached) $ac_c" 1>&6
+else
+ cat > conftest.$ac_ext <<EOF
+#line 1725 "configure"
+#include "confdefs.h"
+#include <sys/types.h>
+#if STDC_HEADERS
+#include <stdlib.h>
+#include <stddef.h>
+#endif
+EOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ egrep "u_quad_t[^a-zA-Z_0-9]" >/dev/null 2>&1; then
+ rm -rf conftest*
+ ac_cv_type_u_quad_t=yes
+else
+ rm -rf conftest*
+ ac_cv_type_u_quad_t=no
+fi
+rm -f conftest*
+
+fi
+echo "$ac_t""$ac_cv_type_u_quad_t" 1>&6
+if test $ac_cv_type_u_quad_t = no; then
+ cat >> confdefs.h <<\EOF
+#define u_quad_t __u64
+EOF
+
+fi
+
+
+top_builddir=`cd .; pwd`
+
+
+test -d compat || mkdir compat
+test -d compat/lib || mkdir compat/lib
+
+trap '' 1 2 15
+cat > confcache <<\EOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs. It is not useful on other systems.
+# If it contains results you don't want to keep, you may remove or edit it.
+#
+# By default, configure uses ./config.cache as the cache file,
+# creating it if it does not exist already. You can give configure
+# the --cache-file=FILE option to use a different cache file; that is
+# what configure does when it calls configure scripts in
+# subdirectories, so they share the cache.
+# Giving --cache-file=/dev/null disables caching, for debugging configure.
+# config.status only pays attention to the cache file if you give it the
+# --recheck option to rerun configure.
+#
+EOF
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, don't put newlines in cache variables' values.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(set) 2>&1 |
+ case `(ac_space=' '; set) 2>&1` in
+ *ac_space=\ *)
+ # `set' does not quote correctly, so add quotes (double-quote substitution
+ # turns \\\\ into \\, and sed turns \\ into \).
+ sed -n \
+ -e "s/'/'\\\\''/g" \
+ -e "s/^\\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\\)=\\(.*\\)/\\1=\${\\1='\\2'}/p"
+ ;;
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n -e 's/^\([a-zA-Z0-9_]*_cv_[a-zA-Z0-9_]*\)=\(.*\)/\1=${\1=\2}/p'
+ ;;
+ esac >> confcache
+if cmp -s $cache_file confcache; then
+ :
+else
+ if test -w $cache_file; then
+ echo "updating cache $cache_file"
+ cat confcache > $cache_file
+ else
+ echo "not updating unwritable cache $cache_file"
+ fi
+fi
+rm -f confcache
+
+trap 'rm -fr conftest* confdefs* core core.* *.core $ac_clean_files; exit 1' 1 2 15
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+# Any assignment to VPATH causes Sun make to only execute
+# the first set of double-colon rules, so remove it if not needed.
+# If there is a colon in the path, we need to keep it.
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[^:]*$/d'
+fi
+
+trap 'rm -f $CONFIG_STATUS conftest*; exit 1' 1 2 15
+
+DEFS=-DHAVE_CONFIG_H
+
+# Without the "./", some shells look in PATH for config.status.
+: ${CONFIG_STATUS=./config.status}
+
+echo creating $CONFIG_STATUS
+rm -f $CONFIG_STATUS
+cat > $CONFIG_STATUS <<EOF
+#! /bin/sh
+# Generated automatically by configure.
+# Run this file to recreate the current configuration.
+# This directory was configured as follows,
+# on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+#
+# $0 $ac_configure_args
+#
+# Compiler output produced by configure, useful for debugging
+# configure, is in ./config.log if it exists.
+
+ac_cs_usage="Usage: $CONFIG_STATUS [--recheck] [--version] [--help]"
+for ac_option
+do
+ case "\$ac_option" in
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ echo "running \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion"
+ exec \${CONFIG_SHELL-/bin/sh} $0 $ac_configure_args --no-create --no-recursion ;;
+ -version | --version | --versio | --versi | --vers | --ver | --ve | --v)
+ echo "$CONFIG_STATUS generated by autoconf version 2.12"
+ exit 0 ;;
+ -help | --help | --hel | --he | --h)
+ echo "\$ac_cs_usage"; exit 0 ;;
+ *) echo "\$ac_cs_usage"; exit 1 ;;
+ esac
+done
+
+ac_given_srcdir=$srcdir
+ac_given_INSTALL="$INSTALL"
+
+trap 'rm -fr `echo "MCONFIG Makefile common/Makefile compat/lib/Makefile dump/Makefile restore/Makefile $RMTMAKEFILE config.h" | sed "s/:[^ ]*//g"` conftest*; exit 1' 1 2 15
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+# Protect against being on the right side of a sed subst in config.status.
+sed 's/%@/@@/; s/@%/@@/; s/%g\$/@g/; /@g\$/s/[\\\\&%]/\\\\&/g;
+ s/@@/%@/; s/@@/@%/; s/@g\$/%g/' > conftest.subs <<\\CEOF
+$ac_vpsub
+$extrasub
+s%@CFLAGS@%$CFLAGS%g
+s%@CPPFLAGS@%$CPPFLAGS%g
+s%@CXXFLAGS@%$CXXFLAGS%g
+s%@DEFS@%$DEFS%g
+s%@LDFLAGS@%$LDFLAGS%g
+s%@LIBS@%$LIBS%g
+s%@exec_prefix@%$exec_prefix%g
+s%@prefix@%$prefix%g
+s%@program_transform_name@%$program_transform_name%g
+s%@bindir@%$bindir%g
+s%@sbindir@%$sbindir%g
+s%@libexecdir@%$libexecdir%g
+s%@datadir@%$datadir%g
+s%@sysconfdir@%$sysconfdir%g
+s%@sharedstatedir@%$sharedstatedir%g
+s%@localstatedir@%$localstatedir%g
+s%@libdir@%$libdir%g
+s%@includedir@%$includedir%g
+s%@oldincludedir@%$oldincludedir%g
+s%@infodir@%$infodir%g
+s%@mandir@%$mandir%g
+/@MCONFIG@/r $MCONFIG
+s%@MCONFIG@%%g
+s%@SET_MAKE@%$SET_MAKE%g
+s%@LN_S@%$LN_S%g
+s%@CP@%$CP%g
+s%@MV@%$MV%g
+s%@RM@%$RM%g
+s%@host@%$host%g
+s%@host_alias@%$host_alias%g
+s%@host_cpu@%$host_cpu%g
+s%@host_vendor@%$host_vendor%g
+s%@host_os@%$host_os%g
+s%@build@%$build%g
+s%@build_alias@%$build_alias%g
+s%@build_cpu@%$build_cpu%g
+s%@build_vendor@%$build_vendor%g
+s%@build_os@%$build_os%g
+s%@AR@%$AR%g
+s%@RANLIB@%$RANLIB%g
+s%@PATCH@%$PATCH%g
+s%@CC@%$CC%g
+s%@INSTALL_PROGRAM@%$INSTALL_PROGRAM%g
+s%@INSTALL_DATA@%$INSTALL_DATA%g
+s%@DUMPDEBUG@%$DUMPDEBUG%g
+s%@RESTOREDEBUG@%$RESTOREDEBUG%g
+s%@STATIC@%$STATIC%g
+s%@RMTDIR@%$RMTDIR%g
+s%@LD@%$LD%g
+s%@CCOPTS@%$CCOPTS%g
+s%@BINOWNER@%$BINOWNER%g
+s%@BINGRP@%$BINGRP%g
+s%@BINMODE@%$BINMODE%g
+s%@MANOWNER@%$MANOWNER%g
+s%@MANGRP@%$MANGRP%g
+s%@MANMODE@%$MANMODE%g
+s%@CPP@%$CPP%g
+s%@top_builddir@%$top_builddir%g
+
+CEOF
+EOF
+
+cat >> $CONFIG_STATUS <<\EOF
+
+# Split the substitutions into bite-sized pieces for seds with
+# small command number limits, like on Digital OSF/1 and HP-UX.
+ac_max_sed_cmds=90 # Maximum number of lines to put in a sed script.
+ac_file=1 # Number of current file.
+ac_beg=1 # First line for current file.
+ac_end=$ac_max_sed_cmds # Line after last line for current file.
+ac_more_lines=:
+ac_sed_cmds=""
+while $ac_more_lines; do
+ if test $ac_beg -gt 1; then
+ sed "1,${ac_beg}d; ${ac_end}q" conftest.subs > conftest.s$ac_file
+ else
+ sed "${ac_end}q" conftest.subs > conftest.s$ac_file
+ fi
+ if test ! -s conftest.s$ac_file; then
+ ac_more_lines=false
+ rm -f conftest.s$ac_file
+ else
+ if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds="sed -f conftest.s$ac_file"
+ else
+ ac_sed_cmds="$ac_sed_cmds | sed -f conftest.s$ac_file"
+ fi
+ ac_file=`expr $ac_file + 1`
+ ac_beg=$ac_end
+ ac_end=`expr $ac_end + $ac_max_sed_cmds`
+ fi
+done
+if test -z "$ac_sed_cmds"; then
+ ac_sed_cmds=cat
+fi
+EOF
+
+cat >> $CONFIG_STATUS <<EOF
+
+CONFIG_FILES=\${CONFIG_FILES-"MCONFIG Makefile common/Makefile compat/lib/Makefile dump/Makefile restore/Makefile $RMTMAKEFILE"}
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+for ac_file in .. $CONFIG_FILES; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ # Adjust a relative srcdir, top_srcdir, and INSTALL for subdirectories.
+
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ ac_dir_suffix="/`echo $ac_dir|sed 's%^\./%%'`"
+ # A "../" for each directory in $ac_dir_suffix.
+ ac_dots=`echo $ac_dir_suffix|sed 's%/[^/]*%../%g'`
+ else
+ ac_dir_suffix= ac_dots=
+ fi
+
+ case "$ac_given_srcdir" in
+ .) srcdir=.
+ if test -z "$ac_dots"; then top_srcdir=.
+ else top_srcdir=`echo $ac_dots|sed 's%/$%%'`; fi ;;
+ /*) srcdir="$ac_given_srcdir$ac_dir_suffix"; top_srcdir="$ac_given_srcdir" ;;
+ *) # Relative path.
+ srcdir="$ac_dots$ac_given_srcdir$ac_dir_suffix"
+ top_srcdir="$ac_dots$ac_given_srcdir" ;;
+ esac
+
+ case "$ac_given_INSTALL" in
+ [/$]*) INSTALL="$ac_given_INSTALL" ;;
+ *) INSTALL="$ac_dots$ac_given_INSTALL" ;;
+ esac
+
+ echo creating "$ac_file"
+ rm -f "$ac_file"
+ configure_input="Generated automatically from `echo $ac_file_in|sed 's%.*/%%'` by configure."
+ case "$ac_file" in
+ *Makefile*) ac_comsub="1i\\
+# $configure_input" ;;
+ *) ac_comsub= ;;
+ esac
+
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ sed -e "$ac_comsub
+s%@configure_input@%$configure_input%g
+s%@srcdir@%$srcdir%g
+s%@top_srcdir@%$top_srcdir%g
+s%@INSTALL@%$INSTALL%g
+" $ac_file_inputs | (eval "$ac_sed_cmds") > $ac_file
+fi; done
+rm -f conftest.s*
+
+# These sed commands are passed to sed as "A NAME B NAME C VALUE D", where
+# NAME is the cpp macro being defined and VALUE is the value it is being given.
+#
+# ac_d sets the value in "#define NAME VALUE" lines.
+ac_dA='s%^\([ ]*\)#\([ ]*define[ ][ ]*\)'
+ac_dB='\([ ][ ]*\)[^ ]*%\1#\2'
+ac_dC='\3'
+ac_dD='%g'
+# ac_u turns "#undef NAME" with trailing blanks into "#define NAME VALUE".
+ac_uA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_uB='\([ ]\)%\1#\2define\3'
+ac_uC=' '
+ac_uD='\4%g'
+# ac_e turns "#undef NAME" without trailing blanks into "#define NAME VALUE".
+ac_eA='s%^\([ ]*\)#\([ ]*\)undef\([ ][ ]*\)'
+ac_eB='$%\1#\2define\3'
+ac_eC=' '
+ac_eD='%g'
+
+if test "${CONFIG_HEADERS+set}" != set; then
+EOF
+cat >> $CONFIG_STATUS <<EOF
+ CONFIG_HEADERS="config.h"
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+fi
+for ac_file in .. $CONFIG_HEADERS; do if test "x$ac_file" != x..; then
+ # Support "outfile[:infile[:infile...]]", defaulting infile="outfile.in".
+ case "$ac_file" in
+ *:*) ac_file_in=`echo "$ac_file"|sed 's%[^:]*:%%'`
+ ac_file=`echo "$ac_file"|sed 's%:.*%%'` ;;
+ *) ac_file_in="${ac_file}.in" ;;
+ esac
+
+ echo creating $ac_file
+
+ rm -f conftest.frag conftest.in conftest.out
+ ac_file_inputs=`echo $ac_file_in|sed -e "s%^%$ac_given_srcdir/%" -e "s%:% $ac_given_srcdir/%g"`
+ cat $ac_file_inputs > conftest.in
+
+EOF
+
+# Transform confdefs.h into a sed script conftest.vals that substitutes
+# the proper values into config.h.in to produce config.h. And first:
+# Protect against being on the right side of a sed subst in config.status.
+# Protect against being in an unquoted here document in config.status.
+rm -f conftest.vals
+cat > conftest.hdr <<\EOF
+s/[\\&%]/\\&/g
+s%[\\$`]%\\&%g
+s%#define \([A-Za-z_][A-Za-z0-9_]*\) *\(.*\)%${ac_dA}\1${ac_dB}\1${ac_dC}\2${ac_dD}%gp
+s%ac_d%ac_u%gp
+s%ac_u%ac_e%gp
+EOF
+sed -n -f conftest.hdr confdefs.h > conftest.vals
+rm -f conftest.hdr
+
+# This sed command replaces #undef with comments. This is necessary, for
+# example, in the case of _POSIX_SOURCE, which is predefined and required
+# on some systems where configure will not decide to define it.
+cat >> conftest.vals <<\EOF
+s%^[ ]*#[ ]*undef[ ][ ]*[a-zA-Z_][a-zA-Z_0-9]*%/* & */%
+EOF
+
+# Break up conftest.vals because some shells have a limit on
+# the size of here documents, and old seds have small limits too.
+
+rm -f conftest.tail
+while :
+do
+ ac_lines=`grep -c . conftest.vals`
+ # grep -c gives empty output for an empty file on some AIX systems.
+ if test -z "$ac_lines" || test "$ac_lines" -eq 0; then break; fi
+ # Write a limited-size here document to conftest.frag.
+ echo ' cat > conftest.frag <<CEOF' >> $CONFIG_STATUS
+ sed ${ac_max_here_lines}q conftest.vals >> $CONFIG_STATUS
+ echo 'CEOF
+ sed -f conftest.frag conftest.in > conftest.out
+ rm -f conftest.in
+ mv conftest.out conftest.in
+' >> $CONFIG_STATUS
+ sed 1,${ac_max_here_lines}d conftest.vals > conftest.tail
+ rm -f conftest.vals
+ mv conftest.tail conftest.vals
+done
+rm -f conftest.vals
+
+cat >> $CONFIG_STATUS <<\EOF
+ rm -f conftest.frag conftest.h
+ echo "/* $ac_file. Generated automatically by configure. */" > conftest.h
+ cat conftest.in >> conftest.h
+ rm -f conftest.in
+ if cmp -s $ac_file conftest.h 2>/dev/null; then
+ echo "$ac_file is unchanged"
+ rm -f conftest.h
+ else
+ # Remove last slash and all that follows it. Not all systems have dirname.
+ ac_dir=`echo $ac_file|sed 's%/[^/][^/]*$%%'`
+ if test "$ac_dir" != "$ac_file" && test "$ac_dir" != .; then
+ # The file is in a subdirectory.
+ test ! -d "$ac_dir" && mkdir "$ac_dir"
+ fi
+ rm -f $ac_file
+ mv conftest.h $ac_file
+ fi
+fi; done
+
+EOF
+cat >> $CONFIG_STATUS <<EOF
+
+EOF
+cat >> $CONFIG_STATUS <<\EOF
+
+exit 0
+EOF
+chmod +x $CONFIG_STATUS
+rm -fr confdefs* $ac_clean_files
+test "$no_create" = yes || ${CONFIG_SHELL-/bin/sh} $CONFIG_STATUS || exit 1
+
--- /dev/null
+AC_INIT(dump/dump.h)
+
+MCONFIG=./MCONFIG
+AC_SUBST_FILE(MCONFIG)
+
+AC_CONFIG_HEADER(config.h)
+
+dnl
+dnl Check for programs
+dnl
+AC_PROG_MAKE_SET
+AC_PROG_LN_S
+AC_PATH_PROG(CP, cp, cp)
+AC_PATH_PROG(MV, mv, mv)
+AC_PATH_PROG(RM, rm, rm)
+AC_CHECK_TOOL(AR, ar, ar)
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+AC_CHECK_TOOL(PATCH, patch, :)
+AC_PROG_CC
+AC_PROG_INSTALL
+
+dnl
+dnl Handle --enable-dumpdates-patch
+dnl
+AC_ARG_ENABLE([dumpdates-patch],
+[ --enable-dumpdates-patch apply the dumpdates patch from Debian],
+if test "$enableval" = "yes"
+then
+ if test "$PATCH" = ":"
+ then
+ AC_MSG_ERROR(The patch program was not found on your system)
+ fi
+ (cd $srcdir; $PATCH -p < debian-patch)
+fi
+,
+)
+
+dnl
+dnl Handle --enable-debug
+dnl
+AC_ARG_ENABLE([debug],
+[ --enable-debug include debugging code],
+if test "$enableval" = "no"
+then
+ DUMPDEBUG=""
+ RESTOREDEBUG=""
+else
+ DUMPDEBUG="-DFDEBUG -DTDEBUG -DWRITEDEBUG -DDIRDEBUG"
+ RESTOREDEBUG="-DDIRDEBUG"
+fi,
+DUMPDEBUG=""
+RESTOREDEBUG=""
+)
+AC_SUBST(DUMPDEBUG)
+AC_SUBST(RESTOREDEBUG)
+
+dnl
+dnl Handle --enable-static
+dnl
+AC_ARG_ENABLE([static],
+[ --enable-static link dump and restore statically],
+if test "$enableval" = "no"
+then
+ STATIC=""
+else
+ STATIC="-static"
+fi
+,
+STATIC=""
+echo "Linking dump and restore dynamically by default"
+)
+AC_SUBST(STATIC)
+
+dnl
+dnl Handle --enable-rmt
+dnl
+AC_ARG_ENABLE([rmt],
+[ --enable-rmt compile and install rmt],
+if test "$enableval" = "no"
+then
+ RMTDIR=""
+ RMTMAKEFILE=""
+else
+ RMTDIR="rmt"
+ RMTMAKEFILE="rmt/Makefile"
+fi
+,
+RMTDIR=""
+echo "Not compiling rmt by default"
+)
+AC_SUBST(RMTDIR)
+
+dnl
+dnl set $(CC) from --with-cc=value
+dnl
+AC_ARG_WITH([cc],
+[ --with-cc=COMPILER select compiler to use],
+AC_MSG_RESULT(CC=$withval)
+CC=$withval,
+if test -z "$CC" ; then CC=cc; fi
+[AC_MSG_RESULT(CC defaults to $CC)])dnl
+export CC
+AC_SUBST([CC])
+
+dnl
+dnl set $(LD) from --with-linker=value
+dnl
+AC_ARG_WITH([linker],
+[ --with-linker=LINKER select linker to use],
+AC_MSG_RESULT(LD=$withval)
+LD=$withval,
+if test -z "$LD" ; then LD=$CC; fi
+[AC_MSG_RESULT(LD defaults to $LD)])dnl
+export LD
+AC_SUBST([LD])
+
+dnl
+dnl set $(CCOPTS) from --with-ccopts=value
+dnl
+AC_ARG_WITH([ccopts],
+[ --with-ccopts=CCOPTS select compiler command line options],
+AC_MSG_RESULT(CCOPTS is $withval)
+CCOPTS=$withval
+CFLAGS="$CFLAGS $withval",
+CCOPTS=)dnl
+AC_SUBST(CCOPTS)
+
+dnl
+dnl set $(LDFLAGS) from --with-ldopts=value
+dnl
+AC_ARG_WITH([ldopts],
+[ --with-ldopts=LDOPTS select linker command line options],
+AC_MSG_RESULT(LDFLAGS is $withval)
+LDFLAGS=$withval,
+LDFLAGS=)dnl
+AC_SUBST(LDFLAGS)
+
+dnl
+dnl set $(BINOWNER) from --with-binowner
+dnl
+AC_ARG_WITH([binowner],
+[ --with-binowner=USER select owner for binaries],
+AC_MSG_RESULT(BINOWNER is $withval)
+BINOWNER=$withval,
+BINOWNER=root
+echo "BINOWNER defaults to $BINOWNER"
+)dnl
+AC_SUBST(BINOWNER)
+
+dnl
+dnl set $(BINGRP) from --with-bingrp
+dnl
+AC_ARG_WITH([bingrp],
+[ --with-bingrp=GROUP select group for binaries],
+AC_MSG_RESULT(BINGRP is $withval)
+BINGRP=$withval,
+BINGRP=tty
+echo "BINGRP defaults to $BINGRP"
+)dnl
+AC_SUBST(BINGRP)
+
+dnl
+dnl set $(BINMODE) from --with-binmode
+dnl
+AC_ARG_WITH([binmode],
+[ --with-binmode=MODE select mode for binaries],
+AC_MSG_RESULT(BINMODE is $withval)
+BINMODE=$withval,
+BINMODE=6555
+echo "BINMODE defaults to $BINMODE"
+)dnl
+AC_SUBST(BINMODE)
+
+dnl
+dnl set $(MANOWNER) from --with-manowner
+dnl
+AC_ARG_WITH([manowner],
+[ --with-manowner=USER select owner for manual pages],
+AC_MSG_RESULT(MANOWNER is $withval)
+MANOWNER=$withval,
+MANOWNER=man
+echo "MANOWNER defaults to $MANOWNER"
+)dnl
+AC_SUBST(MANOWNER)
+
+dnl
+dnl set $(MANGRP) from --with-mangrp
+dnl
+AC_ARG_WITH([mangrp],
+[ --with-mangrp=group select group for manual pages],
+AC_MSG_RESULT(MANGRP is $withval)
+MANGRP=$withval,
+MANGRP=tty
+echo "MANGRP defaults to $MANGRP"
+)dnl
+AC_SUBST(MANGRP)
+
+dnl
+dnl set $(MANMODE) from --with-manmode
+dnl
+AC_ARG_WITH([manmode],
+[ --with-manmode=MODE select mode for manual pages],
+AC_MSG_RESULT(MANMODE is $withval)
+MANMODE=$withval,
+MANMODE=0444
+echo "MANMODE defaults to $MANMODE"
+)dnl
+AC_SUBST(MANMODE)
+
+dnl
+dnl Check for Ext2fs headers and libraries
+dnl
+AC_CHECK_HEADER(ext2fs/ext2fs.h, [ext2fs_h=yes], [ext2fs_h=no])
+AC_CHECK_LIB(ext2fs, ext2fs_open, [ext2fs_lib=yes], [ext2fs_lib=no], [-lcom_err])
+if test "$ext2fs_h" = no -o "$ext2fs_lib" = no; then
+ AC_MSG_ERROR(You need to install the Ext2fs libraries from the E2fsprogs distribution first)
+fi
+
+dnl
+dnl Check for library functions
+dnl
+AC_CHECK_FUNCS(err errx verr verrx vwarn vwarnx warn warnx realpath)
+
+dnl
+dnl Check for types
+dnl
+AC_CHECK_TYPE(quad_t, __s64)
+AC_CHECK_TYPE(u_quad_t, __u64)
+
+dnl
+dnl Compute top_buildir
+dnl
+top_builddir=`cd .; pwd`
+AC_SUBST(top_builddir)
+
+dnl
+dnl Create directories
+dnl
+test -d compat || mkdir compat
+test -d compat/lib || mkdir compat/lib
+
+dnl
+dnl Output files
+dnl
+AC_OUTPUT(MCONFIG Makefile common/Makefile compat/lib/Makefile dump/Makefile restore/Makefile $RMTMAKEFILE)
--- /dev/null
+--- dump/dump.h.orig Sun Dec 15 22:14:30 1996
++++ dump/dump.h Wed Dec 25 16:11:06 1996
+@@ -40,6 +40,9 @@
+ * @(#)dump.h 8.2 (Berkeley) 4/28/95
+ */
+
++/* /etc/dumpdates will not be created, when not already here (Bug#3806).
++ David Frey */
++
+ #define MAXINOPB (MAXBSIZE / sizeof(struct dinode))
+ #define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
+
+@@ -195,8 +198,8 @@
+ int nddates; /* number of records (might be zero) */
+ int ddates_in; /* we have read the increment file */
+ struct dumpdates **ddatev; /* the arrayfied version */
+-void initdumptimes __P((void));
+-void getdumptime __P((void));
++void initdumptimes __P((int));
++void getdumptime __P((int));
+ void putdumptime __P((void));
+ #define ITITERATE(i, ddp) \
+ for (ddp = ddatev[i = 0]; i < nddates; ddp = ddatev[++i])
+--- dump/itime.c.orig Sun Dec 15 22:14:30 1996
++++ dump/itime.c Wed Dec 25 16:18:15 1996
+@@ -4,6 +4,8 @@
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
++/* /etc/dumpdates will not be created, when not already here (Bug#3806).
++ David Frey */
+
+ /*-
+ * Copyright (c) 1980, 1993
+@@ -88,7 +90,8 @@
+ static void readdumptimes __P((FILE *));
+
+ void
+-initdumptimes()
++initdumptimes(createdumpdates)
++int createdumpdates;
+ {
+ FILE *df;
+
+@@ -101,22 +104,26 @@
+ /*
+ * Dumpdates does not exist, make an empty one.
+ */
+- msg("WARNING: no file `%s', making an empty one\n", dumpdates);
+- if ((df = fopen(dumpdates, "w")) == NULL) {
+- quit("cannot create %s: %s\n", dumpdates,
+- strerror(errno));
+- /* NOTREACHED */
++ if (createdumpdates) {
++ msg("WARNING: no file `%s', making an empty one\n", dumpdates);
++ if ((df = fopen(dumpdates, "w")) == NULL) {
++ quit("cannot create %s: %s\n", dumpdates,
++ strerror(errno));
++ /* NOTREACHED */
++ }
++ (void) fclose(df);
++ if ((df = fopen(dumpdates, "r")) == NULL) {
++ quit("cannot read %s even after creating it: %s\n",
++ dumpdates, strerror(errno));
++ /* NOTREACHED */
++ }
+ }
++ }
++ if (df != NULL) {
++ (void) flock(fileno(df), LOCK_SH);
++ readdumptimes(df);
+ (void) fclose(df);
+- if ((df = fopen(dumpdates, "r")) == NULL) {
+- quit("cannot read %s even after creating it: %s\n",
+- dumpdates, strerror(errno));
+- /* NOTREACHED */
+- }
+ }
+- (void) flock(fileno(df), LOCK_SH);
+- readdumptimes(df);
+- (void) fclose(df);
+ }
+
+ static void
+@@ -148,7 +155,8 @@
+ }
+
+ void
+-getdumptime()
++getdumptime(createdumpdates)
++int createdumpdates;
+ {
+ register struct dumpdates *ddp;
+ register int i;
+@@ -162,7 +170,9 @@
+ spcl.c_ddate = 0;
+ lastlevel = '0';
+
+- initdumptimes();
++ initdumptimes(createdumpdates);
++ if (ddp == NULL)
++ return;
+ /*
+ * Go find the entry with the same name for a lower increment
+ * and older date
+--- dump/main.c.orig Sun Dec 15 22:14:30 1996
++++ dump/main.c Wed Dec 25 16:09:26 1996
+@@ -4,6 +4,8 @@
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
++/* /etc/dumpdates will not be created, when not already here (Bug#3806).
++ David Frey */
+
+ /*-
+ * Copyright (c) 1980, 1991, 1993, 1994
+@@ -331,7 +333,7 @@
+ spcl.c_level = level - '0';
+ spcl.c_type = TS_TAPE;
+ if (!Tflag)
+- getdumptime(); /* /etc/dumpdates snarfed */
++ getdumptime(uflag); /* /etc/dumpdates snarfed */
+
+ msg("Date of this level %c dump: %s", level,
+ #ifdef __linux
+--- dump/optr.c.orig Sun Dec 15 22:14:30 1996
++++ dump/optr.c Wed Dec 25 16:09:26 1996
+@@ -4,6 +4,8 @@
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
++/* /etc/dumpdates will not be created, when not already here (Bug#3806).
++ David Frey */
+
+ /*-
+ * Copyright (c) 1980, 1988, 1993
+@@ -534,22 +536,24 @@
+ {
+ register int i;
+ register struct fstab *dt;
+- register struct dumpdates *dtwalk;
++ register struct dumpdates *dtwalk=NULL;
+ char *lastname, *date;
+ int dumpme;
+ time_t tnow;
+
+ (void) time(&tnow);
+ getfstab(); /* /etc/fstab input */
+- initdumptimes(); /* /etc/dumpdates input */
+- qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
+-
+- if (arg == 'w')
+- (void) printf("Dump these file systems:\n");
+- else
++ initdumptimes(0); /* /etc/dumpdates input */
++ if (*ddatev != NULL)
++ {
++ qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
++
++ if (arg == 'w')
++ (void) printf("Dump these file systems:\n");
++ else
+ (void) printf("Last dump(s) done (Dump '>' file systems):\n");
+- lastname = "??";
+- ITITERATE(i, dtwalk) {
++ lastname = "??";
++ ITITERATE(i, dtwalk) {
+ if (strncmp(lastname, dtwalk->dd_name,
+ sizeof(dtwalk->dd_name)) == 0)
+ continue;
+@@ -568,6 +572,7 @@
+ dt ? dt->fs_file : "",
+ dtwalk->dd_level,
+ date);
++ }
+ }
+ }
+
--- /dev/null
+#
+# Insert the header.....
+#
+1i\
+# +++ Dependency line eater +++\
+# \
+# Makefile dependencies follow. This must be the last section in\
+# the Makefile.in file\
+#
+
+#
+# Remove line continuations....
+#
+#:FIRST
+#y/ / /
+#s/^ *//
+#/\\$/{
+#N
+#y/ / /
+#s/\\\n */ /
+#bFIRST
+#}
+#s/ */ /g
+
+s;/usr/include/[^ ]* *;;g
+s;/usr/lib/[^ ]* *;;g
+s;/mit/cygnus[^ ]* *;;g
+
+#
+# Now insert a trailing newline...
+#
+$a\
+
--- /dev/null
+
+ Finally... The public test version of my port of the 4.4BSD dump
+and restore programs to Linux is now available on tsx-11.mit.edu in the
+directory /pub/linux/packages/ext2fs.
+
+ This port understands the Ext2fs structure and is able to backup
+and restore Linux Ext2 filesystems. This is a test version and I have only
+made minimal testing so do not rely too much on it for your backups.
+
+ This version of dump contains all the BSD features and also includes
+some enhancements over the previous test versions:
+ - it is possible to backup a subtree instead of a whole filesystem,
+ - some bugs have been fixed :-)
+ - dump is now able to backup filesystems bigger than 2 GB,
+ - the dump format is now compatible with 4.3BSD. This means that you
+ can restore Linux dumps on BSD based operating systems and you can
+ restore BSD dumps on Linux. I have made some tests with FreeBSD
+ and SunOS 4.1.3 and this works fine. I am interested in reports
+ about other BSD based operating systems.
+
+ I am not sure that multi-volume dumps are Ok. If you use them, please
+send me a bug (or success :-) report.
+
+ The dump format is *not* compatible with the previous test versions
+(versions 0.0 and 0.1), which were distributed as private test versions. If
+you have backups made by dump 0.0 or 0.1, restore 0.2 will not be able to
+read them.
+
+ You need the latest ext2fs programs source distribution to compile dump
+and restore because I have used Theodore T'so's Ext2fs library. The latest
+version (0.5b) of these programs is available on tsx-11.mit.edu in the
+directory /pub/linux/packages/ext2fs. If you want to build ELF binaries, you
+also need to get my ELF patch on ftp.ibp.fr in /pub/linux/ELF/patches.
+
+ I'd like to thank all the people who have used the private test
+versions of dump and restore. I have appreciated their feedback that has
+helped me to improve dump and restore.
+
+--
+Remy Card
+Remy.Card@freenix.fr
--- /dev/null
+
+ I have received bug reports about dump telling that dump receives
+unexpected signals when dump directories (in pass III). I have tried to
+reproduce the problem and it appears that this may be caused by an optimization
+problem in some versions of gcc. Dump works fine when compiled with
+optimization by gcc 2.6.2 but it fails when compiled by gcc 2.6.3:
+ - either it gets an unexpected signal (SIGFPE),
+ - or it issues warnings ``Warning: dumpdirino called with file type
+ 040000'' and does not dump directories.
+
+ I am not courageous enough to study the assembly code generated by
+gcc (yet :-), so I have modified the Makefiles to compile dump without
+optimizations. I have also fixed a few minor bugs and removed some printf's
+that I had added during my tests. I will study the assembly code generated
+by gcc soon and fix the problem.
+
+ The fixed version (numbered 0.2a) is now available on tsx-11.mit.edu
+in the directory /pub/linux/packages/ext2fs. Please get it if you are using
+dump and restore.
+
+ Thanks to Daniel Veillard <Daniel.Veillard@imag.fr>, Bob Snyder
+<rsnyder@janet.advsys.com>, and Florian La Roche <rzsfl@rz.uni-sb.de> for
+their reports and their help!
+
+--
+Remy Card
+Remy.Card@freenix.fr
--- /dev/null
+
+ I have received bug reports about dump telling that dump receives
+unexpected signals when dump directories (in pass III). I have tried to
+reproduce the problem and it appears that this may be caused by an optimization
+problem in some versions of gcc. Dump works fine when compiled with
+optimization by gcc 2.6.2 but it fails when compiled by gcc 2.6.3:
+ - either it gets an unexpected signal (SIGFPE),
+ - or it issues warnings ``Warning: dumpdirino called with file type
+ 040000'' and does not dump directories.
+
+ Finding the problem was not an easy task because the behavior seemed
+to be related to the version of the compiler. Anyway, I have found it :-)
+There was an incorrect assignement in the function dumpdirino(), which is
+responsible for dumping the contents of directories, and this caused some
+problems when compiled with optimizations by some versions of gcc. After
+fixing the problem, dump runs fine when compiled by gcc 2.6.3 or gcc 2.7.0.
+
+ The new fixed version (numbered 0.2b) is now available on
+tsx-11.mit.edu in the directory /pub/linux/packages/ext2fs. Please get it
+if you are using dump and restore.
+
+ Thanks to Daniel Veillard <Daniel.Veillard@imag.fr>, Bob Snyder
+<rsnyder@janet.advsys.com>, and Florian La Roche <rzsfl@rz.uni-sb.de> for
+their reports and their help!
+
+--
+Remy Card
+Remy.Card@freenix.fr
--- /dev/null
+
+ Yet another bug fix release of dump/restore for Ext2fs is available
+on tsx-11.mit.edu in /pub/linux/packages/ext2fs/dump-0.2c.tar.gz.
+
+ A stupid bug has been fixed. This bug caused an incorrect dump of
+``slow'' (i.e. normal) symbolic links. There is no new features (yet :-).
+
+ Thanks to the many people who have sent me success and bug reports!
+
+--
+Remy Card
+Remy.Card@freenix.fr
--- /dev/null
+
+ Ok, I am still trying to saturate comp.os.linux.announce :-) Yet
+another bug fix release of dump/restore for Ext2fs is available on
+tsx-11.mit.edu in /pub/linux/packages/ext2fs/dump-0.2d.tar.gz.
+
+ Dump is now able to backup 2GB+ filesystems. Thanks to Doug Paul
+<dbp@dragonsys.com> for the patch. Dump and restore can now be linked as
+static binaries (you have to edit the file MCONFIG before building them).
+
+--
+Remy Card
+Remy.Card@freenix.fr
--- /dev/null
+
+ Dump 0.2e is now available on tsx-11.mit.edu in the directory
+/pub/linux/packages/ext2fs.
+
+ A stupid bug in the "set owner/mode" pass has been fixed. Files were
+restored with uid=0 and gid=0. The bug was in restore, not in dump, so this
+means that backups made with dump 0.2d are Ok. Thanks to Brent Olson
+<night@halcyon.com> for reporting this problem.
+
+ Thanks also to the patience of the testers :-)
+
+ I remind you that dump and restore should be considered as software
+in BETA test. Don't rely too much on them for your backups...
+
+--
+Remy Card
+Remy.Card@freenix.fr
+
+No to french nuclear experiments!
--- /dev/null
+
+ Ok, I'm back ;-)
+
+ Dump 0.3 is now available on tsx-11.mit.edu in the directory
+/pub/linux/packages/ext2fs.
+
+ Restore is now able to restore named pipes (fifos). Thanks to
+Jason Venner <jason@idiom.com> for reporting the bug. I have also fixed
+a bug in the symlink restoration: owner and group were not set by previous
+version. Thanks to Klaus Kudielka <kkudielk@cacofonix.nt.tuwien.ac.at> for
+reporting it. Restore is now able to restore correctly files ending with
+a hole (mainly DLL shared libraries under Linux). Thanks to David Monro
+<davidm@cs.su.oz.au> for sending me a patch much cleaner than mine :-)
+
+ Kevin Layer <layer@Franz.COM> has implemented a verify option in
+restore. It is now possible to check a dump against the contents of the
+filesystem. Thank you very much, Kevin!
+
+ Some bug fixes from FreeBSD 2.2-current have also been integrated.
+
+ Last, I have added the file `linux-1.2.x.patch' in the distribution.
+This patch for 1.2 kernels should be applied if you want to get better
+performances.
+
+ I remind you that dump and restore should be considered as software
+in BETA test. Don't rely too much on them for your backups...
+
+--
+Remy Card
+Remy.Card@freenix.fr
+
+No to nuclear testings!
--- /dev/null
+
+ A test release of dump 0.4 is now available on tsx-11.mit.edu,
+in the file /pub/linux/ALPHA/ext2fs/dump-0.4b1.tar.gz.
+
+ This new version is based on the latest dump and restore suite
+available from Berkeley (I have integrated the changes from 4.4BSD-Lite2).
+
+ It also includes lots of changes from the Debian 1.2 and Red Hat 4.0
+distributions (I have included most of the patches made by maintainers of
+these distributions).
+
+ Some changes were made to improve the portability of dump and restore:
+ - fixed size types are now used, so that the dump format is the same
+ on every architecture supported by Linux,
+ - dump now uses the Ext2fs library to get the block addresses
+ to solve an endianness problem that was present on SparcLinux.
+
+ Autoconf is now used to configure dump and restore. I have shamelessly
+adapted the configure script from the one present in the e2fsprogs
+distribution (thanks Ted!).
+
+ Last, a few minor bugs have been fixed.
+
+ This version is a test release. Use it only for testing :-) New
+beta versions will probably be released before a stable dump 0.4 version is
+available.
+
+ If you encounter problems with this test release, please send a
+detailled bug report (please look at the file KNOWNBUGS before sending a
+bug report).
+
+--
+Remy Card
+card@Linux.EU.Org
+
--- /dev/null
+Begin3
+Title: dump and restore for Ext2fs
+Version: 0.4b4
+Entered-date: 17JAN97
+Description: Port of the 4.4BSD dump and restore backup suite
+Keywords: backup, filesystem, Ext2fs
+Author: University of California, Berkeley
+Maintained-by: card@Linux.EU.Org (Remy Card)
+Primary-site: tsx-11.mit.edu /pub/linux/ALPHA/ext2fs
+ 126kB dump-0.4b4.tar.gz
+ 627 dump.lsm
+Alternate-site:
+Original-site: ftp.freebsd.org /pub/bsd-sources/4.4BSD-Lite2/sbin
+ dump/*
+ restore/*
+Platforms: linux 2.0.x, e2fsprogs 1.06
+Copying-policy: BSD
+End
--- /dev/null
+top_srcdir= @top_srcdir@
+srcdir= @srcdir@
+
+@MCONFIG@
+
+CFLAGS= @CCOPTS@ -pipe $(GINC) $(INC) $(DEFS) @DUMPDEBUG@
+LDFLAGS:= $(LDFLAGS) @STATIC@
+LIBS= $(GLIBS)
+DEPLIBS= ../compat/lib/libcompat.a
+
+PROG= dump
+LINKS= ${BINDIR}/dump ${BINDIR}/rdump
+SRCS= itime.c main.c optr.c tape.c traverse.c unctime.c
+OBJS= itime.o main.o optr.o tape.o traverse.o unctime.o \
+ ../common/dumprmt.o
+MAN8= dump.8
+MLINKS= $(MANDIR)/dump.8 $(MANDIR)/rdump.8
+
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(DEPLIBS)
+ $(LD) $(CFLAGS) $(LDFLAGS) -o $(PROG) $(OBJS) $(LIBS)
+
+install:: $(PROG)
+ $(INSTALLBIN) $(PROG) $(BINDIR)
+ $(INSTALLMAN) $(srcdir)/$(MAN8) $(MANDIR)
+ @set $(LINKS) $(MLINKS); \
+ while test $$# -ge 2; do \
+ l=$(DESTDIR)$$1; \
+ shift; \
+ t=$(DESTDIR)$$1; \
+ shift; \
+ echo $$t -\> $$l; \
+ $(RM) -f $$t; \
+ $(LN_S) $$l $$t; \
+ done; true
+
+clean::
+ $(RM) -f $(PROG) \#* *.s *.o *.a *~ core
+
+distclean:: clean
+ $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+
--- /dev/null
+.\" Copyright (c) 1980, 1991, 1993
+.\" Regents of the University of California.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)dump.8 8.3 (Berkeley) 5/1/95
+.\"
+.Dd May 1, 1995
+.Dt DUMP 8
+.Os BSD 4
+.Sh NAME
+.Nm dump
+.Nd filesystem backup
+.Sh SYNOPSIS
+.Nm dump
+.Op Fl 0123456789cnu
+.Op Fl B Ar records
+.Op Fl b Ar blocksize
+.Op Fl d Ar density
+.Op Fl f Ar file
+.Op Fl h Ar level
+.Op Fl s Ar feet
+.Op Fl T Ar date
+.Ar filesystem
+.Nm dump
+.Op Fl 0123456789cnu
+.Op Fl B Ar records
+.Op Fl b Ar blocksize
+.Op Fl d Ar density
+.Op Fl f Ar file
+.Op Fl h Ar level
+.Op Fl s Ar feet
+.Op Fl T Ar date
+.Ar directory
+.Nm dump
+.Op Fl W Li \&| Fl w
+.Pp
+.in -\\n(iSu
+(The
+.Bx 4.3
+option syntax is implemented for backward compatibility, but
+is not documented here.)
+.Sh DESCRIPTION
+.Nm Dump
+examines files
+on a filesystem
+and determines which files
+need to be backed up. These files
+are copied to the given disk, tape or other
+storage medium for safe keeping (see the
+.Fl f
+option below for doing remote backups).
+A dump that is larger than the output medium is broken into
+multiple volumes.
+On most media the size is determined by writing until an
+end-of-media indication is returned.
+On media that cannot reliably return an end-of-media indication
+(such as some cartridge tape drives)
+each volume is of a fixed size;
+the actual size is determined by the tape size and density and/or
+block count options below.
+By default, the same output file name is used for each volume
+after prompting the operator to change media.
+.Pp
+The following options are supported by
+.Nm dump :
+.Bl -tag -width Ds
+.It Fl 0\-9
+Dump levels.
+A level 0, full backup,
+guarantees the entire file system is copied
+(but see also the
+.Fl h
+option below).
+A level number above 0,
+incremental backup,
+tells dump to
+copy all files new or modified since the
+last dump of the same or lower level.
+The default level is 9.
+.It Fl B Ar records
+The number of dump records per volume.
+This option overrides the calculation of tape size
+based on length and density.
+.It Fl b Ar blocksize
+The number of kilobytes per dump record.
+.It Fl c
+Modify the calculation of the default density and tape size to be more
+appropriate for cartridge tapes.
+.It Fl d Ar density
+Set tape density to
+.Ar density .
+The default is 1600BPI.
+.It Fl f Ar file
+Write the backup to
+.Ar file ;
+.Ar file
+may be a special device file
+like
+.Pa /dev/rmt12
+(a tape drive),
+.Pa /dev/rsd1c
+(a disk drive),
+an ordinary file,
+or
+.Ql Fl
+(the standard output).
+Multiple file names may be given as a single argument separated by commas.
+Each file will be used for one dump volume in the order listed;
+if the dump requires more volumes than the number of names given,
+the last file name will used for all remaining volumes after prompting
+for media changes.
+If the name of the file is of the form
+.Dq host:file ,
+or
+.Dq user@host:file ,
+.Nm dump
+writes to the named file on the remote host using
+.Xr rmt 8 .
+.It Fl h Ar level
+Honor the user
+.Dq nodump
+flag
+.Dp Dv UF_NODUMP
+only for dumps at or above the given
+.Ar level .
+The default honor level is 1,
+so that incremental backups omit such files
+but full backups retain them.
+.It Fl n
+Whenever
+.Nm dump
+requires operator attention,
+notify all operators in the group
+.Dq operator
+by means similar to a
+.Xr wall 1 .
+.It Fl s Ar feet
+Attempt to calculate the amount of tape needed
+at a particular density.
+If this amount is exceeded,
+.Nm dump
+prompts for a new tape.
+It is recommended to be a bit conservative on this option.
+The default tape length is 2300 feet.
+.ne 1i
+.It Fl T Ar date
+Use the specified date as the starting time for the dump
+instead of the time determined from looking in
+.Pa /etc/dumpdates .
+The format of date is the same as that of
+.Xr ctime 3 .
+This option is useful for automated dump scripts that wish to
+dump over a specific period of time.
+The
+.Fl T
+option is mutually exclusive from the
+.Fl u
+option.
+.It Fl u
+Update the file
+.Pa /etc/dumpdates
+after a successful dump.
+The format of
+.Pa /etc/dumpdates
+is readable by people, consisting of one
+free format record per line:
+filesystem name,
+increment level
+and
+.Xr ctime 3
+format dump date.
+There may be only one entry per filesystem at each level.
+The file
+.Pa /etc/dumpdates
+may be edited to change any of the fields,
+if necessary.
+.It Fl W
+.Nm Dump
+tells the operator what file systems need to be dumped.
+This information is gleaned from the files
+.Pa /etc/dumpdates
+and
+.Pa /etc/fstab .
+The
+.Fl W
+option causes
+.Nm dump
+to print out, for each file system in
+.Pa /etc/dumpdates
+the most recent dump date and level,
+and highlights those file systems that should be dumped.
+If the
+.Fl W
+option is set, all other options are ignored, and
+.Nm dump
+exits immediately.
+.It Fl w
+Is like W, but prints only those filesystems which need to be dumped.
+.El
+.Pp
+.Nm Dump
+requires operator intervention on these conditions:
+end of tape,
+end of dump,
+tape write error,
+tape open error or
+disk read error (if there are more than a threshold of 32).
+In addition to alerting all operators implied by the
+.Fl n
+key,
+.Nm dump
+interacts with the operator on
+.Em dump's
+control terminal at times when
+.Nm dump
+can no longer proceed,
+or if something is grossly wrong.
+All questions
+.Nm dump
+poses
+.Em must
+be answered by typing
+.Dq yes
+or
+.Dq no ,
+appropriately.
+.Pp
+Since making a dump involves a lot of time and effort for full dumps,
+.Nm dump
+checkpoints itself at the start of each tape volume.
+If writing that volume fails for some reason,
+.Nm dump
+will,
+with operator permission,
+restart itself from the checkpoint
+after the old tape has been rewound and removed,
+and a new tape has been mounted.
+.Pp
+.Nm Dump
+tells the operator what is going on at periodic intervals,
+including usually low estimates of the number of blocks to write,
+the number of tapes it will take, the time to completion, and
+the time to the tape change.
+The output is verbose,
+so that others know that the terminal
+controlling
+.Nm dump
+is busy,
+and will be for some time.
+.Pp
+In the event of a catastrophic disk event, the time required
+to restore all the necessary backup tapes or files to disk
+can be kept to a minimum by staggering the incremental dumps.
+An efficient method of staggering incremental dumps
+to minimize the number of tapes follows:
+.Bl -bullet -offset indent
+.It
+Always start with a level 0 backup, for example:
+.Bd -literal -offset indent
+/sbin/dump -0u -f /dev/nrst1 /usr/src
+.Ed
+.Pp
+This should be done at set intervals, say once a month or once every two months,
+and on a set of fresh tapes that is saved forever.
+.It
+After a level 0, dumps of active file
+systems are taken on a daily basis,
+using a modified Tower of Hanoi algorithm,
+with this sequence of dump levels:
+.Bd -literal -offset indent
+3 2 5 4 7 6 9 8 9 9 ...
+.Ed
+.Pp
+For the daily dumps, it should be possible to use a fixed number of tapes
+for each day, used on a weekly basis.
+Each week, a level 1 dump is taken, and
+the daily Hanoi sequence repeats beginning with 3.
+For weekly dumps, another fixed set of tapes per dumped file system is
+used, also on a cyclical basis.
+.El
+.Pp
+After several months or so, the daily and weekly tapes should get
+rotated out of the dump cycle and fresh tapes brought in.
+.Sh FILES
+.Bl -tag -width /etc/dumpdates -compact
+.It Pa /dev/rmt8
+default tape unit to dump to
+.It Pa /etc/dumpdates
+dump date records
+.It Pa /etc/fstab
+dump table: file systems and frequency
+.It Pa /etc/group
+to find group
+.Em operator
+.El
+.Sh SEE ALSO
+.Xr restore 8 ,
+.Xr rmt 8 ,
+.Xr dump 5 ,
+.Xr fstab 5
+.Sh DIAGNOSTICS
+Many, and verbose.
+.Pp
+Dump exits with zero status on success.
+Startup errors are indicated with an exit code of 1;
+abnormal termination is indicated with an exit code of 3.
+.Sh BUGS
+Fewer than 32 read errors on the filesystem are ignored.
+.Pp
+Each reel requires a new process, so parent processes for
+reels already written just hang around until the entire tape
+is written.
+.Pp
+.Nm Dump
+with the
+.Fl W
+or
+.Fl w
+options does not report filesystems that have never been recorded
+in
+.Pa /etc/dumpdates ,
+even if listed in
+.Pa /etc/fstab .
+.Pp
+It would be nice if
+.Nm dump
+knew about the dump sequence,
+kept track of the tapes scribbled on,
+told the operator which tape to mount when,
+and provided more assistance
+for the operator running
+.Xr restore .
+.Sh HISTORY
+A
+.Nm dump
+command appeared in Version 6 AT&T UNIX.
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)dump.h 8.2 (Berkeley) 4/28/95
+ */
+
+#define MAXINOPB (MAXBSIZE / sizeof(struct dinode))
+#define MAXNINDIR (MAXBSIZE / sizeof(daddr_t))
+
+/*
+ * Dump maps used to describe what is to be dumped.
+ */
+int mapsize; /* size of the state maps */
+char *usedinomap; /* map of allocated inodes */
+char *dumpdirmap; /* map of directories to be dumped */
+char *dumpinomap; /* map of files to be dumped */
+/*
+ * Map manipulation macros.
+ */
+#define SETINO(ino, map) \
+ map[(u_int)((ino) - 1) / NBBY] |= 1 << ((u_int)((ino) - 1) % NBBY)
+#define CLRINO(ino, map) \
+ map[(u_int)((ino) - 1) / NBBY] &= ~(1 << ((u_int)((ino) - 1) % NBBY))
+#define TSTINO(ino, map) \
+ (map[(u_int)((ino) - 1) / NBBY] & (1 << ((u_int)((ino) - 1) % NBBY)))
+
+/*
+ * All calculations done in 0.1" units!
+ */
+char *disk; /* name of the disk file */
+char *tape; /* name of the tape file */
+char *dumpdates; /* name of the file containing dump date information*/
+char *temp; /* name of the file for doing rewrite of dumpdates */
+char lastlevel; /* dump level of previous dump */
+char level; /* dump level of this dump */
+int uflag; /* update flag */
+int diskfd; /* disk file descriptor */
+int tapefd; /* tape file descriptor */
+int pipeout; /* true => output to standard output */
+ino_t curino; /* current inumber; used globally */
+int newtape; /* new tape flag */
+int density; /* density in 0.1" units */
+long tapesize; /* estimated tape size, blocks */
+long tsize; /* tape size in 0.1" units */
+long asize; /* number of 0.1" units written on current tape */
+int etapes; /* estimated number of tapes */
+int nonodump; /* if set, do not honor UF_NODUMP user flags */
+
+int notify; /* notify operator flag */
+int blockswritten; /* number of blocks written on current tape */
+int tapeno; /* current tape number */
+time_t tstart_writing; /* when started writing the first tape block */
+#ifdef __linux__
+time_t tend_writing; /* after writing the last tape block */
+ext2_filsys fs;
+#else
+struct fs *sblock; /* the file system super block */
+char sblock_buf[MAXBSIZE];
+#endif
+long dev_bsize; /* block size of underlying disk device */
+int dev_bshift; /* log2(dev_bsize) */
+int tp_bshift; /* log2(TP_BSIZE) */
+
+#ifndef __P
+#include <sys/cdefs.h>
+#endif
+
+/* operator interface functions */
+void broadcast __P((char *message));
+void lastdump __P((int arg)); /* int should be char */
+void msg __P((const char *fmt, ...));
+void msgtail __P((const char *fmt, ...));
+int query __P((char *question));
+void quit __P((const char *fmt, ...));
+void set_operators __P((void));
+void timeest __P((void));
+time_t unctime __P((char *str));
+
+/* mapping rouintes */
+struct dinode;
+long blockest __P((struct dinode *dp));
+int mapfiles __P((ino_t maxino, long *tapesize));
+#ifdef __linux__
+int mapfilesfromdir __P((ino_t maxino, long *tapesize, char *directory));
+#endif
+int mapdirs __P((ino_t maxino, long *tapesize));
+
+/* file dumping routines */
+void blksout __P((daddr_t *blkp, int frags, ino_t ino));
+void bread __P((daddr_t blkno, char *buf, int size));
+void dumpino __P((struct dinode *dp, ino_t ino));
+#ifdef __linux__
+void dumpdirino __P((struct dinode *dp, ino_t ino));
+#endif
+void dumpmap __P((char *map, int type, ino_t ino));
+void writeheader __P((ino_t ino));
+
+/* tape writing routines */
+int alloctape __P((void));
+void close_rewind __P((void));
+void dumpblock __P((daddr_t blkno, int size));
+void startnewtape __P((int top));
+void trewind __P((void));
+void writerec __P((char *dp, int isspcl));
+
+__dead void Exit __P((int status));
+void dumpabort __P((int signo));
+void getfstab __P((void));
+
+char *rawname __P((char *cp));
+struct dinode *getino __P((ino_t inum));
+
+/* rdump routines */
+#ifdef RDUMP
+void rmtclose __P((void));
+int rmthost __P((char *host));
+int rmtopen __P((char *tape, int mode));
+int rmtwrite __P((char *buf, int count));
+#endif /* RDUMP */
+
+void interrupt __P((int signo)); /* in case operator bangs on console */
+
+/*
+ * Exit status codes
+ */
+#define X_FINOK 0 /* normal exit */
+#define X_REWRITE 2 /* restart writing from the check point */
+#define X_ABORT 3 /* abort dump; don't attempt checkpointing */
+
+#define OPGRENT "operator" /* group entry to notify */
+#ifdef __linux__
+#define DIALUP "ttyS" /* prefix for dialups */
+#else
+#define DIALUP "ttyd" /* prefix for dialups */
+#endif
+
+struct fstab *fstabsearch __P((char *key)); /* search fs_file and fs_spec */
+#ifdef __linux__
+struct fstab *fstabsearchdir __P((char *key, char *dir)); /* search fs_file and fs_spec */
+#endif
+
+#ifndef NAME_MAX
+#define NAME_MAX 255
+#endif
+
+/*
+ * The contents of the file _PATH_DUMPDATES is maintained both on
+ * a linked list, and then (eventually) arrayified.
+ */
+struct dumpdates {
+ char dd_name[NAME_MAX+3];
+ char dd_level;
+ time_t dd_ddate;
+};
+struct dumptime {
+ struct dumpdates dt_value;
+ struct dumptime *dt_next;
+};
+struct dumptime *dthead; /* head of the list version */
+int nddates; /* number of records (might be zero) */
+int ddates_in; /* we have read the increment file */
+struct dumpdates **ddatev; /* the arrayfied version */
+void initdumptimes __P((void));
+void getdumptime __P((void));
+void putdumptime __P((void));
+#define ITITERATE(i, ddp) \
+ for (ddp = ddatev[i = 0]; i < nddates; ddp = ddatev[++i])
+
+void sig __P((int signo));
+
+/*
+ * Compatibility with old systems.
+ */
+#ifdef COMPAT
+#include <sys/file.h>
+#define strchr(a,b) index(a,b)
+#define strrchr(a,b) rindex(a,b)
+extern char *strdup(), *ctime();
+extern int read(), write();
+extern int errno;
+#endif
+
+#ifdef __linux__
+#define DUMP_CURRENT_REV 0
+#endif
+
+#ifndef __linux__
+#ifndef _PATH_UTMP
+#define _PATH_UTMP "/etc/utmp"
+#endif
+#ifndef _PATH_FSTAB
+#define _PATH_FSTAB "/etc/fstab"
+#endif
+#endif
+
+#ifdef sunos
+extern char *calloc();
+extern char *malloc();
+extern long atol();
+extern char *strcpy();
+extern char *strncpy();
+extern char *strcat();
+extern time_t time();
+extern void endgrent();
+extern __dead void exit();
+extern off_t lseek();
+extern const char *strerror();
+#endif
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)itime.c 8.1 (Berkeley) 6/5/93";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#include <sys/file.h>
+#else
+#ifdef sunos
+#include <sys/vnode.h>
+
+#include <ufs/fsdir.h>
+#include <ufs/inode.h>
+#include <ufs/fs.h>
+#else
+#include <ufs/ufs/dinode.h>
+#endif
+#endif
+
+#include <protocols/dumprestore.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "dump.h"
+
+struct dumpdates **ddatev = 0;
+int nddates = 0;
+int ddates_in = 0;
+struct dumptime *dthead = 0;
+
+static void dumprecout __P((FILE *, struct dumpdates *));
+static int getrecord __P((FILE *, struct dumpdates *));
+static int makedumpdate __P((struct dumpdates *, char *));
+static void readdumptimes __P((FILE *));
+
+void
+initdumptimes()
+{
+ FILE *df;
+
+ if ((df = fopen(dumpdates, "r")) == NULL) {
+ if (errno != ENOENT) {
+ quit("cannot read %s: %s\n", dumpdates,
+ strerror(errno));
+ /* NOTREACHED */
+ }
+ /*
+ * Dumpdates does not exist, make an empty one.
+ */
+ msg("WARNING: no file `%s', making an empty one\n", dumpdates);
+ if ((df = fopen(dumpdates, "w")) == NULL) {
+ quit("cannot create %s: %s\n", dumpdates,
+ strerror(errno));
+ /* NOTREACHED */
+ }
+ (void) fclose(df);
+ if ((df = fopen(dumpdates, "r")) == NULL) {
+ quit("cannot read %s even after creating it: %s\n",
+ dumpdates, strerror(errno));
+ /* NOTREACHED */
+ }
+ }
+ (void) flock(fileno(df), LOCK_SH);
+ readdumptimes(df);
+ (void) fclose(df);
+}
+
+static void
+readdumptimes(df)
+ FILE *df;
+{
+ register int i;
+ register struct dumptime *dtwalk;
+
+ for (;;) {
+ dtwalk = (struct dumptime *)calloc(1, sizeof (struct dumptime));
+ if (getrecord(df, &(dtwalk->dt_value)) < 0)
+ break;
+ nddates++;
+ dtwalk->dt_next = dthead;
+ dthead = dtwalk;
+ }
+
+ ddates_in = 1;
+ /*
+ * arrayify the list, leaving enough room for the additional
+ * record that we may have to add to the ddate structure
+ */
+ ddatev = (struct dumpdates **)
+ calloc((unsigned) (nddates + 1), sizeof (struct dumpdates *));
+ dtwalk = dthead;
+ for (i = nddates - 1; i >= 0; i--, dtwalk = dtwalk->dt_next)
+ ddatev[i] = &dtwalk->dt_value;
+}
+
+void
+getdumptime()
+{
+ register struct dumpdates *ddp;
+ register int i;
+ char *fname;
+
+ fname = disk;
+#ifdef FDEBUG
+ msg("Looking for name %s in dumpdates = %s for level = %c\n",
+ fname, dumpdates, level);
+#endif
+ spcl.c_ddate = 0;
+ lastlevel = '0';
+
+ initdumptimes();
+ /*
+ * Go find the entry with the same name for a lower increment
+ * and older date
+ */
+ ITITERATE(i, ddp) {
+ if (strncmp(fname, ddp->dd_name, sizeof (ddp->dd_name)) != 0)
+ continue;
+ if (ddp->dd_level >= level)
+ continue;
+#ifdef __linux__
+ if (ddp->dd_ddate <= (time_t)spcl.c_ddate)
+#else
+ if (ddp->dd_ddate <= spcl.c_ddate)
+#endif
+ continue;
+ spcl.c_ddate = ddp->dd_ddate;
+ lastlevel = ddp->dd_level;
+ }
+}
+
+void
+putdumptime()
+{
+ FILE *df;
+ register struct dumpdates *dtwalk;
+ register int i;
+ int fd;
+ char *fname;
+
+ if(uflag == 0)
+ return;
+ if ((df = fopen(dumpdates, "r+")) == NULL)
+ quit("cannot rewrite %s: %s\n", dumpdates, strerror(errno));
+ fd = fileno(df);
+ (void) flock(fd, LOCK_EX);
+ fname = disk;
+ free((char *)ddatev);
+ ddatev = 0;
+ nddates = 0;
+ dthead = 0;
+ ddates_in = 0;
+ readdumptimes(df);
+ if (fseek(df, 0L, 0) < 0)
+ quit("fseek: %s\n", strerror(errno));
+ spcl.c_ddate = 0;
+ ITITERATE(i, dtwalk) {
+ if (strncmp(fname, dtwalk->dd_name,
+ sizeof (dtwalk->dd_name)) != 0)
+ continue;
+ if (dtwalk->dd_level != level)
+ continue;
+ goto found;
+ }
+ /*
+ * construct the new upper bound;
+ * Enough room has been allocated.
+ */
+ dtwalk = ddatev[nddates] =
+ (struct dumpdates *)calloc(1, sizeof (struct dumpdates));
+ nddates += 1;
+ found:
+ (void) strncpy(dtwalk->dd_name, fname, sizeof (dtwalk->dd_name));
+ dtwalk->dd_level = level;
+ dtwalk->dd_ddate = spcl.c_date;
+
+ ITITERATE(i, dtwalk) {
+ dumprecout(df, dtwalk);
+ }
+ if (fflush(df))
+ quit("%s: %s\n", dumpdates, strerror(errno));
+ if (ftruncate(fd, ftell(df)))
+ quit("ftruncate (%s): %s\n", dumpdates, strerror(errno));
+ (void) fclose(df);
+ msg("level %c dump on %s", level,
+#ifdef __linux__
+ spcl.c_date == 0 ? "the epoch\n" : ctime4(&spcl.c_date));
+#else
+ spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
+#endif
+}
+
+static void
+dumprecout(file, what)
+ FILE *file;
+ struct dumpdates *what;
+{
+
+ if (fprintf(file, DUMPOUTFMT,
+ what->dd_name,
+ what->dd_level,
+ ctime(&what->dd_ddate)) < 0)
+ quit("%s: %s\n", dumpdates, strerror(errno));
+}
+
+int recno;
+
+static int
+getrecord(df, ddatep)
+ FILE *df;
+ struct dumpdates *ddatep;
+{
+ char tbuf[BUFSIZ];
+
+ recno = 0;
+ if ( (fgets(tbuf, sizeof (tbuf), df)) != tbuf)
+ return(-1);
+ recno++;
+ if (makedumpdate(ddatep, tbuf) < 0)
+ msg("Unknown intermediate format in %s, line %d\n",
+ dumpdates, recno);
+
+#ifdef FDEBUG
+ msg("getrecord: %s %c %s", ddatep->dd_name, ddatep->dd_level,
+ ddatep->dd_ddate == 0 ? "the epoch\n" : ctime(&ddatep->dd_ddate));
+#endif
+ return(0);
+}
+
+static int
+makedumpdate(ddp, tbuf)
+ struct dumpdates *ddp;
+ char *tbuf;
+{
+ char un_buf[128];
+
+ (void) sscanf(tbuf, DUMPINFMT, ddp->dd_name, &ddp->dd_level, un_buf);
+ ddp->dd_ddate = unctime(un_buf);
+ if (ddp->dd_ddate < 0)
+ return(-1);
+ return(0);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1991, 1993, 1994
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1980, 1991, 1993, 1994\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/1/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <sys/stat.h>
+#include <bsdcompat.h>
+#else
+#ifdef sunos
+#include <sys/vnode.h>
+
+#include <ufs/inode.h>
+#include <ufs/fs.h>
+#else
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#endif
+#endif
+
+#include <protocols/dumprestore.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <fstab.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "dump.h"
+#include "pathnames.h"
+
+#ifndef SBOFF
+#define SBOFF (SBLOCK * DEV_BSIZE)
+#endif
+
+int notify = 0; /* notify operator flag */
+int blockswritten = 0; /* number of blocks written on current tape */
+int tapeno = 0; /* current tape number */
+int density = 0; /* density in bytes/0.1" */
+int ntrec = NTREC; /* # tape blocks in each tape record */
+int cartridge = 0; /* Assume non-cartridge tape */
+long dev_bsize = 1; /* recalculated below */
+long blocksperfile; /* output blocks per file */
+char *host = NULL; /* remote host (if any) */
+
+#ifdef __linux__
+char *__progname;
+#endif
+
+static long numarg __P((char *, long, long));
+static void obsolete __P((int *, char **[]));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ register ino_t ino;
+ register int dirty;
+ register struct dinode *dp;
+ register struct fstab *dt;
+ register char *map;
+ register int ch;
+ int i, anydirskipped, bflag = 0, Tflag = 0, honorlevel = 1;
+ ino_t maxino;
+#ifdef __linux__
+ errcode_t retval;
+ char directory[NAME_MAX];
+ char pathname[NAME_MAX];
+#endif
+
+ spcl.c_date = 0;
+#ifdef __linux__
+ (void)time4(&spcl.c_date);
+#else
+ (void)time((time_t *)&spcl.c_date);
+#endif
+
+#ifdef __linux__
+ __progname = argv[0];
+ directory[0] = 0;
+ initialize_ext2_error_table();
+#endif
+
+ tsize = 0; /* Default later, based on 'c' option for cart tapes */
+ tape = _PATH_DEFTAPE;
+ dumpdates = _PATH_DUMPDATES;
+ temp = _PATH_DTMP;
+ if (TP_BSIZE / DEV_BSIZE == 0 || TP_BSIZE % DEV_BSIZE != 0)
+ quit("TP_BSIZE must be a multiple of DEV_BSIZE\n");
+ level = '0';
+ if (argc < 2)
+ usage();
+
+ obsolete(&argc, &argv);
+ while ((ch = getopt(argc, argv, "0123456789B:b:cd:f:h:ns:T:uWw")) != -1) switch (ch) {
+ /* dump level */
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ level = ch;
+ break;
+
+ case 'B': /* blocks per output file */
+ blocksperfile = numarg("blocks per file", 1L, 0L);
+ break;
+
+ case 'b': /* blocks per tape write */
+ ntrec = numarg("blocks per write", 1L, 1000L);
+ break;
+
+ case 'c': /* Tape is cart. not 9-track */
+ cartridge = 1;
+ break;
+
+ case 'd': /* density, in bits per inch */
+ density = numarg("density", 10L, 327670L) / 10;
+ if (density >= 625 && !bflag)
+ ntrec = HIGHDENSITYTREC;
+ break;
+
+ case 'f': /* output file */
+ tape = optarg;
+ break;
+
+ case 'h':
+ honorlevel = numarg("honor level", 0L, 10L);
+ break;
+
+ case 'n': /* notify operators */
+ notify = 1;
+ break;
+
+ case 's': /* tape size, feet */
+ tsize = numarg("tape size", 1L, 0L) * 12 * 10;
+ break;
+
+ case 'T': /* time of last dump */
+ spcl.c_ddate = unctime(optarg);
+ if (spcl.c_ddate < 0) {
+ (void)fprintf(stderr, "bad time \"%s\"\n",
+ optarg);
+ exit(X_ABORT);
+ }
+ Tflag = 1;
+ lastlevel = '?';
+
+ case 'u': /* update /etc/dumpdates */
+ uflag = 1;
+ break;
+
+ case 'W': /* what to do */
+ case 'w':
+ lastdump(ch);
+ exit(0); /* do nothing else */
+
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (argc < 1) {
+ (void)fprintf(stderr, "Must specify disk or filesystem\n");
+ exit(X_ABORT);
+ }
+ disk = *argv++;
+ argc--;
+ if (argc >= 1) {
+ (void)fprintf(stderr, "Unknown arguments to dump:");
+ while (argc--)
+ (void)fprintf(stderr, " %s", *argv++);
+ (void)fprintf(stderr, "\n");
+ exit(X_ABORT);
+ }
+ if (Tflag && uflag) {
+ (void)fprintf(stderr,
+ "You cannot use the T and u flags together.\n");
+ exit(X_ABORT);
+ }
+ if (strcmp(tape, "-") == 0) {
+ pipeout++;
+ tape = "standard output";
+ }
+
+ if (blocksperfile)
+ blocksperfile = blocksperfile / ntrec * ntrec; /* round down */
+ else {
+ /*
+ * Determine how to default tape size and density
+ *
+ * density tape size
+ * 9-track 1600 bpi (160 bytes/.1") 2300 ft.
+ * 9-track 6250 bpi (625 bytes/.1") 2300 ft.
+ * cartridge 8000 bpi (100 bytes/.1") 1700 ft.
+ * (450*4 - slop)
+ */
+ if (density == 0)
+ density = cartridge ? 100 : 160;
+ if (tsize == 0)
+ tsize = cartridge ? 1700L*120L : 2300L*120L;
+ }
+
+ if (strchr(tape, ':')) {
+ host = tape;
+ tape = strchr(host, ':');
+ *tape++ = '\0';
+#ifdef RDUMP
+ if (rmthost(host) == 0)
+ exit(X_ABORT);
+#else
+ (void)fprintf(stderr, "remote dump not enabled\n");
+ exit(X_ABORT);
+#endif
+ }
+ (void)setuid(getuid()); /* rmthost() is the only reason to be setuid */
+
+ if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
+ signal(SIGHUP, sig);
+ if (signal(SIGTRAP, SIG_IGN) != SIG_IGN)
+ signal(SIGTRAP, sig);
+ if (signal(SIGFPE, SIG_IGN) != SIG_IGN)
+ signal(SIGFPE, sig);
+ if (signal(SIGBUS, SIG_IGN) != SIG_IGN)
+ signal(SIGBUS, sig);
+ if (signal(SIGSEGV, SIG_IGN) != SIG_IGN)
+ signal(SIGSEGV, sig);
+ if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
+ signal(SIGTERM, sig);
+ if (signal(SIGINT, interrupt) == SIG_IGN)
+ signal(SIGINT, SIG_IGN);
+
+ set_operators(); /* /etc/group snarfed */
+ getfstab(); /* /etc/fstab snarfed */
+ /*
+ * disk can be either the full special file name,
+ * the suffix of the special file name,
+ * the special name missing the leading '/',
+ * the file system name with or without the leading '/'.
+ */
+ dt = fstabsearch(disk);
+ if (dt != NULL) {
+ disk = rawname(dt->fs_spec);
+ (void)strncpy(spcl.c_dev, dt->fs_spec, NAMELEN);
+ (void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
+#ifdef __linux__
+ } else {
+ /*
+ * The argument was not found in the fstab
+ * assume that this is a subtree and search for it
+ */
+#ifdef HAVE_REALPATH
+ if (realpath(disk, pathname) == NULL)
+#endif
+ strcpy(pathname, disk);
+ dt = fstabsearchdir(pathname, directory);
+ if (dt != NULL) {
+ char name[MAXPATHLEN];
+ (void)sprintf(name, "%s (dir %s)",
+ dt->fs_spec, directory);
+ (void)strncpy(spcl.c_dev, name, NAMELEN);
+ (void)strncpy(spcl.c_filesys, dt->fs_file, NAMELEN);
+ disk = rawname(dt->fs_spec);
+ } else {
+ (void)strncpy(spcl.c_dev, disk, NAMELEN);
+ (void)strncpy(spcl.c_filesys, "an unlisted file system",
+ NAMELEN);
+ }
+ }
+#else
+ } else {
+ (void)strncpy(spcl.c_dev, disk, NAMELEN);
+ (void)strncpy(spcl.c_filesys, "an unlisted file system",
+ NAMELEN);
+ }
+#endif
+ (void)strcpy(spcl.c_label, "none");
+ (void)gethostname(spcl.c_host, NAMELEN);
+ spcl.c_level = level - '0';
+ spcl.c_type = TS_TAPE;
+ if (!Tflag)
+ getdumptime(); /* /etc/dumpdates snarfed */
+
+ msg("Date of this level %c dump: %s", level,
+#ifdef __linux
+ spcl.c_date == 0 ? "the epoch\n" : ctime4(&spcl.c_date));
+#else
+ spcl.c_date == 0 ? "the epoch\n" : ctime(&spcl.c_date));
+#endif
+ msg("Date of last level %c dump: %s", lastlevel,
+#ifdef __linux__
+ spcl.c_ddate == 0 ? "the epoch\n" : ctime4(&spcl.c_ddate));
+#else
+ spcl.c_ddate == 0 ? "the epoch\n" : ctime(&spcl.c_ddate));
+#endif
+ msg("Dumping %s ", disk);
+ if (dt != NULL)
+ msgtail("(%s) ", dt->fs_file);
+ if (host)
+ msgtail("to %s on host %s\n", tape, host);
+ else
+ msgtail("to %s\n", tape);
+
+#ifdef __linux__
+ retval = ext2fs_open(disk, 0, 0, 0, unix_io_manager, &fs);
+ if (retval) {
+ com_err(disk, retval, "while opening filesystem");
+ if (retval == EXT2_ET_REV_TOO_HIGH)
+ printf ("Get a newer version of dump!\n");
+ exit(X_ABORT);
+ }
+ if (fs->super->s_rev_level > DUMP_CURRENT_REV) {
+ com_err(disk, retval, "while opening filesystem");
+ printf ("Get a newer version of dump!\n");
+ exit(X_ABORT);
+ }
+ if ((diskfd = open(disk, O_RDONLY)) < 0) {
+ msg("Cannot open %s\n", disk);
+ exit(X_ABORT);
+ }
+ sync();
+ dev_bsize = DEV_BSIZE;
+ dev_bshift = ffs(dev_bsize) - 1;
+ if (dev_bsize != (1 << dev_bshift))
+ quit("dev_bsize (%d) is not a power of 2", dev_bsize);
+ tp_bshift = ffs(TP_BSIZE) - 1;
+ if (TP_BSIZE != (1 << tp_bshift))
+ quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
+ maxino = fs->super->s_inodes_count;
+#if 0
+ spcl.c_flags |= DR_NEWINODEFMT;
+#endif
+#else /* __linux __*/
+ if ((diskfd = open(disk, O_RDONLY)) < 0) {
+ msg("Cannot open %s\n", disk);
+ exit(X_ABORT);
+ }
+ sync();
+ sblock = (struct fs *)sblock_buf;
+ bread(SBOFF, (char *) sblock, SBSIZE);
+ if (sblock->fs_magic != FS_MAGIC)
+ quit("bad sblock magic number\n");
+ dev_bsize = sblock->fs_fsize / fsbtodb(sblock, 1);
+ dev_bshift = ffs(dev_bsize) - 1;
+ if (dev_bsize != (1 << dev_bshift))
+ quit("dev_bsize (%d) is not a power of 2", dev_bsize);
+ tp_bshift = ffs(TP_BSIZE) - 1;
+ if (TP_BSIZE != (1 << tp_bshift))
+ quit("TP_BSIZE (%d) is not a power of 2", TP_BSIZE);
+ spcl.c_flags |= DR_NEWINODEFMT;
+#ifdef FS_44INODEFMT
+ if (sblock->fs_inodefmt >= FS_44INODEFMT)
+ spcl.c_flags |= DR_NEWINODEFMT;
+#endif
+ maxino = sblock->fs_ipg * sblock->fs_ncg;
+#endif /* __linux__ */
+ mapsize = roundup(howmany(maxino, NBBY), TP_BSIZE);
+ usedinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
+ dumpdirmap = (char *)calloc((unsigned) mapsize, sizeof(char));
+ dumpinomap = (char *)calloc((unsigned) mapsize, sizeof(char));
+ tapesize = 3 * (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
+
+ nonodump = spcl.c_level < honorlevel;
+
+ msg("mapping (Pass I) [regular files]\n");
+#ifdef __linux__
+ if (directory[0] == 0)
+ anydirskipped = mapfiles(maxino, &tapesize);
+ else
+ anydirskipped = mapfilesfromdir(maxino, &tapesize, directory);
+#else
+ anydirskipped = mapfiles(maxino, &tapesize);
+#endif
+
+ msg("mapping (Pass II) [directories]\n");
+ while (anydirskipped) {
+ anydirskipped = mapdirs(maxino, &tapesize);
+ }
+
+ if (pipeout) {
+ tapesize += 10; /* 10 trailer blocks */
+ msg("estimated %ld tape blocks.\n", tapesize);
+ } else {
+ double fetapes;
+
+ if (blocksperfile)
+ fetapes = (double) tapesize / blocksperfile;
+ else if (cartridge) {
+ /* Estimate number of tapes, assuming streaming stops at
+ the end of each block written, and not in mid-block.
+ Assume no erroneous blocks; this can be compensated
+ for with an artificially low tape size. */
+ fetapes =
+ ( tapesize /* blocks */
+ * TP_BSIZE /* bytes/block */
+ * (1.0/density) /* 0.1" / byte */
+ +
+ tapesize /* blocks */
+ * (1.0/ntrec) /* streaming-stops per block */
+ * 15.48 /* 0.1" / streaming-stop */
+ ) * (1.0 / tsize ); /* tape / 0.1" */
+ } else {
+ /* Estimate number of tapes, for old fashioned 9-track
+ tape */
+ int tenthsperirg = (density == 625) ? 3 : 7;
+ fetapes =
+ ( tapesize /* blocks */
+ * TP_BSIZE /* bytes / block */
+ * (1.0/density) /* 0.1" / byte */
+ +
+ tapesize /* blocks */
+ * (1.0/ntrec) /* IRG's / block */
+ * tenthsperirg /* 0.1" / IRG */
+ ) * (1.0 / tsize ); /* tape / 0.1" */
+ }
+ etapes = fetapes; /* truncating assignment */
+ etapes++;
+ /* count the dumped inodes map on each additional tape */
+ tapesize += (etapes - 1) *
+ (howmany(mapsize * sizeof(char), TP_BSIZE) + 1);
+ tapesize += etapes + 10; /* headers + 10 trailer blks */
+ msg("estimated %ld tape blocks on %3.2f tape(s).\n",
+ tapesize, fetapes);
+ }
+
+ /*
+ * Allocate tape buffer.
+ */
+ if (!alloctape())
+ quit("can't allocate tape buffers - try a smaller blocking factor.\n");
+
+ startnewtape(1);
+ (void)time((time_t *)&(tstart_writing));
+ dumpmap(usedinomap, TS_CLRI, maxino - 1);
+
+ msg("dumping (Pass III) [directories]\n");
+ dirty = 0; /* XXX just to get gcc to shut up */
+ for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
+ if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
+ dirty = *map++;
+ else
+ dirty >>= 1;
+ if ((dirty & 1) == 0)
+ continue;
+ /*
+ * Skip directory inodes deleted and maybe reallocated
+ */
+ dp = getino(ino);
+ if ((dp->di_mode & IFMT) != IFDIR)
+ continue;
+#ifdef __linux__
+ (void)dumpdirino(dp, ino);
+#else
+ (void)dumpino(dp, ino);
+#endif
+ }
+
+ msg("dumping (Pass IV) [regular files]\n");
+ for (map = dumpinomap, ino = 1; ino < maxino; ino++) {
+ int mode;
+
+ if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
+ dirty = *map++;
+ else
+ dirty >>= 1;
+ if ((dirty & 1) == 0)
+ continue;
+ /*
+ * Skip inodes deleted and reallocated as directories.
+ */
+ dp = getino(ino);
+ mode = dp->di_mode & IFMT;
+ if (mode == IFDIR)
+ continue;
+ (void)dumpino(dp, ino);
+ }
+
+#ifdef __linux__
+ (void)time((time_t *)&(tend_writing));
+#endif
+ spcl.c_type = TS_END;
+ for (i = 0; i < ntrec; i++)
+ writeheader(maxino - 1);
+ if (pipeout)
+ msg("DUMP: %ld tape blocks\n",spcl.c_tapea);
+ else
+ msg("DUMP: %ld tape blocks on %d volumes(s)\n",
+ spcl.c_tapea, spcl.c_volume);
+#ifdef __linux__
+ /* report dump performance, avoid division through zero */
+ if (tend_writing - tstart_writing == 0)
+ msg("finished in less than a second\n");
+ else
+ msg("finished in %d seconds, throughput %d KBytes/sec\n",
+ tend_writing - tstart_writing,
+ spcl.c_tapea / (tend_writing - tstart_writing));
+#endif
+ putdumptime();
+ trewind();
+ broadcast("DUMP IS DONE!\7\7\n");
+ msg("DUMP IS DONE\n");
+ Exit(X_FINOK);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+
+ (void)fprintf(stderr, "usage: dump [-0123456789cnu] [-B records] [-b blocksize] [-d density] [-f file]\n [-h level] [-s feet] [-T date] filesystem\n");
+ (void)fprintf(stderr, " dump [-W | -w]\n");
+ exit(1);
+}
+
+/*
+ * Pick up a numeric argument. It must be nonnegative and in the given
+ * range (except that a vmax of 0 means unlimited).
+ */
+static long
+numarg(meaning, vmin, vmax)
+ char *meaning;
+ long vmin, vmax;
+{
+ char *p;
+ long val;
+
+ val = strtol(optarg, &p, 10);
+ if (*p)
+ errx(1, "illegal %s -- %s", meaning, optarg);
+ if (val < vmin || (vmax && val > vmax))
+ errx(1, "%s must be between %ld and %ld", meaning, vmin, vmax);
+ return (val);
+}
+
+void
+sig(signo)
+ int signo;
+{
+ switch(signo) {
+ case SIGALRM:
+ case SIGBUS:
+ case SIGFPE:
+ case SIGHUP:
+ case SIGTERM:
+ case SIGTRAP:
+ if (pipeout)
+ quit("Signal on pipe: cannot recover\n");
+ msg("Rewriting attempted as response to unknown signal.\n");
+ (void)fflush(stderr);
+ (void)fflush(stdout);
+ close_rewind();
+ exit(X_REWRITE);
+ /* NOTREACHED */
+ case SIGSEGV:
+ msg("SIGSEGV: ABORTING!\n");
+ (void)signal(SIGSEGV, SIG_DFL);
+ (void)kill(0, SIGSEGV);
+ /* NOTREACHED */
+ }
+}
+
+char *
+rawname(cp)
+ char *cp;
+{
+#ifdef __linux__
+ return cp;
+#else /* __linux__ */
+ static char rawbuf[MAXPATHLEN];
+ char *dp = strrchr(cp, '/');
+
+ if (dp == NULL)
+ return (NULL);
+ *dp = '\0';
+ (void)strcpy(rawbuf, cp);
+ *dp = '/';
+ (void)strcat(rawbuf, "/r");
+ (void)strcat(rawbuf, dp + 1);
+ return (rawbuf);
+#endif /* __linux__ */
+}
+
+/*
+ * obsolete --
+ * Change set of key letters and ordered arguments into something
+ * getopt(3) will like.
+ */
+static void
+obsolete(argcp, argvp)
+ int *argcp;
+ char **argvp[];
+{
+ int argc, flags;
+ char *ap, **argv, *flagsp, **nargv, *p;
+
+ /* Setup. */
+ argv = *argvp;
+ argc = *argcp;
+
+ /* Return if no arguments or first argument has leading dash. */
+ ap = argv[1];
+ if (argc == 1 || *ap == '-')
+ return;
+
+ /* Allocate space for new arguments. */
+ if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
+ (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
+ err(1, NULL);
+
+ *nargv++ = *argv;
+ argv += 2;
+
+ for (flags = 0; *ap; ++ap) {
+ switch (*ap) {
+ case 'B':
+ case 'b':
+ case 'd':
+ case 'f':
+ case 'h':
+ case 's':
+ case 'T':
+ if (*argv == NULL) {
+ warnx("option requires an argument -- %c", *ap); usage();
+ }
+ if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
+ err(1, NULL);
+ nargv[0][0] = '-';
+ nargv[0][1] = *ap;
+ (void)strcpy(&nargv[0][2], *argv);
+ ++argv;
+ ++nargv;
+ break;
+ default:
+ if (!flags) {
+ *p++ = '-';
+ flags = 1;
+ }
+ *p++ = *ap;
+ break;
+ }
+ }
+
+ /* Terminate flags. */
+ if (flags) {
+ *p = '\0';
+ *nargv++ = flagsp;
+ }
+
+ /* Copy remaining arguments. */
+ while (*nargv++ = *argv++);
+
+ /* Update argument count. */
+ *argcp = nargv - *argvp - 1;
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1988, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)optr.c 8.2 (Berkeley) 1/6/94";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+
+#include <errno.h>
+#include <fstab.h>
+#include <grp.h>
+#include <signal.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#endif
+#include <tzfile.h>
+#ifdef __STDC__
+#include <unistd.h>
+#endif
+#include <utmp.h>
+#ifndef __STDC__
+#include <varargs.h>
+#endif
+
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <ext2fs/ext2fs.h>
+#include <bsdcompat.h>
+#endif
+
+#include "dump.h"
+#include "pathnames.h"
+
+void alarmcatch __P((/* int, int */));
+int datesort __P((const void *, const void *));
+static void sendmes __P((char *, char *));
+
+/*
+ * Query the operator; This previously-fascist piece of code
+ * no longer requires an exact response.
+ * It is intended to protect dump aborting by inquisitive
+ * people banging on the console terminal to see what is
+ * happening which might cause dump to croak, destroying
+ * a large number of hours of work.
+ *
+ * Every 2 minutes we reprint the message, alerting others
+ * that dump needs attention.
+ */
+static int timeout;
+static char *attnmessage; /* attention message */
+
+int
+query(question)
+ char *question;
+{
+ char replybuffer[64];
+ int back, errcount;
+ FILE *mytty;
+
+ if ((mytty = fopen(_PATH_TTY, "r")) == NULL)
+ quit("fopen on %s fails: %s\n", _PATH_TTY, strerror(errno));
+ attnmessage = question;
+ timeout = 0;
+ alarmcatch();
+ back = -1;
+ errcount = 0;
+ do {
+ if (fgets(replybuffer, 63, mytty) == NULL) {
+ clearerr(mytty);
+ if (++errcount > 30) /* XXX ugly */
+ quit("excessive operator query failures\n");
+ } else if (replybuffer[0] == 'y' || replybuffer[0] == 'Y') {
+ back = 1;
+ } else if (replybuffer[0] == 'n' || replybuffer[0] == 'N') {
+ back = 0;
+ } else {
+ (void) fprintf(stderr,
+ " DUMP: \"Yes\" or \"No\"?\n");
+ (void) fprintf(stderr,
+ " DUMP: %s: (\"yes\" or \"no\") ", question);
+ }
+ } while (back < 0);
+
+ /*
+ * Turn off the alarm, and reset the signal to trap out..
+ */
+ (void) alarm(0);
+ if (signal(SIGALRM, sig) == SIG_IGN)
+ signal(SIGALRM, SIG_IGN);
+ (void) fclose(mytty);
+ return(back);
+}
+
+char lastmsg[100];
+
+/*
+ * Alert the console operator, and enable the alarm clock to
+ * sleep for 2 minutes in case nobody comes to satisfy dump
+ */
+void
+alarmcatch()
+{
+ if (notify == 0) {
+ if (timeout == 0)
+ (void) fprintf(stderr,
+ " DUMP: %s: (\"yes\" or \"no\") ",
+ attnmessage);
+ else
+ msgtail("\7\7");
+ } else {
+ if (timeout) {
+ msgtail("\n");
+ broadcast(""); /* just print last msg */
+ }
+ (void) fprintf(stderr," DUMP: %s: (\"yes\" or \"no\") ",
+ attnmessage);
+ }
+ signal(SIGALRM, alarmcatch);
+ (void) alarm(120);
+ timeout = 1;
+}
+
+/*
+ * Here if an inquisitive operator interrupts the dump program
+ */
+void
+interrupt(signo)
+ int signo;
+{
+ msg("Interrupt received.\n");
+ if (query("Do you want to abort dump?"))
+ dumpabort(0);
+}
+
+/*
+ * The following variables and routines manage alerting
+ * operators to the status of dump.
+ * This works much like wall(1) does.
+ */
+struct group *gp;
+
+/*
+ * Get the names from the group entry "operator" to notify.
+ */
+void
+set_operators()
+{
+ if (!notify) /*not going to notify*/
+ return;
+ gp = getgrnam(OPGRENT);
+ (void) endgrent();
+ if (gp == NULL) {
+ msg("No group entry for %s.\n", OPGRENT);
+ notify = 0;
+ return;
+ }
+}
+
+struct tm *localclock;
+
+/*
+ * We fork a child to do the actual broadcasting, so
+ * that the process control groups are not messed up
+ */
+void
+broadcast(message)
+ char *message;
+{
+ time_t clock;
+ FILE *f_utmp;
+ struct utmp utmp;
+ char **np;
+ int pid, s;
+
+ if (!notify || gp == NULL)
+ return;
+
+ switch (pid = fork()) {
+ case -1:
+ return;
+ case 0:
+ break;
+ default:
+ while (wait(&s) != pid)
+ continue;
+ return;
+ }
+
+ clock = time((time_t *)0);
+ localclock = localtime(&clock);
+
+ if ((f_utmp = fopen(_PATH_UTMP, "r")) == NULL) {
+ msg("Cannot open %s: %s\n", _PATH_UTMP, strerror(errno));
+ return;
+ }
+
+ while (!feof(f_utmp)) {
+ if (fread((char *) &utmp, sizeof (struct utmp), 1, f_utmp) != 1)
+ break;
+ if (utmp.ut_name[0] == 0)
+ continue;
+ for (np = gp->gr_mem; *np; np++) {
+ if (strncmp(*np, utmp.ut_name, sizeof(utmp.ut_name)) != 0)
+ continue;
+ /*
+ * Do not send messages to operators on dialups
+ */
+ if (strncmp(utmp.ut_line, DIALUP, strlen(DIALUP)) == 0)
+ continue;
+#ifdef DEBUG
+ msg("Message to %s at %s\n", *np, utmp.ut_line);
+#endif
+ sendmes(utmp.ut_line, message);
+ }
+ }
+ (void) fclose(f_utmp);
+ Exit(0); /* the wait in this same routine will catch this */
+ /* NOTREACHED */
+}
+
+static void
+sendmes(tty, message)
+ char *tty, *message;
+{
+ char t[50], buf[BUFSIZ];
+ register char *cp;
+ int lmsg = 1;
+ FILE *f_tty;
+
+ (void) strcpy(t, _PATH_DEV);
+ (void) strcat(t, tty);
+
+ if ((f_tty = fopen(t, "w")) != NULL) {
+ setbuf(f_tty, buf);
+ (void) fprintf(f_tty,
+ "\n\
+\7\7\7Message from the dump program to all operators at %d:%02d ...\r\n\n\
+DUMP: NEEDS ATTENTION: ",
+ localclock->tm_hour, localclock->tm_min);
+ for (cp = lastmsg; ; cp++) {
+ if (*cp == '\0') {
+ if (lmsg) {
+ cp = message;
+ if (*cp == '\0')
+ break;
+ lmsg = 0;
+ } else
+ break;
+ }
+ if (*cp == '\n')
+ (void) putc('\r', f_tty);
+ (void) putc(*cp, f_tty);
+ }
+ (void) fclose(f_tty);
+ }
+}
+
+/*
+ * print out an estimate of the amount of time left to do the dump
+ */
+
+time_t tschedule = 0;
+
+void
+timeest()
+{
+ time_t tnow, deltat;
+
+ (void) time((time_t *) &tnow);
+ if (tnow >= tschedule) {
+ tschedule = tnow + 300;
+ if (blockswritten < 500)
+ return;
+ deltat = tstart_writing - tnow +
+ (1.0 * (tnow - tstart_writing))
+ / blockswritten * tapesize;
+ msg("%3.2f%% done, finished in %d:%02d\n",
+ (blockswritten * 100.0) / tapesize,
+ deltat / 3600, (deltat % 3600) / 60);
+ }
+}
+
+void
+#if __STDC__
+msg(const char *fmt, ...)
+#else
+msg(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ (void) fprintf(stderr," DUMP: ");
+#ifdef TDEBUG
+ (void) fprintf(stderr, "pid=%d ", getpid());
+#endif
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void) vfprintf(stderr, fmt, ap);
+ (void) fflush(stdout);
+ (void) fflush(stderr);
+ (void) vsprintf(lastmsg, fmt, ap);
+ va_end(ap);
+}
+
+void
+#if __STDC__
+msgtail(const char *fmt, ...)
+#else
+msgtail(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+void
+#if __STDC__
+quit(const char *fmt, ...)
+#else
+quit(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+
+ (void) fprintf(stderr," DUMP: ");
+#ifdef TDEBUG
+ (void) fprintf(stderr, "pid=%d ", getpid());
+#endif
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void) vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ (void) fflush(stdout);
+ (void) fflush(stderr);
+ dumpabort(0);
+}
+
+/*
+ * Tell the operator what has to be done;
+ * we don't actually do it
+ */
+
+struct fstab *
+allocfsent(fs)
+ register struct fstab *fs;
+{
+ register struct fstab *new;
+
+ new = (struct fstab *)malloc(sizeof (*fs));
+ if (new == NULL ||
+ (new->fs_file = strdup(fs->fs_file)) == NULL ||
+ (new->fs_type = strdup(fs->fs_type)) == NULL ||
+ (new->fs_spec = strdup(fs->fs_spec)) == NULL)
+ quit("%s\n", strerror(errno));
+ new->fs_passno = fs->fs_passno;
+ new->fs_freq = fs->fs_freq;
+ return (new);
+}
+
+struct pfstab {
+ struct pfstab *pf_next;
+ struct fstab *pf_fstab;
+};
+
+static struct pfstab *table;
+
+void
+getfstab()
+{
+ register struct fstab *fs;
+ register struct pfstab *pf;
+
+ if (setfsent() == 0) {
+ msg("Can't open %s for dump table information: %s\n",
+ _PATH_FSTAB, strerror(errno));
+ return;
+ }
+ while ((fs = getfsent()) != NULL) {
+ if (strcmp(fs->fs_type, FSTAB_RW) &&
+ strcmp(fs->fs_type, FSTAB_RO) &&
+ strcmp(fs->fs_type, FSTAB_RQ))
+ continue;
+ fs = allocfsent(fs);
+ if ((pf = (struct pfstab *)malloc(sizeof (*pf))) == NULL)
+ quit("%s\n", strerror(errno));
+ pf->pf_fstab = fs;
+ pf->pf_next = table;
+ table = pf;
+ }
+ (void) endfsent();
+}
+
+/*
+ * Search in the fstab for a file name.
+ * This file name can be either the special or the path file name.
+ *
+ * The entries in the fstab are the BLOCK special names, not the
+ * character special names.
+ * The caller of fstabsearch assures that the character device
+ * is dumped (that is much faster)
+ *
+ * The file name can omit the leading '/'.
+ */
+struct fstab *
+fstabsearch(key)
+ char *key;
+{
+ register struct pfstab *pf;
+ register struct fstab *fs;
+ char *rn;
+
+ for (pf = table; pf != NULL; pf = pf->pf_next) {
+ fs = pf->pf_fstab;
+ if (strcmp(fs->fs_file, key) == 0 ||
+ strcmp(fs->fs_spec, key) == 0)
+ return (fs);
+ rn = rawname(fs->fs_spec);
+ if (rn != NULL && strcmp(rn, key) == 0)
+ return (fs);
+ if (key[0] != '/') {
+ if (*fs->fs_spec == '/' &&
+ strcmp(fs->fs_spec + 1, key) == 0)
+ return (fs);
+ if (*fs->fs_file == '/' &&
+ strcmp(fs->fs_file + 1, key) == 0)
+ return (fs);
+ }
+ }
+ return (NULL);
+}
+
+#ifdef __linux__
+struct fstab *
+fstabsearchdir(key, directory)
+ char *key;
+ char *directory;
+{
+ register struct pfstab *pf;
+ register struct fstab *fs;
+ register struct fstab *found_fs = NULL;
+ unsigned int size = 0;
+
+ for (pf = table; pf != NULL; pf = pf->pf_next) {
+ fs = pf->pf_fstab;
+ if (strlen(fs->fs_file) > size &&
+ strlen(key) > strlen(fs->fs_file) + 2 &&
+ strncmp(fs->fs_file, key, strlen(fs->fs_file)) == 0 &&
+ (key[strlen(fs->fs_file)] == '/' ||
+ fs->fs_file[strlen(fs->fs_file) - 1] == '/')) {
+ found_fs = fs;
+ size = strlen(fs->fs_file);
+ }
+ }
+ if (found_fs != NULL) {
+ /*
+ * Ok, we have found a fstab entry which matches the argument
+ * We have to split the argument name into:
+ * - a device name (from the fstab entry)
+ * - a directory name on this device
+ */
+ strcpy(directory, key + size);
+ }
+ return(found_fs);
+}
+#endif
+
+/*
+ * Tell the operator what to do
+ */
+void
+lastdump(arg)
+ char arg; /* w ==> just what to do; W ==> most recent dumps */
+{
+ register int i;
+ register struct fstab *dt;
+ register struct dumpdates *dtwalk;
+ char *lastname, *date;
+ int dumpme;
+ time_t tnow;
+
+ (void) time(&tnow);
+ getfstab(); /* /etc/fstab input */
+ initdumptimes(); /* /etc/dumpdates input */
+ qsort((char *) ddatev, nddates, sizeof(struct dumpdates *), datesort);
+
+ if (arg == 'w')
+ (void) printf("Dump these file systems:\n");
+ else
+ (void) printf("Last dump(s) done (Dump '>' file systems):\n");
+ lastname = "??";
+ ITITERATE(i, dtwalk) {
+ if (strncmp(lastname, dtwalk->dd_name,
+ sizeof(dtwalk->dd_name)) == 0)
+ continue;
+ date = (char *)ctime(&dtwalk->dd_ddate);
+ date[16] = '\0'; /* blast away seconds and year */
+ lastname = dtwalk->dd_name;
+ dt = fstabsearch(dtwalk->dd_name);
+ dumpme = (dt != NULL &&
+ dt->fs_freq != 0 &&
+ dtwalk->dd_ddate < tnow - (dt->fs_freq * SECSPERDAY));
+ if (arg != 'w' || dumpme)
+ (void) printf(
+ "%c %8s\t(%6s) Last dump: Level %c, Date %s\n",
+ dumpme && (arg != 'w') ? '>' : ' ',
+ dtwalk->dd_name,
+ dt ? dt->fs_file : "",
+ dtwalk->dd_level,
+ date);
+ }
+}
+
+int
+datesort(a1, a2)
+ const void *a1, *a2;
+{
+ struct dumpdates *d1 = *(struct dumpdates **)a1;
+ struct dumpdates *d2 = *(struct dumpdates **)a2;
+ int diff;
+
+ diff = strncmp(d1->dd_name, d2->dd_name, sizeof(d1->dd_name));
+ if (diff == 0)
+ return (d2->dd_ddate - d1->dd_ddate);
+ return (diff);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tape.c 8.4 (Berkeley) 5/1/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/wait.h>
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#ifdef sunos
+#include <sys/vnode.h>
+
+#include <ufs/fs.h>
+#include <ufs/inode.h>
+#else
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#endif
+#endif /* __linux__ */
+
+#include <protocols/dumprestore.h>
+
+#include <errno.h>
+#include <fcntl.h>
+#include <setjmp.h>
+#include <signal.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#else
+int write(), read();
+#endif
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+#include "dump.h"
+#include "pathnames.h"
+
+int writesize; /* size of malloc()ed buffer for tape */
+long lastspclrec = -1; /* tape block number of last written header */
+int trecno = 0; /* next record to write in current block */
+extern long blocksperfile; /* number of blocks per output file */
+long blocksthisvol; /* number of blocks on current output file */
+extern int ntrec; /* blocking factor on tape */
+extern int cartridge;
+extern char *host;
+char *nexttape;
+
+static int atomic __P((int (*)(), int, char *, int));
+static void doslave __P((int, int));
+static void enslave __P((void));
+static void flushtape __P((void));
+static void killall __P((void));
+static void rollforward __P((void));
+
+/*
+ * Concurrent dump mods (Caltech) - disk block reading and tape writing
+ * are exported to several slave processes. While one slave writes the
+ * tape, the others read disk blocks; they pass control of the tape in
+ * a ring via signals. The parent process traverses the filesystem and
+ * sends writeheader()'s and lists of daddr's to the slaves via pipes.
+ * The following structure defines the instruction packets sent to slaves.
+ */
+struct req {
+ daddr_t dblk;
+ int count;
+};
+int reqsiz;
+
+#define SLAVES 3 /* 1 slave writing, 1 reading, 1 for slack */
+struct slave {
+ int tapea; /* header number at start of this chunk */
+ int count; /* count to next header (used for TS_TAPE */
+ /* after EOT) */
+ int inode; /* inode that we are currently dealing with */
+ int fd; /* FD for this slave */
+ int pid; /* PID for this slave */
+ int sent; /* 1 == we've sent this slave requests */
+ int firstrec; /* record number of this block */
+ char (*tblock)[TP_BSIZE]; /* buffer for data blocks */
+ struct req *req; /* buffer for requests */
+} slaves[SLAVES+1];
+struct slave *slp;
+
+char (*nextblock)[TP_BSIZE];
+
+int master; /* pid of master, for sending error signals */
+int tenths; /* length of tape used per block written */
+static int caught; /* have we caught the signal to proceed? */
+static int ready; /* have we reached the lock point without having */
+ /* received the SIGUSR2 signal from the prev slave? */
+static jmp_buf jmpbuf; /* where to jump to if we are ready when the */
+ /* SIGUSR2 arrives from the previous slave */
+
+int
+alloctape()
+{
+ int pgoff = getpagesize() - 1;
+ char *buf;
+ int i;
+
+ writesize = ntrec * TP_BSIZE;
+ reqsiz = (ntrec + 1) * sizeof(struct req);
+ /*
+ * CDC 92181's and 92185's make 0.8" gaps in 1600-bpi start/stop mode
+ * (see DEC TU80 User's Guide). The shorter gaps of 6250-bpi require
+ * repositioning after stopping, i.e, streaming mode, where the gap is
+ * variable, 0.30" to 0.45". The gap is maximal when the tape stops.
+ */
+ if (blocksperfile == 0)
+ tenths = writesize / density +
+ (cartridge ? 16 : density == 625 ? 5 : 8);
+ /*
+ * Allocate tape buffer contiguous with the array of instruction
+ * packets, so flushtape() can write them together with one write().
+ * Align tape buffer on page boundary to speed up tape write().
+ */
+ for (i = 0; i <= SLAVES; i++) {
+ buf = (char *)
+ malloc((unsigned)(reqsiz + writesize + pgoff + TP_BSIZE));
+ if (buf == NULL)
+ return(0);
+ slaves[i].tblock = (char (*)[TP_BSIZE])
+#ifdef __linux__
+ (((long)&buf[reqsiz] + pgoff) &~ pgoff);
+#else
+ (((long)&buf[ntrec + 1] + pgoff) &~ pgoff);
+#endif
+ slaves[i].req = (struct req *)slaves[i].tblock - ntrec - 1;
+ }
+ slp = &slaves[0];
+ slp->count = 1;
+ slp->tapea = 0;
+ slp->firstrec = 0;
+ nextblock = slp->tblock;
+ return(1);
+}
+
+void
+writerec(dp, isspcl)
+ char *dp;
+ int isspcl;
+{
+
+ slp->req[trecno].dblk = (daddr_t)0;
+ slp->req[trecno].count = 1;
+ *(union u_spcl *)(*(nextblock)++) = *(union u_spcl *)dp;
+ if (isspcl)
+ lastspclrec = spcl.c_tapea;
+ trecno++;
+ spcl.c_tapea++;
+ if (trecno >= ntrec)
+ flushtape();
+}
+
+void
+dumpblock(blkno, size)
+ daddr_t blkno;
+ int size;
+{
+ int avail, tpblks, dblkno;
+
+ dblkno = fsbtodb(sblock, blkno);
+ tpblks = size >> tp_bshift;
+ while ((avail = MIN(tpblks, ntrec - trecno)) > 0) {
+ slp->req[trecno].dblk = dblkno;
+ slp->req[trecno].count = avail;
+ trecno += avail;
+ spcl.c_tapea += avail;
+ if (trecno >= ntrec)
+ flushtape();
+ dblkno += avail << (tp_bshift - dev_bshift);
+ tpblks -= avail;
+ }
+}
+
+int nogripe = 0;
+
+void
+tperror(signo)
+ int signo;
+{
+
+ if (pipeout) {
+ msg("write error on %s\n", tape);
+ quit("Cannot recover\n");
+ /* NOTREACHED */
+ }
+ msg("write error %d blocks into volume %d\n", blocksthisvol, tapeno);
+ broadcast("DUMP WRITE ERROR!\n");
+ if (!query("Do you want to restart?"))
+ dumpabort(0);
+ msg("Closing this volume. Prepare to restart with new media;\n");
+ msg("this dump volume will be rewritten.\n");
+ killall();
+ nogripe = 1;
+ close_rewind();
+ Exit(X_REWRITE);
+}
+
+void
+sigpipe(signo)
+ int signo;
+{
+
+ quit("Broken pipe\n");
+}
+
+static void
+flushtape()
+{
+ int i, blks, got;
+ long lastfirstrec;
+
+ int siz = (char *)nextblock - (char *)slp->req;
+
+ slp->req[trecno].count = 0; /* Sentinel */
+
+ if (atomic(write, slp->fd, (char *)slp->req, siz) != siz)
+ quit("error writing command pipe: %s\n", strerror(errno));
+ slp->sent = 1; /* we sent a request, read the response later */
+
+ lastfirstrec = slp->firstrec;
+
+ if (++slp >= &slaves[SLAVES])
+ slp = &slaves[0];
+
+ /* Read results back from next slave */
+ if (slp->sent) {
+ if (atomic(read, slp->fd, (char *)&got, sizeof got)
+ != sizeof got) {
+ perror(" DUMP: error reading command pipe in master");
+ dumpabort(0);
+ }
+ slp->sent = 0;
+
+ /* Check for end of tape */
+ if (got < writesize) {
+ msg("End of tape detected\n");
+
+ /*
+ * Drain the results, don't care what the values were.
+ * If we read them here then trewind won't...
+ */
+ for (i = 0; i < SLAVES; i++) {
+ if (slaves[i].sent) {
+ if (atomic(read, slaves[i].fd,
+ (char *)&got, sizeof got)
+ != sizeof got) {
+ perror(" DUMP: error reading command pipe in master");
+ dumpabort(0);
+ }
+ slaves[i].sent = 0;
+ }
+ }
+
+ close_rewind();
+ rollforward();
+ return;
+ }
+ }
+
+ blks = 0;
+ if (spcl.c_type != TS_END) {
+ for (i = 0; i < spcl.c_count; i++)
+ if (spcl.c_addr[i] != 0)
+ blks++;
+ }
+ slp->count = lastspclrec + blks + 1 - spcl.c_tapea;
+ slp->tapea = spcl.c_tapea;
+ slp->firstrec = lastfirstrec + ntrec;
+ slp->inode = curino;
+ nextblock = slp->tblock;
+ trecno = 0;
+ asize += tenths;
+ blockswritten += ntrec;
+ blocksthisvol += ntrec;
+ if (!pipeout && (blocksperfile ?
+ (blocksthisvol >= blocksperfile) : (asize > tsize))) {
+ close_rewind();
+ startnewtape(0);
+ }
+ timeest();
+}
+
+void
+trewind()
+{
+ int f;
+ int got;
+
+ for (f = 0; f < SLAVES; f++) {
+ /*
+ * Drain the results, but unlike EOT we DO (or should) care
+ * what the return values were, since if we detect EOT after
+ * we think we've written the last blocks to the tape anyway,
+ * we have to replay those blocks with rollforward.
+ *
+ * fixme: punt for now.
+ */
+ if (slaves[f].sent) {
+ if (atomic(read, slaves[f].fd, (char *)&got, sizeof got)
+ != sizeof got) {
+ perror(" DUMP: error reading command pipe in master");
+ dumpabort(0);
+ }
+ slaves[f].sent = 0;
+ if (got != writesize) {
+ msg("EOT detected in last 2 tape records!\n");
+ msg("Use a longer tape, decrease the size estimate\n");
+ quit("or use no size estimate at all.\n");
+ }
+ }
+ (void) close(slaves[f].fd);
+ }
+ while (wait((int *)NULL) >= 0) /* wait for any signals from slaves */
+ /* void */;
+
+ if (pipeout)
+ return;
+
+ msg("Closing %s\n", tape);
+
+#ifdef RDUMP
+ if (host) {
+ rmtclose();
+ while (rmtopen(tape, 0) < 0)
+ sleep(10);
+ rmtclose();
+ return;
+ }
+#endif
+ (void) close(tapefd);
+ while ((f = open(tape, 0)) < 0)
+ sleep (10);
+ (void) close(f);
+}
+
+void
+close_rewind()
+{
+ trewind();
+ if (nexttape)
+ return;
+ if (!nogripe) {
+ msg("Change Volumes: Mount volume #%d\n", tapeno+1);
+ broadcast("CHANGE DUMP VOLUMES!\7\7\n");
+ }
+ while (!query("Is the new volume mounted and ready to go?"))
+ if (query("Do you want to abort?")) {
+ dumpabort(0);
+ /*NOTREACHED*/
+ }
+}
+
+void
+rollforward()
+{
+ register struct req *p, *q, *prev;
+ register struct slave *tslp;
+ int i, size, savedtapea, got;
+ union u_spcl *ntb, *otb;
+ tslp = &slaves[SLAVES];
+ ntb = (union u_spcl *)tslp->tblock[1];
+
+ /*
+ * Each of the N slaves should have requests that need to
+ * be replayed on the next tape. Use the extra slave buffers
+ * (slaves[SLAVES]) to construct request lists to be sent to
+ * each slave in turn.
+ */
+ for (i = 0; i < SLAVES; i++) {
+ q = &tslp->req[1];
+ otb = (union u_spcl *)slp->tblock;
+
+ /*
+ * For each request in the current slave, copy it to tslp.
+ */
+
+ prev = NULL;
+ for (p = slp->req; p->count > 0; p += p->count) {
+ *q = *p;
+ if (p->dblk == 0)
+ *ntb++ = *otb++; /* copy the datablock also */
+ prev = q;
+ q += q->count;
+ }
+ if (prev == NULL)
+ quit("rollforward: protocol botch");
+ if (prev->dblk != 0)
+ prev->count -= 1;
+ else
+ ntb--;
+ q -= 1;
+ q->count = 0;
+ q = &tslp->req[0];
+ if (i == 0) {
+ q->dblk = 0;
+ q->count = 1;
+ trecno = 0;
+ nextblock = tslp->tblock;
+ savedtapea = spcl.c_tapea;
+ spcl.c_tapea = slp->tapea;
+ startnewtape(0);
+ spcl.c_tapea = savedtapea;
+ lastspclrec = savedtapea - 1;
+ }
+ size = (char *)ntb - (char *)q;
+ if (atomic(write, slp->fd, (char *)q, size) != size) {
+ perror(" DUMP: error writing command pipe");
+ dumpabort(0);
+ }
+ slp->sent = 1;
+ if (++slp >= &slaves[SLAVES])
+ slp = &slaves[0];
+
+ q->count = 1;
+
+ if (prev->dblk != 0) {
+ /*
+ * If the last one was a disk block, make the
+ * first of this one be the last bit of that disk
+ * block...
+ */
+ q->dblk = prev->dblk +
+ prev->count * (TP_BSIZE / DEV_BSIZE);
+ ntb = (union u_spcl *)tslp->tblock;
+ } else {
+ /*
+ * It wasn't a disk block. Copy the data to its
+ * new location in the buffer.
+ */
+ q->dblk = 0;
+ *((union u_spcl *)tslp->tblock) = *ntb;
+ ntb = (union u_spcl *)tslp->tblock[1];
+ }
+ }
+ slp->req[0] = *q;
+ nextblock = slp->tblock;
+ if (q->dblk == 0)
+ nextblock++;
+ trecno = 1;
+
+ /*
+ * Clear the first slaves' response. One hopes that it
+ * worked ok, otherwise the tape is much too short!
+ */
+ if (slp->sent) {
+ if (atomic(read, slp->fd, (char *)&got, sizeof got)
+ != sizeof got) {
+ perror(" DUMP: error reading command pipe in master");
+ dumpabort(0);
+ }
+ slp->sent = 0;
+
+ if (got != writesize) {
+ quit("EOT detected at start of the tape!\n");
+ }
+ }
+}
+
+/*
+ * We implement taking and restoring checkpoints on the tape level.
+ * When each tape is opened, a new process is created by forking; this
+ * saves all of the necessary context in the parent. The child
+ * continues the dump; the parent waits around, saving the context.
+ * If the child returns X_REWRITE, then it had problems writing that tape;
+ * this causes the parent to fork again, duplicating the context, and
+ * everything continues as if nothing had happened.
+ */
+void
+startnewtape(top)
+ int top;
+{
+ int parentpid;
+ int childpid;
+ int status;
+ int waitpid;
+ char *p;
+#ifdef __linux__
+ void (*interrupt_save)();
+#else /* __linux__ */
+#ifdef sunos
+ void (*interrupt_save)();
+#else
+ sig_t interrupt_save;
+#endif
+#endif /* __linux__ */
+
+ interrupt_save = signal(SIGINT, SIG_IGN);
+ parentpid = getpid();
+
+restore_check_point:
+ (void)signal(SIGINT, interrupt_save);
+ /*
+ * All signals are inherited...
+ */
+ childpid = fork();
+ if (childpid < 0) {
+ msg("Context save fork fails in parent %d\n", parentpid);
+ Exit(X_ABORT);
+ }
+ if (childpid != 0) {
+ /*
+ * PARENT:
+ * save the context by waiting
+ * until the child doing all of the work returns.
+ * don't catch the interrupt
+ */
+ signal(SIGINT, SIG_IGN);
+#ifdef TDEBUG
+ msg("Tape: %d; parent process: %d child process %d\n",
+ tapeno+1, parentpid, childpid);
+#endif /* TDEBUG */
+ while ((waitpid = wait(&status)) != childpid)
+ msg("Parent %d waiting for child %d has another child %d return\n",
+ parentpid, childpid, waitpid);
+ if (status & 0xFF) {
+ msg("Child %d returns LOB status %o\n",
+ childpid, status&0xFF);
+ }
+ status = (status >> 8) & 0xFF;
+#ifdef TDEBUG
+ switch(status) {
+ case X_FINOK:
+ msg("Child %d finishes X_FINOK\n", childpid);
+ break;
+ case X_ABORT:
+ msg("Child %d finishes X_ABORT\n", childpid);
+ break;
+ case X_REWRITE:
+ msg("Child %d finishes X_REWRITE\n", childpid);
+ break;
+ default:
+ msg("Child %d finishes unknown %d\n",
+ childpid, status);
+ break;
+ }
+#endif /* TDEBUG */
+ switch(status) {
+ case X_FINOK:
+ Exit(X_FINOK);
+ case X_ABORT:
+ Exit(X_ABORT);
+ case X_REWRITE:
+ goto restore_check_point;
+ default:
+ msg("Bad return code from dump: %d\n", status);
+ Exit(X_ABORT);
+ }
+ /*NOTREACHED*/
+ } else { /* we are the child; just continue */
+#ifdef TDEBUG
+ sleep(4); /* allow time for parent's message to get out */
+ msg("Child on Tape %d has parent %d, my pid = %d\n",
+ tapeno+1, parentpid, getpid());
+#endif /* TDEBUG */
+ /*
+ * If we have a name like "/dev/rmt0,/dev/rmt1",
+ * use the name before the comma first, and save
+ * the remaining names for subsequent volumes.
+ */
+ tapeno++; /* current tape sequence */
+ if (nexttape || strchr(tape, ',')) {
+ if (nexttape && *nexttape)
+ tape = nexttape;
+ if ((p = strchr(tape, ',')) != NULL) {
+ *p = '\0';
+ nexttape = p + 1;
+ } else
+ nexttape = NULL;
+ msg("Dumping volume %d on %s\n", tapeno, tape);
+ }
+#ifdef RDUMP
+ while ((tapefd = (host ? rmtopen(tape, 2) :
+ pipeout ? 1 : open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
+#else
+ while ((tapefd = (pipeout ? 1 :
+ open(tape, O_WRONLY|O_CREAT, 0666))) < 0)
+#endif
+ {
+ msg("Cannot open output \"%s\".\n", tape);
+ if (!query("Do you want to retry the open?"))
+ dumpabort(0);
+ }
+
+ enslave(); /* Share open tape file descriptor with slaves */
+
+ asize = 0;
+ blocksthisvol = 0;
+ if (top)
+ newtape++; /* new tape signal */
+ spcl.c_count = slp->count;
+ /*
+ * measure firstrec in TP_BSIZE units since restore doesn't
+ * know the correct ntrec value...
+ */
+ spcl.c_firstrec = slp->firstrec;
+ spcl.c_volume++;
+ spcl.c_type = TS_TAPE;
+ spcl.c_flags |= DR_NEWHEADER;
+ writeheader((ino_t)slp->inode);
+ spcl.c_flags &=~ DR_NEWHEADER;
+ if (tapeno > 1)
+ msg("Volume %d begins with blocks from inode %d\n",
+ tapeno, slp->inode);
+ }
+}
+
+void
+dumpabort(signo)
+ int signo;
+{
+
+ if (master != 0 && master != getpid())
+ /* Signals master to call dumpabort */
+ (void) kill(master, SIGTERM);
+ else {
+ killall();
+ msg("The ENTIRE dump is aborted.\n");
+ }
+#ifdef RDUMP
+ rmtclose();
+#endif
+ Exit(X_ABORT);
+}
+
+__dead void
+Exit(status)
+ int status;
+{
+
+#ifdef TDEBUG
+ msg("pid = %d exits with status %d\n", getpid(), status);
+#endif /* TDEBUG */
+ exit(status);
+}
+
+/*
+ * proceed - handler for SIGUSR2, used to synchronize IO between the slaves.
+ */
+void
+proceed(signo)
+ int signo;
+{
+
+ if (ready)
+ longjmp(jmpbuf, 1);
+ caught++;
+}
+
+void
+enslave()
+{
+ int cmd[2];
+#ifdef LINUX_FORK_BUG
+ int i, j;
+#else
+ register int i, j;
+#endif
+
+ master = getpid();
+
+ signal(SIGTERM, dumpabort); /* Slave sends SIGTERM on dumpabort() */
+ signal(SIGPIPE, sigpipe);
+ signal(SIGUSR1, tperror); /* Slave sends SIGUSR1 on tape errors */
+ signal(SIGUSR2, proceed); /* Slave sends SIGUSR2 to next slave */
+
+ for (i = 0; i < SLAVES; i++) {
+ if (i == slp - &slaves[0]) {
+ caught = 1;
+ } else {
+ caught = 0;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM, 0, cmd) < 0 ||
+ (slaves[i].pid = fork()) < 0)
+ quit("too many slaves, %d (recompile smaller): %s\n",
+ i, strerror(errno));
+
+ slaves[i].fd = cmd[1];
+ slaves[i].sent = 0;
+ if (slaves[i].pid == 0) { /* Slave starts up here */
+ for (j = 0; j <= i; j++)
+ (void) close(slaves[j].fd);
+ signal(SIGINT, SIG_IGN); /* Master handles this */
+#ifdef LINUX_FORK_BUG
+ if (atomic(write, cmd[0], (char *) &i, sizeof i)
+ != sizeof i)
+ quit("master/slave protocol botched 3\n");
+#endif
+ doslave(cmd[0], i);
+ Exit(X_FINOK);
+ }
+ }
+
+#ifdef LINUX_FORK_BUG
+ /*
+ * Wait for all slaves to _actually_ start to circumvent a bug in
+ * Linux kernels >= 2.1.3 where a signal sent to a child that hasn't
+ * returned from fork() causes a SEGV in the child process
+ */
+ for (i = 0; i < SLAVES; i++)
+ if (atomic(read, slaves[i].fd, (char *) &j, sizeof j) != sizeof j)
+ quit("master/slave protocol botched 4\n");
+#endif
+
+ /* write pid of next slave to each slave */
+ for (i = 0; i < SLAVES; i++)
+ (void) atomic(write, slaves[i].fd,
+ (char *) &slaves[(i + 1) % SLAVES].pid,
+ sizeof slaves[0].pid);
+
+ master = 0;
+}
+
+void
+killall()
+{
+ register int i;
+
+ for (i = 0; i < SLAVES; i++)
+ if (slaves[i].pid > 0)
+ (void) kill(slaves[i].pid, SIGKILL);
+}
+
+/*
+ * Synchronization - each process has a lockfile, and shares file
+ * descriptors to the following process's lockfile. When our write
+ * completes, we release our lock on the following process's lock-
+ * file, allowing the following process to lock it and proceed. We
+ * get the lock back for the next cycle by swapping descriptors.
+ */
+static void
+doslave(cmd, slave_number)
+ register int cmd;
+ int slave_number;
+{
+ register int nread;
+ int nextslave, size, wrote, eot_count;
+#ifdef __linux__
+ errcode_t retval;
+#endif
+
+#ifdef TDEBUG
+ msg("slave %d, pid %d\n", slave_number, getpid());
+#endif
+ /*
+ * Need our own seek pointer.
+ */
+ (void) close(diskfd);
+ if ((diskfd = open(disk, O_RDONLY)) < 0)
+ quit("slave couldn't reopen disk: %s\n", strerror(errno));
+#ifdef __linux__
+ ext2fs_close(fs);
+ retval = ext2fs_open(disk, 0, 0, 0, unix_io_manager, &fs);
+ if (retval)
+ quit("slave couldn't reopen disk: %s\n", strerror(errno));
+#endif /* __linux__ */
+
+ /*
+ * Need the pid of the next slave in the loop...
+ */
+ if ((nread = atomic(read, cmd, (char *)&nextslave, sizeof nextslave))
+ != sizeof nextslave) {
+ quit("master/slave protocol botched - didn't get pid of next slave.\n");
+ }
+
+ /*
+ * Get list of blocks to dump, read the blocks into tape buffer
+ */
+ while ((nread = atomic(read, cmd, (char *)slp->req, reqsiz)) == reqsiz) {
+ register struct req *p = slp->req;
+
+ for (trecno = 0; trecno < ntrec;
+ trecno += p->count, p += p->count) {
+ if (p->dblk) {
+ bread(p->dblk, slp->tblock[trecno],
+ p->count * TP_BSIZE);
+ } else {
+ if (p->count != 1 || atomic(read, cmd,
+ (char *)slp->tblock[trecno],
+ TP_BSIZE) != TP_BSIZE)
+ quit("master/slave protocol botched.\n");
+ }
+ }
+ if (setjmp(jmpbuf) == 0) {
+ ready = 1;
+ if (!caught)
+ (void) pause();
+ }
+ ready = 0;
+ caught = 0;
+
+ /* Try to write the data... */
+ eot_count = 0;
+ size = 0;
+
+ while (eot_count < 10 && size < writesize) {
+#ifdef RDUMP
+ if (host)
+ wrote = rmtwrite(slp->tblock[0]+size,
+ writesize-size);
+ else
+#endif
+ wrote = write(tapefd, slp->tblock[0]+size,
+ writesize-size);
+#ifdef WRITEDEBUG
+ msg("slave %d wrote %d\n", slave_number, wrote);
+#endif
+ if (wrote < 0)
+ break;
+ if (wrote == 0)
+ eot_count++;
+ size += wrote;
+ }
+
+#ifdef WRITEDEBUG
+ if (size != writesize)
+ msg("slave %d only wrote %d out of %d bytes and gave up.\n",
+ slave_number, size, writesize);
+#endif
+
+ if (eot_count > 0)
+ size = 0;
+
+ /*
+ * fixme: Pyramids running OSx return ENOSPC
+ * at EOT on 1/2 inch drives.
+ */
+ if (size < 0) {
+ (void) kill(master, SIGUSR1);
+ for (;;)
+ (void) sigpause(0);
+ } else {
+ /*
+ * pass size of write back to master
+ * (for EOT handling)
+ */
+ (void) atomic(write, cmd, (char *)&size, sizeof size);
+ }
+
+ /*
+ * If partial write, don't want next slave to go.
+ * Also jolts him awake.
+ */
+ (void) kill(nextslave, SIGUSR2);
+ }
+ if (nread != 0)
+ quit("error reading command pipe: %s\n", strerror(errno));
+}
+
+/*
+ * Since a read from a pipe may not return all we asked for,
+ * or a write may not write all we ask if we get a signal,
+ * loop until the count is satisfied (or error).
+ */
+static int
+atomic(func, fd, buf, count)
+ int (*func)(), fd;
+ char *buf;
+ int count;
+{
+ int got, need = count;
+
+ while ((got = (*func)(fd, buf, need)) > 0 && (need -= got) > 0)
+ buf += got;
+ return (got < 0 ? got : count - need);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1988, 1991, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)traverse.c 8.7 (Berkeley) 6/15/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#include <err.h>
+#include <stdlib.h>
+#else /* __linux__ */
+#ifdef sunos
+#include <sys/vnode.h>
+
+#include <ufs/fs.h>
+#include <ufs/fsdir.h>
+#include <ufs/inode.h>
+#else
+#include <ufs/ufs/dir.h>
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#endif
+#endif /* __linux__ */
+
+#include <protocols/dumprestore.h>
+
+#include <ctype.h>
+#include <stdio.h>
+#ifdef __STDC__
+#include <string.h>
+#include <unistd.h>
+#endif
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "dump.h"
+
+#define HASDUMPEDFILE 0x1
+#define HASSUBDIRS 0x2
+
+#ifdef FS_44INODEFMT
+typedef quad_t fsizeT;
+#else
+typedef long fsizeT;
+#endif
+
+#ifndef __linux__
+static int dirindir __P((ino_t ino, daddr_t blkno, int level, long *size));
+#endif
+static void dmpindir __P((ino_t ino, daddr_t blk, int level, fsizeT *size));
+#ifdef __linux__
+static int searchdir __P((struct ext2_dir_entry *dp, int offset,
+ int blocksize, char *buf, void *private));
+#else
+static int searchdir __P((ino_t ino, daddr_t blkno, long size, long filesize));
+#endif
+
+/*
+ * This is an estimation of the number of TP_BSIZE blocks in the file.
+ * It estimates the number of blocks in files with holes by assuming
+ * that all of the blocks accounted for by di_blocks are data blocks
+ * (when some of the blocks are usually used for indirect pointers);
+ * hence the estimate may be high.
+ */
+long
+blockest(dp)
+ register struct dinode *dp;
+{
+ long blkest, sizeest;
+
+ /*
+ * dp->di_size is the size of the file in bytes.
+ * dp->di_blocks stores the number of sectors actually in the file.
+ * If there are more sectors than the size would indicate, this just
+ * means that there are indirect blocks in the file or unused
+ * sectors in the last file block; we can safely ignore these
+ * (blkest = sizeest below).
+ * If the file is bigger than the number of sectors would indicate,
+ * then the file has holes in it. In this case we must use the
+ * block count to estimate the number of data blocks used, but
+ * we use the actual size for estimating the number of indirect
+ * dump blocks (sizeest vs. blkest in the indirect block
+ * calculation).
+ */
+ blkest = howmany(dbtob(dp->di_blocks), TP_BSIZE);
+ sizeest = howmany(dp->di_size, TP_BSIZE);
+ if (blkest > sizeest)
+ blkest = sizeest;
+#ifdef __linux__
+ if (dp->di_size > fs->blocksize * NDADDR) {
+ /* calculate the number of indirect blocks on the dump tape */
+ blkest +=
+ howmany(sizeest - NDADDR * fs->blocksize / TP_BSIZE,
+ TP_NINDIR);
+ }
+#else
+ if (dp->di_size > sblock->fs_bsize * NDADDR) {
+ /* calculate the number of indirect blocks on the dump tape */
+ blkest +=
+ howmany(sizeest - NDADDR * sblock->fs_bsize / TP_BSIZE,
+ TP_NINDIR);
+ }
+#endif
+ return (blkest + 1);
+}
+
+/* Auxiliary macro to pick up files changed since previous dump. */
+#define CHANGEDSINCE(dp, t) \
+ ((dp)->di_mtime >= (t) || (dp)->di_ctime >= (t))
+
+/* The WANTTODUMP macro decides whether a file should be dumped. */
+#ifdef UF_NODUMP
+#define WANTTODUMP(dp) \
+ (CHANGEDSINCE(dp, spcl.c_ddate) && \
+ (nonodump || ((dp)->di_flags & UF_NODUMP) != UF_NODUMP))
+#else
+#define WANTTODUMP(dp) CHANGEDSINCE(dp, spcl.c_ddate)
+#endif
+
+/*
+ * Dump pass 1.
+ *
+ * Walk the inode list for a filesystem to find all allocated inodes
+ * that have been modified since the previous dump time. Also, find all
+ * the directories in the filesystem.
+ */
+int
+mapfiles(maxino, tapesize)
+ ino_t maxino;
+ long *tapesize;
+{
+ register int mode;
+ register ino_t ino;
+ register struct dinode *dp;
+ int anydirskipped = 0;
+
+ for (ino = ROOTINO; ino < maxino; ino++) {
+ dp = getino(ino);
+ if ((mode = (dp->di_mode & IFMT)) == 0)
+ continue;
+#ifdef __linux__
+ if (dp->di_nlink == 0 || dp->di_dtime != 0)
+ continue;
+#endif
+ SETINO(ino, usedinomap);
+ if (mode == IFDIR)
+ SETINO(ino, dumpdirmap);
+ if (WANTTODUMP(dp)) {
+ SETINO(ino, dumpinomap);
+ if (mode != IFREG && mode != IFDIR && mode != IFLNK)
+ *tapesize += 1;
+ else
+ *tapesize += blockest(dp);
+ continue;
+ }
+ if (mode == IFDIR)
+ anydirskipped = 1;
+ }
+ /*
+ * Restore gets very upset if the root is not dumped,
+ * so ensure that it always is dumped.
+ */
+ SETINO(ROOTINO, dumpinomap);
+ return (anydirskipped);
+}
+
+#ifdef __linux__
+struct mapfile_context {
+ long *tapesize;
+ int anydirskipped;
+};
+
+static int
+mapfilesindir(dirent, offset, blocksize, buf, private)
+ struct ext2_dir_entry *dirent;
+ int offset;
+ int blocksize;
+ char *buf;
+ void *private;
+{
+ register struct dinode *dp;
+ register int mode;
+ ino_t ino;
+ errcode_t retval;
+ struct mapfile_context *mfc;
+
+ ino = dirent->inode;
+ mfc = (struct mapfile_context *)private;
+ dp = getino(ino);
+ if ((mode = (dp->di_mode & IFMT)) != 0 &&
+ dp->di_nlink != 0 && dp->di_dtime == 0) {
+ SETINO(ino, usedinomap);
+ if (mode == IFDIR)
+ SETINO(ino, dumpdirmap);
+ if (WANTTODUMP(dp)) {
+ SETINO(ino, dumpinomap);
+ if (mode != IFREG && mode != IFDIR && mode != IFLNK)
+ *mfc->tapesize += 1;
+ else
+ *mfc->tapesize += blockest(dp);
+ }
+ if (mode == IFDIR) {
+ mfc->anydirskipped = 1;
+ if ((dirent->name[0] != '.' || dirent->name_len != 1) &&
+ (dirent->name[0] != '.' || dirent->name[1] != '.' ||
+ dirent->name_len != 2)) {
+ retval = ext2fs_dir_iterate(fs, ino, 0, NULL,
+ mapfilesindir, private);
+ if (retval)
+ return retval;
+ }
+ }
+ }
+ return 0;
+}
+
+/*
+ * Dump pass 1.
+ *
+ * Walk the inode list for a filesystem to find all allocated inodes
+ * that have been modified since the previous dump time. Also, find all
+ * the directories in the filesystem.
+ */
+int
+mapfilesfromdir(maxino, tapesize, directory)
+ ino_t maxino;
+ long *tapesize;
+ char *directory;
+{
+ errcode_t retval;
+ struct mapfile_context mfc;
+ ino_t dir_ino;
+ char dir_name [MAXPATHLEN];
+ int i;
+
+ /*
+ * Mark every directory in the path as being dumped
+ */
+ for (i = 0; i < strlen (directory); i++) {
+ if (directory[i] == '/') {
+ strncpy (dir_name, directory, i);
+ dir_name[i] = '\0';
+ retval = ext2fs_namei(fs, ROOTINO, ROOTINO, dir_name,
+ &dir_ino);
+ if (retval) {
+ com_err(disk, retval, "while translating %s",
+ dir_name);
+ exit(X_ABORT);
+ }
+/* SETINO(dir_ino, dumpinomap); */
+ SETINO(dir_ino, dumpdirmap);
+ }
+ }
+ /*
+ * Mark the final directory
+ */
+ retval = ext2fs_namei(fs, ROOTINO, ROOTINO, directory, &dir_ino);
+ if (retval) {
+ com_err(disk, retval, "while translating %s", directory);
+ exit(X_ABORT);
+ }
+/* SETINO(dir_ino, dumpinomap); */
+ SETINO(dir_ino, dumpdirmap);
+
+ mfc.tapesize = tapesize;
+ mfc.anydirskipped = 0;
+ retval = ext2fs_dir_iterate(fs, dir_ino, 0, NULL, mapfilesindir,
+ (void *)&mfc);
+
+ if (retval) {
+ com_err(disk, retval, "while mapping files in %s", directory);
+ exit(X_ABORT);
+ }
+ /*
+ * Restore gets very upset if the root is not dumped,
+ * so ensure that it always is dumped.
+ */
+/* SETINO(ROOTINO, dumpinomap); */
+ SETINO(ROOTINO, dumpdirmap);
+ return (mfc.anydirskipped);
+}
+#endif
+
+/*
+ * Dump pass 2.
+ *
+ * Scan each directory on the filesystem to see if it has any modified
+ * files in it. If it does, and has not already been added to the dump
+ * list (because it was itself modified), then add it. If a directory
+ * has not been modified itself, contains no modified files and has no
+ * subdirectories, then it can be deleted from the dump list and from
+ * the list of directories. By deleting it from the list of directories,
+ * its parent may now qualify for the same treatment on this or a later
+ * pass using this algorithm.
+ */
+int
+mapdirs(maxino, tapesize)
+ ino_t maxino;
+ long *tapesize;
+{
+ register struct dinode *dp;
+ register int i, isdir;
+ register char *map;
+ register ino_t ino;
+ long filesize;
+ int ret, change = 0;
+
+ isdir = 0; /* XXX just to get gcc to shut up */
+ for (map = dumpdirmap, ino = 1; ino < maxino; ino++) {
+ if (((ino - 1) % NBBY) == 0) /* map is offset by 1 */
+ isdir = *map++;
+ else
+ isdir >>= 1;
+ if ((isdir & 1) == 0 || TSTINO(ino, dumpinomap))
+ continue;
+#ifdef __linux__
+ dp = getino(ino);
+ ret = 0;
+ ext2fs_dir_iterate(fs, ino, 0, NULL, searchdir, (void *) &ret);
+#else /* __linux__ */
+ dp = getino(ino);
+ filesize = dp->di_size;
+ for (ret = 0, i = 0; filesize > 0 && i < NDADDR; i++) {
+ if (dp->di_db[i] != 0)
+ ret |= searchdir(ino, dp->di_db[i],
+ (long)dblksize(sblock, dp, i),
+ filesize);
+ if (ret & HASDUMPEDFILE)
+ filesize = 0;
+ else
+ filesize -= sblock->fs_bsize;
+ }
+ for (i = 0; filesize > 0 && i < NIADDR; i++) {
+ if (dp->di_ib[i] == 0)
+ continue;
+ ret |= dirindir(ino, dp->di_ib[i], i, &filesize);
+ }
+#endif /* __linux__ */
+ if (ret & HASDUMPEDFILE) {
+ SETINO(ino, dumpinomap);
+ *tapesize += blockest(dp);
+ change = 1;
+ continue;
+ }
+ if ((ret & HASSUBDIRS) == 0) {
+ if (!TSTINO(ino, dumpinomap)) {
+ CLRINO(ino, dumpdirmap);
+ change = 1;
+ }
+ }
+ }
+ return (change);
+}
+
+#ifndef __linux__
+/*
+ * Read indirect blocks, and pass the data blocks to be searched
+ * as directories. Quit as soon as any entry is found that will
+ * require the directory to be dumped.
+ */
+static int
+dirindir(ino, blkno, ind_level, filesize)
+ ino_t ino;
+ daddr_t blkno;
+ int ind_level;
+ long *filesize;
+{
+ int ret = 0;
+ register int i;
+ daddr_t idblk[MAXNINDIR];
+
+ bread(fsbtodb(sblock, blkno), (char *)idblk, (int)sblock->fs_bsize);
+ if (ind_level <= 0) {
+ for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
+ blkno = idblk[i];
+ if (blkno != 0)
+ ret |= searchdir(ino, blkno, sblock->fs_bsize,
+ *filesize);
+ if (ret & HASDUMPEDFILE)
+ *filesize = 0;
+ else
+ *filesize -= sblock->fs_bsize;
+ }
+ return (ret);
+ }
+ ind_level--;
+ for (i = 0; *filesize > 0 && i < NINDIR(sblock); i++) {
+ blkno = idblk[i];
+ if (blkno != 0)
+ ret |= dirindir(ino, blkno, ind_level, filesize);
+ }
+ return (ret);
+}
+#endif /* !__linux__ */
+
+/*
+ * Scan a disk block containing directory information looking to see if
+ * any of the entries are on the dump list and to see if the directory
+ * contains any subdirectories.
+ */
+#ifdef __linux__
+static int
+searchdir(dp, offset, blocksize, buf, private)
+ struct ext2_dir_entry *dp;
+ int offset;
+ int blocksize;
+ char *buf;
+ void *private;
+{
+ int *ret = (int *) private;
+
+ if (dp->inode == 0)
+ return 0;
+ if (dp->name[0] == '.') {
+ if (dp->name_len == 1)
+ return 0;
+ if (dp->name[1] == '.' && dp->name_len == 2)
+ return 0;
+ }
+ if (TSTINO(dp->inode, dumpinomap)) {
+ *ret |= HASDUMPEDFILE;
+ if (*ret & HASSUBDIRS)
+ return DIRENT_ABORT;
+ }
+ if (TSTINO(dp->inode, dumpdirmap)) {
+ *ret |= HASSUBDIRS;
+ if (*ret & HASDUMPEDFILE)
+ return DIRENT_ABORT;
+ }
+ return 0;
+}
+
+#else /* __linux__ */
+
+static int
+searchdir(ino, blkno, size, filesize)
+ ino_t ino;
+ daddr_t blkno;
+ register long size;
+ long filesize;
+{
+ register struct direct *dp;
+ register long loc, ret = 0;
+ char dblk[MAXBSIZE];
+
+ bread(fsbtodb(sblock, blkno), dblk, (int)size);
+ if (filesize < size)
+ size = filesize;
+ for (loc = 0; loc < size; ) {
+ dp = (struct direct *)(dblk + loc);
+ if (dp->d_reclen == 0) {
+ msg("corrupted directory, inumber %d\n", ino);
+ break;
+ }
+ loc += dp->d_reclen;
+ if (dp->d_ino == 0)
+ continue;
+ if (dp->d_name[0] == '.') {
+ if (dp->d_name[1] == '\0')
+ continue;
+ if (dp->d_name[1] == '.' && dp->d_name[2] == '\0')
+ continue;
+ }
+ if (TSTINO(dp->d_ino, dumpinomap)) {
+ ret |= HASDUMPEDFILE;
+ if (ret & HASSUBDIRS)
+ break;
+ }
+ if (TSTINO(dp->d_ino, dumpdirmap)) {
+ ret |= HASSUBDIRS;
+ if (ret & HASDUMPEDFILE)
+ break;
+ }
+ }
+ return (ret);
+}
+#endif /* __linux__ */
+
+#ifdef __linux__
+
+struct block_context {
+ ino_t ino;
+ int *buf;
+ int cnt;
+ int max;
+ int next_block;
+};
+
+/*
+ * Dump a block to the tape
+ */
+static int
+dumponeblock(ext2_filsys fs, blk_t *blocknr, int blockcnt, void *private)
+{
+ struct block_context *p;
+ int i;
+
+ if (blockcnt < NDADDR)
+ return 0;
+ p = (struct block_context *)private;
+ for (i = p->next_block; i < blockcnt; i++) {
+ p->buf[p->cnt++] = 0;
+ if (p->cnt == p->max) {
+ blksout (p->buf, p->cnt, p->ino);
+ p->cnt = 0;
+ }
+ }
+ p->buf[p->cnt++] = *blocknr;
+ if (p->cnt == p->max) {
+ blksout (p->buf, p->cnt, p->ino);
+ p->cnt = 0;
+ }
+ p->next_block = blockcnt + 1;
+ return 0;
+}
+#endif
+
+/*
+ * Dump passes 3 and 4.
+ *
+ * Dump the contents of an inode to tape.
+ */
+void
+dumpino(dp, ino)
+ register struct dinode *dp;
+ ino_t ino;
+{
+ int ind_level, cnt;
+ fsizeT size;
+ char buf[TP_BSIZE];
+ struct old_bsd_inode obi;
+#ifdef __linux__
+ struct block_context bc;
+#endif
+
+ if (newtape) {
+ newtape = 0;
+ dumpmap(dumpinomap, TS_BITS, ino);
+ }
+ CLRINO(ino, dumpinomap);
+#ifdef __linux__
+ memset(&obi, 0, sizeof(obi));
+ obi.di_mode = dp->di_mode;
+ obi.di_uid = dp->di_uid;
+ obi.di_gid = dp->di_gid;
+ obi.di_qsize.v = (u_quad_t)dp->di_size;
+ obi.di_atime = dp->di_atime;
+ obi.di_mtime = dp->di_mtime;
+ obi.di_ctime = dp->di_ctime;
+ obi.di_nlink = dp->di_nlink;
+ obi.di_blocks = dp->di_blocks;
+ obi.di_flags = dp->di_flags;
+ obi.di_gen = dp->di_gen;
+ memmove(&obi.di_db, &dp->di_db, (NDADDR + NIADDR) * sizeof(daddr_t));
+ if (dp->di_file_acl || dp->di_dir_acl)
+ warn("ACLs in inode #%d won't be dumped", ino);
+ memmove(&spcl.c_dinode, &obi, sizeof(obi));
+#else /* __linux__ */
+ spcl.c_dinode = *dp;
+#endif /* __linux__ */
+ spcl.c_type = TS_INODE;
+ spcl.c_count = 0;
+ switch (dp->di_mode & S_IFMT) {
+
+ case 0:
+ /*
+ * Freed inode.
+ */
+ return;
+
+#ifdef __linux__
+ case S_IFDIR:
+ msg("Warning: dumpino called on a directory (ino %d)\n", ino);
+ return;
+#endif
+
+ case S_IFLNK:
+ /*
+ * Check for short symbolic link.
+ */
+#ifdef __linux__
+ if (dp->di_size > 0 &&
+ dp->di_size < EXT2_N_BLOCKS * sizeof (daddr_t)) {
+ spcl.c_addr[0] = 1;
+ spcl.c_count = 1;
+ writeheader(ino);
+ memmove(buf, dp->di_db, (u_long)dp->di_size);
+ buf[dp->di_size] = '\0';
+ writerec(buf, 0);
+ return;
+ }
+#endif /* __linux__ */
+#ifdef FS_44INODEFMT
+ if (dp->di_size > 0 &&
+ dp->di_size < sblock->fs_maxsymlinklen) {
+ spcl.c_addr[0] = 1;
+ spcl.c_count = 1;
+ writeheader(ino);
+ memmove(buf, dp->di_shortlink, (u_long)dp->di_size);
+ buf[dp->di_size] = '\0';
+ writerec(buf, 0);
+ return;
+ }
+#endif
+ /* fall through */
+
+#ifndef __linux__
+ case S_IFDIR:
+#endif
+ case S_IFREG:
+ if (dp->di_size > 0)
+ break;
+ /* fall through */
+
+ case S_IFIFO:
+ case S_IFSOCK:
+ case S_IFCHR:
+ case S_IFBLK:
+ writeheader(ino);
+ return;
+
+ default:
+ msg("Warning: undefined file type 0%o\n", dp->di_mode & IFMT);
+ return;
+ }
+ if (dp->di_size > NDADDR * sblock->fs_bsize)
+#ifdef __linux__
+ cnt = NDADDR * EXT2_FRAGS_PER_BLOCK(fs->super);
+#else
+ cnt = NDADDR * sblock->fs_frag;
+#endif
+ else
+ cnt = howmany(dp->di_size, sblock->fs_fsize);
+ blksout(&dp->di_db[0], cnt, ino);
+ if ((size = ((int)dp->di_size) - NDADDR * sblock->fs_bsize) <= 0)
+ return;
+#ifdef __linux__
+ bc.max = NINDIR(sblock) * EXT2_FRAGS_PER_BLOCK(fs->super);
+ bc.buf = (int *)malloc (bc.max * sizeof (int));
+ bc.cnt = 0;
+ bc.ino = ino;
+ bc.next_block = NDADDR;
+
+ ext2fs_block_iterate (fs, ino, 0, NULL, dumponeblock, (void *)&bc);
+ if (bc.cnt > 0) {
+ blksout (bc.buf, bc.cnt, bc.ino);
+ }
+#else
+ for (ind_level = 0; ind_level < NIADDR; ind_level++) {
+ dmpindir(ino, dp->di_ib[ind_level], ind_level, &size);
+ if (size <= 0)
+ return;
+ }
+#endif
+}
+
+#ifdef __linux__
+
+struct convert_dir_context {
+ char *buf;
+ int prev_offset;
+ int offset;
+ int bs;
+};
+
+/*
+ * This function converts an ext2fs directory entry to the BSD format.
+ *
+ * Basically, it adds a null-character at the end of the name, recomputes the
+ * size of the entry, and creates it in a temporary buffer
+ */
+static int
+convert_dir(dirent, offset, blocksize, buf, private)
+ struct ext2_dir_entry *dirent;
+ int offset;
+ int blocksize;
+ char *buf;
+ void *private;
+{
+ struct convert_dir_context *p;
+ struct direct *dp;
+ int reclen;
+
+ p = (struct convert_dir_context *)private;
+
+ reclen = EXT2_DIR_REC_LEN(dirent->name_len + 1);
+ if (((p->offset + reclen - 1) / p->bs) != (p->offset / p->bs)) {
+ dp = (struct direct *)(p->buf + p->prev_offset);
+ dp->d_reclen += p->bs - (p->offset % p->bs);
+ p->offset += p->bs - (p->offset % p->bs);
+ }
+
+ dp = (struct direct *)(p->buf + p->offset);
+ dp->d_ino = dirent->inode;
+ dp->d_reclen = reclen;
+ dp->d_type = 0;
+ dp->d_namlen = dirent->name_len;
+ strncpy(dp->d_name, dirent->name, dirent->name_len);
+ dp->d_name[dp->d_namlen] = '\0';
+ p->prev_offset = p->offset;
+ p->offset += reclen;
+
+ return 0;
+}
+
+/*
+ * Dump pass 3
+ *
+ * Dumps a directory to tape after converting it to the BSD format
+ */
+void
+dumpdirino(dp, ino)
+ register struct dinode *dp;
+ ino_t ino;
+{
+ fsizeT size;
+ char buf[TP_BSIZE];
+ struct old_bsd_inode obi;
+ struct convert_dir_context cdc;
+ errcode_t retval;
+ struct ext2_dir_entry *de;
+ fsizeT dir_size;
+
+ if (newtape) {
+ newtape = 0;
+ dumpmap(dumpinomap, TS_BITS, ino);
+ }
+ CLRINO(ino, dumpinomap);
+
+ /*
+ * Convert the directory to the BSD format
+ */
+ /* Allocate a buffer for the conversion (twice the size of the
+ ext2fs directory to avoid problems ;-) */
+ cdc.buf = (char *)malloc(dp->di_size * 2 * sizeof(char));
+ if (cdc.buf == NULL)
+ err(1, "Cannot allocate buffer to convert directory #%ld\n",
+ ino);
+ cdc.offset = 0;
+ cdc.prev_offset = 0;
+ cdc.bs = MIN(DIRBLKSIZ, TP_BSIZE);
+ /* Do the conversion */
+ retval = ext2fs_dir_iterate(fs, ino, 0, NULL, convert_dir, (void *)&cdc);
+ if (retval) {
+ com_err(disk, retval, "while converting directory #%ld\n", ino);
+ exit(X_ABORT);
+ }
+ /* Fix the last entry */
+ if ((cdc.offset % cdc.bs) != 0) {
+ de = (struct ext2_dir_entry *)(cdc.buf + cdc.prev_offset);
+ de->rec_len += cdc.bs - (cdc.offset % cdc.bs);
+ cdc.offset += cdc.bs - (cdc.offset % cdc.bs);
+ }
+
+ dir_size = cdc.offset;
+
+#ifdef __linux__
+ memset(&obi, 0, sizeof(obi));
+ obi.di_mode = dp->di_mode;
+ obi.di_uid = dp->di_uid;
+ obi.di_gid = dp->di_gid;
+ obi.di_qsize.v = dir_size; /* (u_quad_t)dp->di_size; */
+ obi.di_atime = dp->di_atime;
+ obi.di_mtime = dp->di_mtime;
+ obi.di_ctime = dp->di_ctime;
+ obi.di_nlink = dp->di_nlink;
+ obi.di_blocks = dp->di_blocks;
+ obi.di_flags = dp->di_flags;
+ obi.di_gen = dp->di_gen;
+ memmove(&obi.di_db, &dp->di_db, (NDADDR + NIADDR) * sizeof(daddr_t));
+ if (dp->di_file_acl || dp->di_dir_acl)
+ warn("ACLs in inode #%d won't be dumped", ino);
+ memmove(&spcl.c_dinode, &obi, sizeof(obi));
+#else /* __linux__ */
+ spcl.c_dinode = *dp;
+#endif /* __linux__ */
+ spcl.c_type = TS_INODE;
+ spcl.c_count = 0;
+ switch (dp->di_mode & S_IFMT) {
+
+ case 0:
+ /*
+ * Freed inode.
+ */
+ return;
+
+ case S_IFDIR:
+ if (dir_size > 0)
+ break;
+ msg("Warning: size of directory inode #%d is <= 0 (%d)!\n",
+ ino, dir_size);
+ return;
+
+ default:
+ msg("Warning: dumpdirino called with file type 0%o (inode #%d)\n",
+ dp->di_mode & IFMT, ino);
+ return;
+ }
+ for (size = 0; size < dir_size; size += TP_BSIZE) {
+ spcl.c_addr[0] = 1;
+ spcl.c_count = 1;
+ writeheader(ino);
+ memmove(buf, cdc.buf + size, TP_BSIZE);
+ writerec(buf, 0);
+ spcl.c_type = TS_ADDR;
+ }
+
+ (void)free(cdc.buf);
+}
+#endif /* __linux__ */
+
+#ifndef __linux__
+/*
+ * Read indirect blocks, and pass the data blocks to be dumped.
+ */
+static void
+dmpindir(ino, blk, ind_level, size)
+ ino_t ino;
+ daddr_t blk;
+ int ind_level;
+ fsizeT *size;
+{
+ int i, cnt;
+ daddr_t idblk[MAXNINDIR];
+
+ if (blk != 0)
+ bread(fsbtodb(sblock, blk), (char *)idblk, (int) sblock->fs_bsize);
+ else
+ memset(idblk, 0, (int)sblock->fs_bsize);
+ if (ind_level <= 0) {
+ if (*size < NINDIR(sblock) * sblock->fs_bsize)
+ cnt = howmany(*size, sblock->fs_fsize);
+ else
+#ifdef __linux__
+ cnt = NINDIR(sblock) * EXT2_FRAGS_PER_BLOCK(fs->super);
+#else
+ cnt = NINDIR(sblock) * sblock->fs_frag;
+#endif
+ *size -= NINDIR(sblock) * sblock->fs_bsize;
+ blksout(&idblk[0], cnt, ino);
+ return;
+ }
+ ind_level--;
+ for (i = 0; i < NINDIR(sblock); i++) {
+ dmpindir(ino, idblk[i], ind_level, size);
+ if (*size <= 0)
+ return;
+ }
+}
+#endif
+
+/*
+ * Collect up the data into tape record sized buffers and output them.
+ */
+void
+blksout(blkp, frags, ino)
+ daddr_t *blkp;
+ int frags;
+ ino_t ino;
+{
+ register daddr_t *bp;
+ int i, j, count, blks, tbperdb;
+
+ blks = howmany(frags * sblock->fs_fsize, TP_BSIZE);
+ tbperdb = sblock->fs_bsize >> tp_bshift;
+ for (i = 0; i < blks; i += TP_NINDIR) {
+ if (i + TP_NINDIR > blks)
+ count = blks;
+ else
+ count = i + TP_NINDIR;
+ for (j = i; j < count; j++)
+ if (blkp[j / tbperdb] != 0)
+ spcl.c_addr[j - i] = 1;
+ else
+ spcl.c_addr[j - i] = 0;
+ spcl.c_count = count - i;
+ writeheader(ino);
+ bp = &blkp[i / tbperdb];
+ for (j = i; j < count; j += tbperdb, bp++)
+ if (*bp != 0)
+ if (j + tbperdb <= count)
+ dumpblock(*bp, (int)sblock->fs_bsize);
+ else
+ dumpblock(*bp, (count - j) * TP_BSIZE);
+ spcl.c_type = TS_ADDR;
+ }
+}
+
+/*
+ * Dump a map to the tape.
+ */
+void
+dumpmap(map, type, ino)
+ char *map;
+ int type;
+ ino_t ino;
+{
+ register int i;
+ char *cp;
+
+ spcl.c_type = type;
+ spcl.c_count = howmany(mapsize * sizeof(char), TP_BSIZE);
+ writeheader(ino);
+ for (i = 0, cp = map; i < spcl.c_count; i++, cp += TP_BSIZE)
+ writerec(cp, 0);
+}
+
+/*
+ * Write a header record to the dump tape.
+ */
+void
+writeheader(ino)
+ ino_t ino;
+{
+#ifdef __linux__
+ register __s32 sum, cnt, *lp;
+#else
+ register long sum, cnt, *lp;
+#endif
+
+ spcl.c_inumber = ino;
+ spcl.c_magic = NFS_MAGIC;
+ spcl.c_checksum = 0;
+#ifdef __linux__
+ lp = (__s32 *)&spcl;
+#else
+ lp = (long *)&spcl;
+#endif
+ sum = 0;
+#ifdef __linux__
+ cnt = sizeof(union u_spcl) / (4 * sizeof(__s32));
+#else
+ cnt = sizeof(union u_spcl) / (4 * sizeof(long));
+#endif
+ while (--cnt >= 0) {
+ sum += *lp++;
+ sum += *lp++;
+ sum += *lp++;
+ sum += *lp++;
+ }
+ spcl.c_checksum = CHECKSUM - sum;
+ writerec((char *)&spcl, 1);
+}
+
+#ifdef __linux__
+struct dinode *
+getino(inum)
+ ino_t inum;
+{
+ static struct dinode dinode;
+
+ curino = inum;
+ ext2fs_read_inode(fs, inum, (struct ext2_inode *) &dinode);
+ return &dinode;
+}
+#else /* __linux__ */
+struct dinode *
+getino(inum)
+ ino_t inum;
+{
+ static daddr_t minino, maxino;
+ static struct dinode inoblock[MAXINOPB];
+
+ curino = inum;
+ if (inum >= minino && inum < maxino)
+ return (&inoblock[inum - minino]);
+ bread(fsbtodb(sblock, ino_to_fsba(sblock, inum)), (char *)inoblock,
+ (int)sblock->fs_bsize);
+ minino = inum - (inum % INOPB(sblock));
+ maxino = minino + INOPB(sblock);
+ return (&inoblock[inum - minino]);
+}
+#endif /* __linux__ */
+
+/*
+ * Read a chunk of data from the disk.
+ * Try to recover from hard errors by reading in sector sized pieces.
+ * Error recovery is attempted at most BREADEMAX times before seeking
+ * consent from the operator to continue.
+ */
+int breaderrors = 0;
+#define BREADEMAX 32
+
+void
+bread(blkno, buf, size)
+ daddr_t blkno;
+ char *buf;
+ int size;
+{
+ int cnt, i;
+ extern int errno;
+
+loop:
+#ifdef __linux__
+ if (ext2_llseek(diskfd, ((ext2_loff_t)blkno << dev_bshift), 0) !=
+ ((ext2_loff_t)blkno << dev_bshift))
+#else
+ if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) == -1)
+#endif
+ msg("bread: lseek fails\n");
+ if ((cnt = read(diskfd, buf, size)) == size)
+ return;
+ if (blkno + (size / dev_bsize) > fsbtodb(sblock, sblock->fs_size)) {
+ /*
+ * Trying to read the final fragment.
+ *
+ * NB - dump only works in TP_BSIZE blocks, hence
+ * rounds `dev_bsize' fragments up to TP_BSIZE pieces.
+ * It should be smarter about not actually trying to
+ * read more than it can get, but for the time being
+ * we punt and scale back the read only when it gets
+ * us into trouble. (mkm 9/25/83)
+ */
+ size -= dev_bsize;
+ goto loop;
+ }
+ if (cnt == -1)
+ msg("read error from %s: %s: [block %d]: count=%d\n",
+ disk, strerror(errno), blkno, size);
+ else
+ msg("short read error from %s: [block %d]: count=%d, got=%d\n",
+ disk, blkno, size, cnt);
+ if (++breaderrors > BREADEMAX) {
+ msg("More than %d block read errors from %d\n",
+ BREADEMAX, disk);
+ broadcast("DUMP IS AILING!\n");
+ msg("This is an unrecoverable error.\n");
+ if (!query("Do you want to attempt to continue?")){
+ dumpabort(0);
+ /*NOTREACHED*/
+ } else
+ breaderrors = 0;
+ }
+ /*
+ * Zero buffer, then try to read each sector of buffer separately.
+ */
+ memset(buf, 0, size);
+ for (i = 0; i < size; i += dev_bsize, buf += dev_bsize, blkno++) {
+#ifdef __linux__
+ if (ext2_llseek(diskfd, ((ext2_loff_t)blkno << dev_bshift), 0) !=
+ ((ext2_loff_t)blkno << dev_bshift))
+#else
+ if ((int)lseek(diskfd, ((off_t)blkno << dev_bshift), 0) == -1)
+#endif
+ msg("bread: lseek2 fails!\n");
+ if ((cnt = read(diskfd, buf, (int)dev_bsize)) == dev_bsize)
+ continue;
+ if (cnt == -1) {
+ msg("read error from %s: %s: [sector %d]: count=%d\n",
+ disk, strerror(errno), blkno, dev_bsize);
+ continue;
+ }
+ msg("short read error from %s: [sector %d]: count=%d, got=%d\n",
+ disk, blkno, dev_bsize, cnt);
+ }
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1980, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)unctime.c 8.2 (Berkeley) 6/14/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+
+#include <stdio.h>
+#include <time.h>
+#ifdef __STDC__
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#ifndef __P
+#include <sys/cdefs.h>
+#endif
+
+/*
+ * Convert a ctime(3) format string into a system format date.
+ * Return the date thus calculated.
+ *
+ * Return -1 if the string is not in ctime format.
+ */
+
+/*
+ * Offsets into the ctime string to various parts.
+ */
+
+#define E_MONTH 4
+#define E_DAY 8
+#define E_HOUR 11
+#define E_MINUTE 14
+#define E_SECOND 17
+#define E_YEAR 20
+
+static int lookup __P((char *));
+
+
+time_t
+unctime(str)
+ char *str;
+{
+ struct tm then;
+ char dbuf[26];
+
+ (void) strncpy(dbuf, str, sizeof(dbuf) - 1);
+ dbuf[sizeof(dbuf) - 1] = '\0';
+ dbuf[E_MONTH+3] = '\0';
+ if ((then.tm_mon = lookup(&dbuf[E_MONTH])) < 0)
+ return (-1);
+ then.tm_mday = atoi(&dbuf[E_DAY]);
+ then.tm_hour = atoi(&dbuf[E_HOUR]);
+ then.tm_min = atoi(&dbuf[E_MINUTE]);
+ then.tm_sec = atoi(&dbuf[E_SECOND]);
+ then.tm_year = atoi(&dbuf[E_YEAR]) - 1900;
+ then.tm_isdst = -1;
+ return(mktime(&then));
+}
+
+static char months[] =
+ "JanFebMarAprMayJunJulAugSepOctNovDec";
+
+static int
+lookup(str)
+ char *str;
+{
+ register char *cp, *cp2;
+
+ for (cp = months, cp2 = str; *cp != '\0'; cp += 3)
+ if (strncmp(cp, cp2, 3) == 0)
+ return((cp-months) / 3);
+ return(-1);
+}
--- /dev/null
+#! /bin/sh
+#
+# install - install a program, script, or datafile
+# This comes from X11R5.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# `make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+mkdirprog="${MKDIRPROG-mkdir}"
+
+tranformbasename=""
+transform_arg=""
+instcmd="$mvprog"
+chmodcmd="$chmodprog 0755"
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+dir_arg=""
+
+while [ x"$1" != x ]; do
+ case $1 in
+ -c) instcmd="$cpprog"
+ shift
+ continue;;
+
+ -d) dir_arg=true
+ shift
+ continue;;
+
+ -m) chmodcmd="$chmodprog $2"
+ shift
+ shift
+ continue;;
+
+ -o) chowncmd="$chownprog $2"
+ shift
+ shift
+ continue;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift
+ shift
+ continue;;
+
+ -s) stripcmd="$stripprog"
+ shift
+ continue;;
+
+ -t=*) transformarg=`echo $1 | sed 's/-t=//'`
+ shift
+ continue;;
+
+ -b=*) transformbasename=`echo $1 | sed 's/-b=//'`
+ shift
+ continue;;
+
+ *) if [ x"$src" = x ]
+ then
+ src=$1
+ else
+ # this colon is to work around a 386BSD /bin/sh bug
+ :
+ dst=$1
+ fi
+ shift
+ continue;;
+ esac
+done
+
+if [ x"$src" = x ]
+then
+ echo "install: no input file specified"
+ exit 1
+else
+ true
+fi
+
+if [ x"$dir_arg" != x ]; then
+ dst=$src
+ src=""
+
+ if [ -d $dst ]; then
+ instcmd=:
+ else
+ instcmd=mkdir
+ fi
+else
+
+# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
+# might cause directories to be created, which would be especially bad
+# if $src (and thus $dsttmp) contains '*'.
+
+ if [ -f $src -o -d $src ]
+ then
+ true
+ else
+ echo "install: $src does not exist"
+ exit 1
+ fi
+
+ if [ x"$dst" = x ]
+ then
+ echo "install: no destination specified"
+ exit 1
+ else
+ true
+ fi
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+ if [ -d $dst ]
+ then
+ dst="$dst"/`basename $src`
+ else
+ true
+ fi
+fi
+
+## this sed command emulates the dirname command
+dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
+
+# Make sure that the destination directory exists.
+# this part is taken from Noah Friedman's mkinstalldirs script
+
+# Skip lots of stat calls in the usual case.
+if [ ! -d "$dstdir" ]; then
+defaultIFS='
+'
+IFS="${IFS-${defaultIFS}}"
+
+oIFS="${IFS}"
+# Some sh's can't handle IFS=/ for some reason.
+IFS='%'
+set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
+IFS="${oIFS}"
+
+pathcomp=''
+
+while [ $# -ne 0 ] ; do
+ pathcomp="${pathcomp}${1}"
+ shift
+
+ if [ ! -d "${pathcomp}" ] ;
+ then
+ $mkdirprog "${pathcomp}"
+ else
+ true
+ fi
+
+ pathcomp="${pathcomp}/"
+done
+fi
+
+if [ x"$dir_arg" != x ]
+then
+ $doit $instcmd $dst &&
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
+else
+
+# If we're going to rename the final executable, determine the name now.
+
+ if [ x"$transformarg" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ dstfile=`basename $dst $transformbasename |
+ sed $transformarg`$transformbasename
+ fi
+
+# don't allow the sed command to completely eliminate the filename
+
+ if [ x"$dstfile" = x ]
+ then
+ dstfile=`basename $dst`
+ else
+ true
+ fi
+
+# Make a temp file name in the proper directory.
+
+ dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+ $doit $instcmd $src $dsttmp &&
+
+ trap "rm -f ${dsttmp}" 0 &&
+
+# and set any options; do chmod last to preserve setuid bits
+
+# If any of these fail, we abort the whole thing. If we want to
+# ignore errors from any of these, just make sure not to ignore
+# errors from the above "$doit $instcmd $src $dsttmp" command.
+
+ if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
+ if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
+ if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
+ if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
+
+# Now rename the file to the real destination.
+
+ $doit $rmcmd -f $dstdir/$dstfile &&
+ $doit $mvcmd $dsttmp $dstdir/$dstfile
+
+fi &&
+
+
+exit 0
--- /dev/null
+--- fs/read_write.c.orig Sun Aug 27 15:41:29 1995
++++ fs/read_write.c Sun Aug 27 15:42:39 1995
+@@ -112,9 +112,11 @@
+ }
+ if (tmp < 0)
+ return -EINVAL;
+- file->f_pos = tmp;
+- file->f_reada = 0;
+- file->f_version = ++event;
++ if (tmp != file->f_pos) {
++ file->f_pos = tmp;
++ file->f_reada = 0;
++ file->f_version = ++event;
++ }
+ memcpy_tofs(result, &file->f_pos, sizeof(loff_t));
+ return 0;
+ }
--- /dev/null
+top_srcdir= @top_srcdir@
+srcdir= @srcdir@
+
+@MCONFIG@
+
+CFLAGS= @CCOPTS@ -pipe $(DEFS) $(GINC) $(INC) @RESTOREDEBUG@
+LDFLAGS:= $(LDFLAGS) @STATIC@
+LIBS= $(GLIBS) -le2p
+DEPLIBS= ../compat/lib/libcompat.a
+
+PROG= restore
+LINKS= ${BINDIR}/restore ${BINDIR}/rrestore
+SRCS= dirs.c interactive.c main.c restore.c symtab.c tape.c \
+ utilities.c
+OBJS= dirs.o interactive.o main.o restore.o symtab.o tape.o \
+ utilities.o ../common/dumprmt.o
+MAN8= restore.8
+MLINKS= $(MANDIR)/restore.8 $(MANDIR)/rrestore.8
+
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(DEPLIBS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROG) $(OBJS) $(LIBS)
+
+install:: $(PROG)
+ $(INSTALLBIN) $(PROG) $(BINDIR)
+ $(INSTALLMAN) $(srcdir)/$(MAN8) $(MANDIR)
+ @set $(LINKS) $(MLINKS); \
+ while test $$# -ge 2; do \
+ l=$(DESTDIR)$$1; \
+ shift; \
+ t=$(DESTDIR)$$1; \
+ shift; \
+ echo $$t -\> $$l; \
+ $(RM) -f $$t; \
+ $(LN_S) $$l $$t; \
+ done; true
+
+clean::
+ $(RM) -f $(PROG) \#* *.s *.o *.a *~ core
+
+distclean:: clean
+ $(RM) -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)dirs.c 8.7 (Berkeley) 5/1/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ffs/fs.h>
+#endif /* __linux__ */
+#include <protocols/dumprestore.h>
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <endian.h>
+#else
+#include <machine/endian.h>
+#endif
+
+#include "pathnames.h"
+#include "restore.h"
+#include "extern.h"
+
+/*
+ * Symbol table of directories read from tape.
+ */
+#define HASHSIZE 1000
+#define INOHASH(val) (val % HASHSIZE)
+struct inotab {
+ struct inotab *t_next;
+ ino_t t_ino;
+ long t_seekpt;
+ long t_size;
+};
+static struct inotab *inotab[HASHSIZE];
+
+/*
+ * Information retained about directories.
+ */
+struct modeinfo {
+ ino_t ino;
+ struct timeval timep[2];
+ mode_t mode;
+ uid_t uid;
+ gid_t gid;
+ int flags;
+};
+
+/*
+ * Definitions for library routines operating on directories.
+ */
+#undef DIRBLKSIZ
+#define DIRBLKSIZ 1024
+struct rstdirdesc {
+ int dd_fd;
+ long dd_loc;
+ long dd_size;
+ char dd_buf[DIRBLKSIZ];
+};
+
+/*
+ * Global variables for this file.
+ */
+static long seekpt;
+static FILE *df, *mf;
+static RST_DIR *dirp;
+static char dirfile[32] = "#"; /* No file */
+static char modefile[32] = "#"; /* No file */
+static char dot[2] = "."; /* So it can be modified */
+
+/*
+ * Format of old style directories.
+ */
+#define ODIRSIZ 14
+struct odirect {
+ u_short d_ino;
+ char d_name[ODIRSIZ];
+};
+
+#ifdef __linux__
+static struct inotab *allocinotab __P((ino_t, struct new_bsd_inode *, long));
+#else
+static struct inotab *allocinotab __P((ino_t, struct dinode *, long));
+#endif
+static void dcvt __P((struct odirect *, struct direct *));
+static void flushent __P((void));
+static struct inotab *inotablookup __P((ino_t));
+static RST_DIR *opendirfile __P((const char *));
+static void putdir __P((char *, long));
+static void putent __P((struct direct *));
+static void rst_seekdir __P((RST_DIR *, long, long));
+static long rst_telldir __P((RST_DIR *));
+static struct direct *searchdir __P((ino_t, char *));
+
+/*
+ * Extract directory contents, building up a directory structure
+ * on disk for extraction by name.
+ * If genmode is requested, save mode, owner, and times for all
+ * directories on the tape.
+ */
+void
+extractdirs(genmode)
+ int genmode;
+{
+ register int i;
+#ifdef __linux__
+ register struct new_bsd_inode *ip;
+#else
+ register struct dinode *ip;
+#endif
+ struct inotab *itp;
+ struct direct nulldir;
+
+ vprintf(stdout, "Extract directories from tape\n");
+ (void) sprintf(dirfile, "%s/rstdir%d", tmpdir, dumpdate);
+ df = fopen(dirfile, "w");
+ if (df == NULL) {
+ fprintf(stderr,
+ "restore: %s - cannot create directory temporary\n",
+ dirfile);
+ fprintf(stderr, "fopen: %s\n", strerror(errno));
+ done(1);
+ }
+ if (genmode != 0) {
+ (void) sprintf(modefile, "%s/rstmode%d", tmpdir, dumpdate);
+ mf = fopen(modefile, "w");
+ if (mf == NULL) {
+ fprintf(stderr,
+ "restore: %s - cannot create modefile \n",
+ modefile);
+ fprintf(stderr, "fopen: %s\n", strerror(errno));
+ done(1);
+ }
+ }
+ nulldir.d_ino = 0;
+#ifdef __linux__
+ nulldir.d_type = DT_DIR;
+#endif
+ nulldir.d_namlen = 1;
+ (void) strcpy(nulldir.d_name, "/");
+ nulldir.d_reclen = DIRSIZ(0, &nulldir);
+ for (;;) {
+ curfile.name = "<directory file - name unknown>";
+ curfile.action = USING;
+ ip = curfile.dip;
+ if (ip == NULL || (ip->di_mode & IFMT) != IFDIR) {
+ (void) fclose(df);
+ dirp = opendirfile(dirfile);
+ if (dirp == NULL)
+ fprintf(stderr, "opendirfile: %s\n",
+ strerror(errno));
+ if (mf != NULL)
+ (void) fclose(mf);
+ i = dirlookup(dot);
+ if (i == 0)
+ panic("Root directory is not on tape\n");
+ return;
+ }
+ itp = allocinotab(curfile.ino, ip, seekpt);
+ getfile(putdir, xtrnull);
+ putent(&nulldir);
+ flushent();
+ itp->t_size = seekpt - itp->t_seekpt;
+ }
+}
+
+/*
+ * skip over all the directories on the tape
+ */
+void
+skipdirs()
+{
+
+ while (curfile.dip && (curfile.dip->di_mode & IFMT) == IFDIR) {
+ skipfile();
+ }
+}
+
+/*
+ * Recursively find names and inumbers of all files in subtree
+ * pname and pass them off to be processed.
+ */
+void
+treescan(pname, ino, todo)
+ char *pname;
+ ino_t ino;
+ long (*todo) __P((char *, ino_t, int));
+{
+ register struct inotab *itp;
+ register struct direct *dp;
+ int namelen;
+ long bpt;
+ char locname[MAXPATHLEN + 1];
+
+ itp = inotablookup(ino);
+ if (itp == NULL) {
+ /*
+ * Pname is name of a simple file or an unchanged directory.
+ */
+ (void) (*todo)(pname, ino, LEAF);
+ return;
+ }
+ /*
+ * Pname is a dumped directory name.
+ */
+ if ((*todo)(pname, ino, NODE) == FAIL)
+ return;
+ /*
+ * begin search through the directory
+ * skipping over "." and ".."
+ */
+ (void) strncpy(locname, pname, MAXPATHLEN);
+ (void) strncat(locname, "/", MAXPATHLEN);
+ namelen = strlen(locname);
+ rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+ dp = rst_readdir(dirp); /* "." */
+ if (dp != NULL && strcmp(dp->d_name, ".") == 0)
+ dp = rst_readdir(dirp); /* ".." */
+ else
+ fprintf(stderr, "Warning: `.' missing from directory %s\n",
+ pname);
+ if (dp != NULL && strcmp(dp->d_name, "..") == 0)
+ dp = rst_readdir(dirp); /* first real entry */
+ else
+ fprintf(stderr, "Warning: `..' missing from directory %s\n",
+ pname);
+ bpt = rst_telldir(dirp);
+ /*
+ * a zero inode signals end of directory
+ */
+ while (dp != NULL) {
+ locname[namelen] = '\0';
+ if (namelen + dp->d_namlen >= MAXPATHLEN) {
+ fprintf(stderr, "%s%s: name exceeds %d char\n",
+ locname, dp->d_name, MAXPATHLEN);
+ } else {
+ (void) strncat(locname, dp->d_name, (int)dp->d_namlen);
+ treescan(locname, dp->d_ino, todo);
+ rst_seekdir(dirp, bpt, itp->t_seekpt);
+ }
+ dp = rst_readdir(dirp);
+ bpt = rst_telldir(dirp);
+ }
+}
+
+/*
+ * Lookup a pathname which is always assumed to start from the ROOTINO.
+ */
+struct direct *
+pathsearch(pathname)
+ const char *pathname;
+{
+ ino_t ino;
+ struct direct *dp;
+ char *path, *name, buffer[MAXPATHLEN];
+
+ strcpy(buffer, pathname);
+ path = buffer;
+ ino = ROOTINO;
+ while (*path == '/')
+ path++;
+ dp = NULL;
+ while ((name = strsep(&path, "/")) != NULL && *name /* != NULL */) {
+ if ((dp = searchdir(ino, name)) == NULL)
+ return (NULL);
+ ino = dp->d_ino;
+ }
+ return (dp);
+}
+
+/*
+ * Lookup the requested name in directory inum.
+ * Return its inode number if found, zero if it does not exist.
+ */
+static struct direct *
+searchdir(inum, name)
+ ino_t inum;
+ char *name;
+{
+ register struct direct *dp;
+ register struct inotab *itp;
+ int len;
+
+ itp = inotablookup(inum);
+ if (itp == NULL)
+ return (NULL);
+ rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+ len = strlen(name);
+ do {
+ dp = rst_readdir(dirp);
+ if (dp == NULL)
+ return (NULL);
+ } while (dp->d_namlen != len || strncmp(dp->d_name, name, len) != 0);
+ return (dp);
+}
+
+/*
+ * Put the directory entries in the directory file
+ */
+static void
+putdir(buf, size)
+ char *buf;
+ long size;
+{
+ struct direct cvtbuf;
+ register struct odirect *odp;
+ struct odirect *eodp;
+ register struct direct *dp;
+ long loc, i;
+
+ if (cvtflag) {
+ eodp = (struct odirect *)&buf[size];
+ for (odp = (struct odirect *)buf; odp < eodp; odp++)
+ if (odp->d_ino != 0) {
+ dcvt(odp, &cvtbuf);
+ putent(&cvtbuf);
+ }
+ } else {
+ for (loc = 0; loc < size; ) {
+ dp = (struct direct *)(buf + loc);
+#ifdef DIRDEBUG
+ printf ("reclen = %d, namlen = %d, type = %d\n",
+ dp->d_reclen, dp->d_namlen, dp->d_type);
+#endif
+ if (Bcvt)
+ swabst((u_char *)"ls", (u_char *) dp);
+ if (oldinofmt && dp->d_ino != 0) {
+#ifdef __linux__
+ if (Bcvt)
+ swabst((u_char *)"s", (u_char *)&dp->d_namlen);
+#else
+# if BYTE_ORDER == BIG_ENDIAN
+ if (Bcvt)
+ dp->d_namlen = dp->d_type;
+# else
+ if (!Bcvt)
+ dp->d_namlen = dp->d_type;
+# endif
+#endif /* __linux__ */
+ dp->d_type = DT_UNKNOWN;
+ }
+#ifdef __linux__
+ /*
+ * Horrible hack to read FreeBSD 2.0 dumps
+ */
+ if (!oldinofmt)
+ swabst((u_char *)"6bs", (u_char *) dp);
+#endif /* __linux__ */
+#ifdef DIRDEBUG
+ printf ("reclen = %d, namlen = %d, type = %d\n",
+ dp->d_reclen, dp->d_namlen, dp->d_type);
+#endif
+ i = DIRBLKSIZ - (loc & (DIRBLKSIZ - 1));
+ if ((dp->d_reclen & 0x3) != 0 ||
+ dp->d_reclen > i ||
+ dp->d_reclen < DIRSIZ(0, dp) ||
+ dp->d_namlen > NAME_MAX) {
+ vprintf(stdout, "Mangled directory: ");
+ if ((dp->d_reclen & 0x3) != 0)
+ vprintf(stdout,
+ "reclen not multiple of 4 ");
+ if (dp->d_reclen < DIRSIZ(0, dp))
+ vprintf(stdout,
+ "reclen less than DIRSIZ (%d < %d) ",
+ dp->d_reclen, DIRSIZ(0, dp));
+ if (dp->d_namlen > NAME_MAX)
+ vprintf(stdout,
+ "reclen name too big (%d > %d) ",
+ dp->d_namlen, NAME_MAX);
+ vprintf(stdout, "\n");
+ loc += i;
+ continue;
+ }
+ loc += dp->d_reclen;
+ if (dp->d_ino != 0) {
+ putent(dp);
+ }
+ }
+ }
+}
+
+/*
+ * These variables are "local" to the following two functions.
+ */
+char dirbuf[DIRBLKSIZ];
+long dirloc = 0;
+long prev = 0;
+
+/*
+ * add a new directory entry to a file.
+ */
+static void
+putent(dp)
+ struct direct *dp;
+{
+ dp->d_reclen = DIRSIZ(0, dp);
+ if (dirloc + dp->d_reclen > DIRBLKSIZ) {
+ ((struct direct *)(dirbuf + prev))->d_reclen =
+ DIRBLKSIZ - prev;
+ (void) fwrite(dirbuf, 1, DIRBLKSIZ, df);
+ dirloc = 0;
+ }
+ memmove(dirbuf + dirloc, dp, (long)dp->d_reclen);
+ prev = dirloc;
+ dirloc += dp->d_reclen;
+}
+
+/*
+ * flush out a directory that is finished.
+ */
+static void
+flushent()
+{
+ ((struct direct *)(dirbuf + prev))->d_reclen = DIRBLKSIZ - prev;
+ (void) fwrite(dirbuf, (int)dirloc, 1, df);
+ seekpt = ftell(df);
+ dirloc = 0;
+}
+
+static void
+dcvt(odp, ndp)
+ register struct odirect *odp;
+ register struct direct *ndp;
+{
+
+ memset(ndp, 0, (long)(sizeof *ndp));
+ ndp->d_ino = odp->d_ino;
+#ifdef __linux__
+ ndp->d_type = DT_UNKNOWN;
+#endif
+ (void) strncpy(ndp->d_name, odp->d_name, ODIRSIZ);
+ ndp->d_namlen = strlen(ndp->d_name);
+ ndp->d_reclen = DIRSIZ(0, ndp);
+}
+
+/*
+ * Seek to an entry in a directory.
+ * Only values returned by rst_telldir should be passed to rst_seekdir.
+ * This routine handles many directories in a single file.
+ * It takes the base of the directory in the file, plus
+ * the desired seek offset into it.
+ */
+static void
+rst_seekdir(dirp, loc, base)
+ register RST_DIR *dirp;
+ long loc, base;
+{
+
+ if (loc == rst_telldir(dirp))
+ return;
+ loc -= base;
+ if (loc < 0)
+ fprintf(stderr, "bad seek pointer to rst_seekdir %d\n", loc);
+ (void) lseek(dirp->dd_fd, base + (loc & ~(DIRBLKSIZ - 1)), SEEK_SET);
+ dirp->dd_loc = loc & (DIRBLKSIZ - 1);
+ if (dirp->dd_loc != 0)
+ dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf, DIRBLKSIZ);
+}
+
+/*
+ * get next entry in a directory.
+ */
+struct direct *
+rst_readdir(dirp)
+ register RST_DIR *dirp;
+{
+ register struct direct *dp;
+
+ for (;;) {
+ if (dirp->dd_loc == 0) {
+ dirp->dd_size = read(dirp->dd_fd, dirp->dd_buf,
+ DIRBLKSIZ);
+ if (dirp->dd_size <= 0) {
+ dprintf(stderr, "error reading directory\n");
+ return (NULL);
+ }
+ }
+ if (dirp->dd_loc >= dirp->dd_size) {
+ dirp->dd_loc = 0;
+ continue;
+ }
+ dp = (struct direct *)(dirp->dd_buf + dirp->dd_loc);
+ if (dp->d_reclen == 0 ||
+ dp->d_reclen > DIRBLKSIZ + 1 - dirp->dd_loc) {
+ dprintf(stderr, "corrupted directory: bad reclen %d\n"
+ "dd_loc = %d, dd_size = %d\n",
+ dp->d_reclen, dirp->dd_loc, dirp->dd_size);
+ return (NULL);
+ }
+ dirp->dd_loc += dp->d_reclen;
+ if (dp->d_ino == 0 && strcmp(dp->d_name, "/") == 0)
+ return (NULL);
+ if (dp->d_ino >= maxino) {
+ dprintf(stderr, "corrupted directory: bad inum %d\n",
+ dp->d_ino);
+ continue;
+ }
+ return (dp);
+ }
+}
+
+/*
+ * Simulate the opening of a directory
+ */
+RST_DIR *
+rst_opendir(name)
+ const char *name;
+{
+ struct inotab *itp;
+ RST_DIR *dirp;
+ ino_t ino;
+
+ if ((ino = dirlookup(name)) > 0 &&
+ (itp = inotablookup(ino)) != NULL) {
+ dirp = opendirfile(dirfile);
+ rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+ return (dirp);
+ }
+ return (NULL);
+}
+
+/*
+ * In our case, there is nothing to do when closing a directory.
+ */
+void
+rst_closedir(dirp)
+ RST_DIR *dirp;
+{
+
+ (void)close(dirp->dd_fd);
+ free(dirp);
+ return;
+}
+
+/*
+ * Simulate finding the current offset in the directory.
+ */
+static long
+rst_telldir(dirp)
+ RST_DIR *dirp;
+{
+ return ((long)lseek(dirp->dd_fd,
+ (off_t)0, SEEK_CUR) - dirp->dd_size + dirp->dd_loc);
+}
+
+/*
+ * Open a directory file.
+ */
+static RST_DIR *
+opendirfile(name)
+ const char *name;
+{
+ register RST_DIR *dirp;
+ register int fd;
+
+ if ((fd = open(name, O_RDONLY)) == -1)
+ return (NULL);
+ if ((dirp = malloc(sizeof(RST_DIR))) == NULL) {
+ (void)close(fd);
+ return (NULL);
+ }
+ dirp->dd_fd = fd;
+ dirp->dd_loc = 0;
+ return (dirp);
+}
+
+/*
+ * Set the mode, owner, and times for all new or changed directories
+ */
+void
+setdirmodes(flags)
+ int flags;
+{
+ FILE *mf;
+ struct modeinfo node;
+ struct entry *ep;
+ char *cp;
+
+ vprintf(stdout, "Set directory mode, owner, and times.\n");
+ (void) sprintf(modefile, "%s/rstmode%d", tmpdir, dumpdate);
+ mf = fopen(modefile, "r");
+ if (mf == NULL) {
+ fprintf(stderr, "fopen: %s\n", strerror(errno));
+ fprintf(stderr, "cannot open mode file %s\n", modefile);
+ fprintf(stderr, "directory mode, owner, and times not set\n");
+ return;
+ }
+ clearerr(mf);
+ for (;;) {
+ (void) fread((char *)&node, 1, sizeof(struct modeinfo), mf);
+ if (feof(mf))
+ break;
+ ep = lookupino(node.ino);
+ if (command == 'i' || command == 'x') {
+ if (ep == NULL)
+ continue;
+ if ((flags & FORCE) == 0 && ep->e_flags & EXISTED) {
+ ep->e_flags &= ~NEW;
+ continue;
+ }
+ if (node.ino == ROOTINO &&
+ reply("set owner/mode for '.'") == FAIL)
+ continue;
+ }
+ if (ep == NULL) {
+ panic("cannot find directory inode %d\n", node.ino);
+ } else {
+ cp = myname(ep);
+ (void) chown(cp, node.uid, node.gid);
+ (void) chmod(cp, node.mode);
+#ifdef __linux__
+ (void) setflags(cp, node.flags);
+#else
+ (void) chflags(cp, node.flags);
+#endif
+ utimes(cp, node.timep);
+ ep->e_flags &= ~NEW;
+ }
+ }
+ if (ferror(mf))
+ panic("error setting directory modes\n");
+ (void) fclose(mf);
+}
+
+/*
+ * Generate a literal copy of a directory.
+ */
+int
+genliteraldir(name, ino)
+ char *name;
+ ino_t ino;
+{
+ register struct inotab *itp;
+ int ofile, dp, i, size;
+ char buf[BUFSIZ];
+
+ itp = inotablookup(ino);
+ if (itp == NULL)
+ panic("Cannot find directory inode %d named %s\n", ino, name);
+ if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC, 0666)) < 0) {
+ fprintf(stderr, "%s: ", name);
+ (void) fflush(stderr);
+ fprintf(stderr, "cannot create file: %s\n", strerror(errno));
+ return (FAIL);
+ }
+ rst_seekdir(dirp, itp->t_seekpt, itp->t_seekpt);
+ dp = dup(dirp->dd_fd);
+ for (i = itp->t_size; i > 0; i -= BUFSIZ) {
+ size = i < BUFSIZ ? i : BUFSIZ;
+ if (read(dp, buf, (int) size) == -1) {
+ fprintf(stderr,
+ "write error extracting inode %d, name %s\n",
+ curfile.ino, curfile.name);
+ fprintf(stderr, "read: %s\n", strerror(errno));
+ done(1);
+ }
+ if (!Nflag && write(ofile, buf, (int) size) == -1) {
+ fprintf(stderr,
+ "write error extracting inode %d, name %s\n",
+ curfile.ino, curfile.name);
+ fprintf(stderr, "write: %s\n", strerror(errno));
+ done(1);
+ }
+ }
+ (void) close(dp);
+ (void) close(ofile);
+ return (GOOD);
+}
+
+/*
+ * Determine the type of an inode
+ */
+int
+inodetype(ino)
+ ino_t ino;
+{
+ struct inotab *itp;
+
+ itp = inotablookup(ino);
+ if (itp == NULL)
+ return (LEAF);
+ return (NODE);
+}
+
+/*
+ * Allocate and initialize a directory inode entry.
+ * If requested, save its pertinent mode, owner, and time info.
+ */
+static struct inotab *
+allocinotab(ino, dip, seekpt)
+ ino_t ino;
+#ifdef __linux__
+ struct new_bsd_inode *dip;
+#else
+ struct dinode *dip;
+#endif
+ long seekpt;
+{
+ register struct inotab *itp;
+ struct modeinfo node;
+
+ itp = calloc(1, sizeof(struct inotab));
+ if (itp == NULL)
+ panic("no memory directory table\n");
+ itp->t_next = inotab[INOHASH(ino)];
+ inotab[INOHASH(ino)] = itp;
+ itp->t_ino = ino;
+ itp->t_seekpt = seekpt;
+ if (mf == NULL)
+ return (itp);
+ node.ino = ino;
+#ifdef __linux__
+ node.timep[0].tv_sec = dip->di_atime.tv_sec;
+ node.timep[0].tv_usec = dip->di_atime.tv_usec;
+ node.timep[1].tv_sec = dip->di_mtime.tv_sec;
+ node.timep[1].tv_usec = dip->di_mtime.tv_usec;
+#else /* __linux__ */
+ node.timep[0].tv_sec = dip->di_atime;
+ node.timep[0].tv_usec = dip->di_atimensec / 1000;
+ node.timep[1].tv_sec = dip->di_mtime;
+ node.timep[1].tv_usec = dip->di_mtimensec / 1000;
+#endif /* __linux__ */
+ node.mode = dip->di_mode;
+ node.flags = dip->di_flags;
+ node.uid = dip->di_uid;
+ node.gid = dip->di_gid;
+ (void) fwrite((char *)&node, 1, sizeof(struct modeinfo), mf);
+ return (itp);
+}
+
+/*
+ * Look up an inode in the table of directories
+ */
+static struct inotab *
+inotablookup(ino)
+ ino_t ino;
+{
+ register struct inotab *itp;
+
+ for (itp = inotab[INOHASH(ino)]; itp != NULL; itp = itp->t_next)
+ if (itp->t_ino == ino)
+ return (itp);
+ return (NULL);
+}
+
+/*
+ * Clean up and exit
+ */
+__dead void
+done(exitcode)
+ int exitcode;
+{
+
+ closemt();
+ if (modefile[0] != '#')
+ (void) unlink(modefile);
+ if (dirfile[0] != '#')
+ (void) unlink(dirfile);
+ exit(exitcode);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*-
+ * Copyright (c) 1992, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)extern.h 8.2 (Berkeley) 1/7/94
+ */
+
+struct entry *addentry __P((char *, ino_t, int));
+long addfile __P((char *, ino_t, int));
+void badentry __P((struct entry *, char *));
+void canon __P((char *, char *));
+void checkrestore __P((void));
+void closemt __P((void));
+void createfiles __P((void));
+void createleaves __P((char *));
+void compareleaves __P((void));
+void createlinks __P((void));
+long deletefile __P((char *, ino_t, int));
+void deleteino __P((ino_t));
+ino_t dirlookup __P((const char *));
+__dead void done __P((int));
+void dumpsymtable __P((char *, long));
+void extractdirs __P((int));
+int extractfile __P((char *));
+void comparefile __P((char *));
+void findunreflinks __P((void));
+char *flagvalues __P((struct entry *));
+void freeentry __P((struct entry *));
+void freename __P((char *));
+int genliteraldir __P((char *, ino_t));
+char *gentempname __P((struct entry *));
+void getfile __P((void (*)(char *, long), void (*)(char *, long)));
+void getvol __P((long));
+void initsymtable __P((char *));
+int inodetype __P((ino_t));
+int linkit __P((char *, char *, int));
+struct entry *lookupino __P((ino_t));
+struct entry *lookupname __P((char *));
+long listfile __P((char *, ino_t, int));
+ino_t lowerbnd __P((ino_t));
+void mktempname __P((struct entry *));
+void moveentry __P((struct entry *, char *));
+void msg __P((const char *, ...));
+char *myname __P((struct entry *));
+void newnode __P((struct entry *));
+void newtapebuf __P((long));
+long nodeupdates __P((char *, ino_t, int));
+void onintr __P((int));
+void panic __P((const char *, ...));
+void pathcheck __P((char *));
+struct direct *pathsearch __P((const char *));
+void printdumpinfo __P((void));
+void removeleaf __P((struct entry *));
+void removenode __P((struct entry *));
+void removeoldleaves __P((void));
+void removeoldnodes __P((void));
+void renameit __P((char *, char *));
+int reply __P((char *));
+RST_DIR *rst_opendir __P((const char *));
+struct direct *rst_readdir __P((RST_DIR *));
+void rst_closedir __P((RST_DIR *dirp));
+void runcmdshell __P((void));
+char *savename __P((char *));
+void setdirmodes __P((int));
+void setinput __P((char *));
+void setup __P((void));
+void skipdirs __P((void));
+void skipfile __P((void));
+void skipmaps __P((void));
+void swabst __P((u_char *, u_char *));
+void treescan __P((char *, ino_t, long (*)(char *, ino_t, int)));
+ino_t upperbnd __P((ino_t));
+long verifyfile __P((char *, ino_t, int));
+void xtrnull __P((char *, long));
+
+/* From ../dump/dumprmt.c */
+void rmtclose __P((void));
+int rmthost __P((char *));
+int rmtioctl __P((int, int));
+int rmtopen __P((char *, int));
+int rmtread __P((char *, int));
+int rmtseek __P((int, int));
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1985, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)interactive.c 8.5 (Berkeley) 5/1/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#include <ufs/ffs/fs.h>
+#endif /* __linux__ */
+#include <protocols/dumprestore.h>
+
+#include <setjmp.h>
+#include <glob.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "restore.h"
+#include "extern.h"
+
+#define round(a, b) (((a) + (b) - 1) / (b) * (b))
+
+/*
+ * Things to handle interruptions.
+ */
+static int runshell;
+static jmp_buf reset;
+static char *nextarg = NULL;
+
+/*
+ * Structure and routines associated with listing directories.
+ */
+struct afile {
+ ino_t fnum; /* inode number of file */
+ char *fname; /* file name */
+ short len; /* name length */
+ char prefix; /* prefix character */
+ char postfix; /* postfix character */
+};
+struct arglist {
+ int freeglob; /* glob structure needs to be freed */
+ int argcnt; /* next globbed argument to return */
+ glob_t glob; /* globbing information */
+ char *cmd; /* the current command */
+};
+
+static char *copynext __P((char *, char *));
+static int fcmp __P((const void *, const void *));
+static void formatf __P((struct afile *, int));
+static void getcmd __P((char *, char *, char *, struct arglist *));
+struct dirent *glob_readdir __P((RST_DIR *dirp));
+static int glob_stat __P((const char *, struct stat *));
+static void mkentry __P((char *, struct direct *, struct afile *));
+static void printlist __P((char *, char *));
+
+/*
+ * Read and execute commands from the terminal.
+ */
+void
+runcmdshell()
+{
+ register struct entry *np;
+ ino_t ino;
+ struct arglist arglist;
+ char curdir[MAXPATHLEN];
+ char name[MAXPATHLEN];
+ char cmd[BUFSIZ];
+
+ arglist.freeglob = 0;
+ arglist.argcnt = 0;
+ arglist.glob.gl_flags = GLOB_ALTDIRFUNC;
+ arglist.glob.gl_opendir = (void *)rst_opendir;
+ arglist.glob.gl_readdir = (void *)glob_readdir;
+ arglist.glob.gl_closedir = (void *)rst_closedir;
+ arglist.glob.gl_lstat = glob_stat;
+ arglist.glob.gl_stat = glob_stat;
+ canon("/", curdir);
+loop:
+ if (setjmp(reset) != 0) {
+ if (arglist.freeglob != 0) {
+ arglist.freeglob = 0;
+ arglist.argcnt = 0;
+ globfree(&arglist.glob);
+ }
+ nextarg = NULL;
+ volno = 0;
+ }
+ runshell = 1;
+ getcmd(curdir, cmd, name, &arglist);
+ switch (cmd[0]) {
+ /*
+ * Add elements to the extraction list.
+ */
+ case 'a':
+ if (strncmp(cmd, "add", strlen(cmd)) != 0)
+ goto bad;
+ ino = dirlookup(name);
+ if (ino == 0)
+ break;
+ if (mflag)
+ pathcheck(name);
+ treescan(name, ino, addfile);
+ break;
+ /*
+ * Change working directory.
+ */
+ case 'c':
+ if (strncmp(cmd, "cd", strlen(cmd)) != 0)
+ goto bad;
+ ino = dirlookup(name);
+ if (ino == 0)
+ break;
+ if (inodetype(ino) == LEAF) {
+ fprintf(stderr, "%s: not a directory\n", name);
+ break;
+ }
+ (void) strcpy(curdir, name);
+ break;
+ /*
+ * Delete elements from the extraction list.
+ */
+ case 'd':
+ if (strncmp(cmd, "delete", strlen(cmd)) != 0)
+ goto bad;
+ np = lookupname(name);
+ if (np == NULL || (np->e_flags & NEW) == 0) {
+ fprintf(stderr, "%s: not on extraction list\n", name);
+ break;
+ }
+ treescan(name, np->e_ino, deletefile);
+ break;
+ /*
+ * Extract the requested list.
+ */
+ case 'e':
+ if (strncmp(cmd, "extract", strlen(cmd)) != 0)
+ goto bad;
+ createfiles();
+ createlinks();
+ setdirmodes(0);
+ if (dflag)
+ checkrestore();
+ volno = 0;
+ break;
+ /*
+ * List available commands.
+ */
+ case 'h':
+ if (strncmp(cmd, "help", strlen(cmd)) != 0)
+ goto bad;
+ case '?':
+ fprintf(stderr, "%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s",
+ "Available commands are:\n",
+ "\tls [arg] - list directory\n",
+ "\tcd arg - change directory\n",
+ "\tpwd - print current directory\n",
+ "\tadd [arg] - add `arg' to list of",
+ " files to be extracted\n",
+ "\tdelete [arg] - delete `arg' from",
+ " list of files to be extracted\n",
+ "\textract - extract requested files\n",
+ "\tsetmodes - set modes of requested directories\n",
+ "\tquit - immediately exit program\n",
+ "\twhat - list dump header information\n",
+ "\tverbose - toggle verbose flag",
+ " (useful with ``ls'')\n",
+ "\thelp or `?' - print this list\n",
+ "If no `arg' is supplied, the current",
+ " directory is used\n");
+ break;
+ /*
+ * List a directory.
+ */
+ case 'l':
+ if (strncmp(cmd, "ls", strlen(cmd)) != 0)
+ goto bad;
+ printlist(name, curdir);
+ break;
+ /*
+ * Print current directory.
+ */
+ case 'p':
+ if (strncmp(cmd, "pwd", strlen(cmd)) != 0)
+ goto bad;
+ if (curdir[1] == '\0')
+ fprintf(stderr, "/\n");
+ else
+ fprintf(stderr, "%s\n", &curdir[1]);
+ break;
+ /*
+ * Quit.
+ */
+ case 'q':
+ if (strncmp(cmd, "quit", strlen(cmd)) != 0)
+ goto bad;
+ return;
+ case 'x':
+ if (strncmp(cmd, "xit", strlen(cmd)) != 0)
+ goto bad;
+ return;
+ /*
+ * Toggle verbose mode.
+ */
+ case 'v':
+ if (strncmp(cmd, "verbose", strlen(cmd)) != 0)
+ goto bad;
+ if (vflag) {
+ fprintf(stderr, "verbose mode off\n");
+ vflag = 0;
+ break;
+ }
+ fprintf(stderr, "verbose mode on\n");
+ vflag++;
+ break;
+ /*
+ * Just restore requested directory modes.
+ */
+ case 's':
+ if (strncmp(cmd, "setmodes", strlen(cmd)) != 0)
+ goto bad;
+ setdirmodes(FORCE);
+ break;
+ /*
+ * Print out dump header information.
+ */
+ case 'w':
+ if (strncmp(cmd, "what", strlen(cmd)) != 0)
+ goto bad;
+ printdumpinfo();
+ break;
+ /*
+ * Turn on debugging.
+ */
+ case 'D':
+ if (strncmp(cmd, "Debug", strlen(cmd)) != 0)
+ goto bad;
+ if (dflag) {
+ fprintf(stderr, "debugging mode off\n");
+ dflag = 0;
+ break;
+ }
+ fprintf(stderr, "debugging mode on\n");
+ dflag++;
+ break;
+ /*
+ * Unknown command.
+ */
+ default:
+ bad:
+ fprintf(stderr, "%s: unknown command; type ? for help\n", cmd);
+ break;
+ }
+ goto loop;
+}
+
+/*
+ * Read and parse an interactive command.
+ * The first word on the line is assigned to "cmd". If
+ * there are no arguments on the command line, then "curdir"
+ * is returned as the argument. If there are arguments
+ * on the line they are returned one at a time on each
+ * successive call to getcmd. Each argument is first assigned
+ * to "name". If it does not start with "/" the pathname in
+ * "curdir" is prepended to it. Finally "canon" is called to
+ * eliminate any embedded ".." components.
+ */
+static void
+getcmd(curdir, cmd, name, ap)
+ char *curdir, *cmd, *name;
+ struct arglist *ap;
+{
+ register char *cp;
+ static char input[BUFSIZ];
+ char output[BUFSIZ];
+# define rawname input /* save space by reusing input buffer */
+
+ /*
+ * Check to see if still processing arguments.
+ */
+ if (ap->argcnt > 0)
+ goto retnext;
+ if (nextarg != NULL)
+ goto getnext;
+ /*
+ * Read a command line and trim off trailing white space.
+ */
+ do {
+ fprintf(stderr, "restore > ");
+ (void) fflush(stderr);
+ (void) fgets(input, BUFSIZ, terminal);
+ } while (!feof(terminal) && input[0] == '\n');
+ if (feof(terminal)) {
+ (void) strcpy(cmd, "quit");
+ return;
+ }
+ for (cp = &input[strlen(input) - 2]; *cp == ' ' || *cp == '\t'; cp--)
+ /* trim off trailing white space and newline */;
+ *++cp = '\0';
+ /*
+ * Copy the command into "cmd".
+ */
+ cp = copynext(input, cmd);
+ ap->cmd = cmd;
+ /*
+ * If no argument, use curdir as the default.
+ */
+ if (*cp == '\0') {
+ (void) strcpy(name, curdir);
+ return;
+ }
+ nextarg = cp;
+ /*
+ * Find the next argument.
+ */
+getnext:
+ cp = copynext(nextarg, rawname);
+ if (*cp == '\0')
+ nextarg = NULL;
+ else
+ nextarg = cp;
+ /*
+ * If it is an absolute pathname, canonicalize it and return it.
+ */
+ if (rawname[0] == '/') {
+ canon(rawname, name);
+ } else {
+ /*
+ * For relative pathnames, prepend the current directory to
+ * it then canonicalize and return it.
+ */
+ (void) strcpy(output, curdir);
+ (void) strcat(output, "/");
+ (void) strcat(output, rawname);
+ canon(output, name);
+ }
+ if (glob(name, GLOB_ALTDIRFUNC, NULL, &ap->glob) < 0)
+ fprintf(stderr, "%s: out of memory\n", ap->cmd);
+ if (ap->glob.gl_pathc == 0)
+ return;
+ ap->freeglob = 1;
+ ap->argcnt = ap->glob.gl_pathc;
+
+retnext:
+ strcpy(name, ap->glob.gl_pathv[ap->glob.gl_pathc - ap->argcnt]);
+ if (--ap->argcnt == 0) {
+ ap->freeglob = 0;
+ globfree(&ap->glob);
+ }
+# undef rawname
+}
+
+/*
+ * Strip off the next token of the input.
+ */
+static char *
+copynext(input, output)
+ char *input, *output;
+{
+ register char *cp, *bp;
+ char quote;
+
+ for (cp = input; *cp == ' ' || *cp == '\t'; cp++)
+ /* skip to argument */;
+ bp = output;
+ while (*cp != ' ' && *cp != '\t' && *cp != '\0') {
+ /*
+ * Handle back slashes.
+ */
+ if (*cp == '\\') {
+ if (*++cp == '\0') {
+ fprintf(stderr,
+ "command lines cannot be continued\n");
+ continue;
+ }
+ *bp++ = *cp++;
+ continue;
+ }
+ /*
+ * The usual unquoted case.
+ */
+ if (*cp != '\'' && *cp != '"') {
+ *bp++ = *cp++;
+ continue;
+ }
+ /*
+ * Handle single and double quotes.
+ */
+ quote = *cp++;
+ while (*cp != quote && *cp != '\0')
+ *bp++ = *cp++ /* | 0200 */;
+ if (*cp++ == '\0') {
+ fprintf(stderr, "missing %c\n", quote);
+ cp--;
+ continue;
+ }
+ }
+ *bp = '\0';
+ return (cp);
+}
+
+/*
+ * Canonicalize file names to always start with ``./'' and
+ * remove any imbedded "." and ".." components.
+ */
+void
+canon(rawname, canonname)
+ char *rawname, *canonname;
+{
+ register char *cp, *np;
+
+ if (strcmp(rawname, ".") == 0 || strncmp(rawname, "./", 2) == 0)
+ (void) strcpy(canonname, "");
+ else if (rawname[0] == '/')
+ (void) strcpy(canonname, ".");
+ else
+ (void) strcpy(canonname, "./");
+ (void) strcat(canonname, rawname);
+ /*
+ * Eliminate multiple and trailing '/'s
+ */
+ for (cp = np = canonname; *np != '\0'; cp++) {
+ *cp = *np++;
+ while (*cp == '/' && *np == '/')
+ np++;
+ }
+ *cp = '\0';
+ if (*--cp == '/')
+ *cp = '\0';
+ /*
+ * Eliminate extraneous "." and ".." from pathnames.
+ */
+ for (np = canonname; *np != '\0'; ) {
+ np++;
+ cp = np;
+ while (*np != '/' && *np != '\0')
+ np++;
+ if (np - cp == 1 && *cp == '.') {
+ cp--;
+ (void) strcpy(cp, np);
+ np = cp;
+ }
+ if (np - cp == 2 && strncmp(cp, "..", 2) == 0) {
+ cp--;
+ while (cp > &canonname[1] && *--cp != '/')
+ /* find beginning of name */;
+ (void) strcpy(cp, np);
+ np = cp;
+ }
+ }
+}
+
+/*
+ * Do an "ls" style listing of a directory
+ */
+static void
+printlist(name, basename)
+ char *name;
+ char *basename;
+{
+ register struct afile *fp, *list, *listp;
+ register struct direct *dp;
+ struct afile single;
+ RST_DIR *dirp;
+ int entries, len, namelen;
+ char locname[MAXPATHLEN + 1];
+
+ dp = pathsearch(name);
+ if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
+ (!vflag && dp->d_ino == WINO))
+ return;
+ if ((dirp = rst_opendir(name)) == NULL) {
+ entries = 1;
+ list = &single;
+ mkentry(name, dp, list);
+ len = strlen(basename) + 1;
+ if (strlen(name) - len > single.len) {
+ freename(single.fname);
+ single.fname = savename(&name[len]);
+ single.len = strlen(single.fname);
+ }
+ } else {
+ entries = 0;
+/* while ((dp = rst_readdir(dirp)) && (dp->d_ino != 0)) */
+ while (dp = rst_readdir(dirp))
+ entries++;
+ rst_closedir(dirp);
+ list = (struct afile *)malloc(entries * sizeof(struct afile));
+ if (list == NULL) {
+ fprintf(stderr, "ls: out of memory\n");
+ return;
+ }
+ if ((dirp = rst_opendir(name)) == NULL)
+ panic("directory reopen failed\n");
+ fprintf(stderr, "%s:\n", name);
+ entries = 0;
+ listp = list;
+ (void) strncpy(locname, name, MAXPATHLEN);
+ (void) strncat(locname, "/", MAXPATHLEN);
+ namelen = strlen(locname);
+ while (dp = rst_readdir(dirp)) {
+ if (dp == NULL)
+ break;
+ if (!dflag && TSTINO(dp->d_ino, dumpmap) == 0)
+ continue;
+ if (!vflag && (dp->d_ino == WINO ||
+ strcmp(dp->d_name, ".") == 0 ||
+ strcmp(dp->d_name, "..") == 0))
+ continue;
+ locname[namelen] = '\0';
+ if (namelen + dp->d_namlen >= MAXPATHLEN) {
+ fprintf(stderr, "%s%s: name exceeds %d char\n",
+ locname, dp->d_name, MAXPATHLEN);
+ } else {
+ (void) strncat(locname, dp->d_name,
+ (int)dp->d_namlen);
+ mkentry(locname, dp, listp++);
+ entries++;
+ }
+ }
+ rst_closedir(dirp);
+ if (entries == 0) {
+ fprintf(stderr, "\n");
+ free(list);
+ return;
+ }
+ qsort((char *)list, entries, sizeof(struct afile), fcmp);
+ }
+ formatf(list, entries);
+ if (dirp != NULL) {
+ for (fp = listp - 1; fp >= list; fp--)
+ freename(fp->fname);
+ fprintf(stderr, "\n");
+ free(list);
+ }
+}
+
+/*
+ * Read the contents of a directory.
+ */
+static void
+mkentry(name, dp, fp)
+ char *name;
+ struct direct *dp;
+ register struct afile *fp;
+{
+ char *cp;
+ struct entry *np;
+
+ fp->fnum = dp->d_ino;
+ fp->fname = savename(dp->d_name);
+ for (cp = fp->fname; *cp; cp++)
+ if (!vflag && (*cp < ' ' || *cp >= 0177))
+ *cp = '?';
+ fp->len = cp - fp->fname;
+ if (dflag && TSTINO(fp->fnum, dumpmap) == 0)
+ fp->prefix = '^';
+ else if ((np = lookupname(name)) != NULL && (np->e_flags & NEW))
+ fp->prefix = '*';
+ else
+ fp->prefix = ' ';
+#if 0
+ if (inodetype(dp->d_ino) == NODE)
+ fp->postfix = '/';
+ else
+ fp->postfix = ' ';
+#else /* __linux__ */
+ switch(dp->d_type) {
+
+ default:
+ fprintf(stderr, "Warning: undefined file type %d\n",
+ dp->d_type);
+ /* fall through */
+ case DT_REG:
+ fp->postfix = ' ';
+ break;
+
+ case DT_LNK:
+ fp->postfix = '@';
+ break;
+
+ case DT_FIFO:
+ case DT_SOCK:
+ fp->postfix = '=';
+ break;
+
+ case DT_CHR:
+ case DT_BLK:
+ fp->postfix = '#';
+ break;
+
+ case DT_WHT:
+ fp->postfix = '%';
+ break;
+
+ case DT_UNKNOWN:
+ case DT_DIR:
+ if (inodetype(dp->d_ino) == NODE)
+ fp->postfix = '/';
+ else
+ fp->postfix = ' ';
+ break;
+ }
+#endif /* __linux__ */
+ return;
+}
+
+/*
+ * Print out a pretty listing of a directory
+ */
+static void
+formatf(list, nentry)
+ register struct afile *list;
+ int nentry;
+{
+ register struct afile *fp, *endlist;
+ int width, bigino, haveprefix, havepostfix;
+ int i, j, w, precision, columns, lines;
+
+ width = 0;
+ haveprefix = 0;
+ havepostfix = 0;
+ bigino = ROOTINO;
+ endlist = &list[nentry];
+ for (fp = &list[0]; fp < endlist; fp++) {
+ if (bigino < fp->fnum)
+ bigino = fp->fnum;
+ if (width < fp->len)
+ width = fp->len;
+ if (fp->prefix != ' ')
+ haveprefix = 1;
+ if (fp->postfix != ' ')
+ havepostfix = 1;
+ }
+ if (haveprefix)
+ width++;
+ if (havepostfix)
+ width++;
+ if (vflag) {
+ for (precision = 0, i = bigino; i > 0; i /= 10)
+ precision++;
+ width += precision + 1;
+ }
+ width++;
+ columns = 81 / width;
+ if (columns == 0)
+ columns = 1;
+ lines = (nentry + columns - 1) / columns;
+ for (i = 0; i < lines; i++) {
+ for (j = 0; j < columns; j++) {
+ fp = &list[j * lines + i];
+ if (vflag) {
+ fprintf(stderr, "%*d ", precision, fp->fnum);
+ fp->len += precision + 1;
+ }
+ if (haveprefix) {
+ putc(fp->prefix, stderr);
+ fp->len++;
+ }
+ fprintf(stderr, "%s", fp->fname);
+ if (havepostfix) {
+ putc(fp->postfix, stderr);
+ fp->len++;
+ }
+ if (fp + lines >= endlist) {
+ fprintf(stderr, "\n");
+ break;
+ }
+ for (w = fp->len; w < width; w++)
+ putc(' ', stderr);
+ }
+ }
+}
+
+/*
+ * Skip over directory entries that are not on the tape
+ *
+ * First have to get definition of a dirent.
+ */
+#ifdef __linux__
+struct dirent {
+ off_t d_off; /* offset of next disk dir entry */
+ unsigned long d_fileno; /* file number of entry */
+ unsigned short d_reclen; /* length of this record */
+ unsigned short d_namlen; /* length of string in d_name */
+ char d_name[255+1]; /* name (up to MAXNAMLEN + 1) */
+};
+#else /* __linux__ */
+#undef DIRBLKSIZ
+#include <dirent.h>
+#undef d_ino
+#endif /* __linux__ */
+
+struct dirent *
+glob_readdir(dirp)
+ RST_DIR *dirp;
+{
+ struct direct *dp;
+ static struct dirent adirent;
+
+ while ((dp = rst_readdir(dirp)) != NULL) {
+ if (!vflag && dp->d_ino == WINO)
+ continue;
+ if (dflag || TSTINO(dp->d_ino, dumpmap))
+ break;
+ }
+ if (dp == NULL)
+ return (NULL);
+ adirent.d_fileno = dp->d_ino;
+#ifdef __linux__
+ adirent.d_namlen = dp->d_namlen;
+#else
+ adirent.d_namlen = dp->d_namlen & 0xff;
+#endif
+ memmove(adirent.d_name, dp->d_name, dp->d_namlen + 1);
+ return (&adirent);
+}
+
+/*
+ * Return st_mode information in response to stat or lstat calls
+ */
+static int
+glob_stat(name, stp)
+ const char *name;
+ struct stat *stp;
+{
+ register struct direct *dp;
+
+ dp = pathsearch(name);
+ if (dp == NULL || (!dflag && TSTINO(dp->d_ino, dumpmap) == 0) ||
+ (!vflag && dp->d_ino == WINO))
+ return (-1);
+ if (inodetype(dp->d_ino) == NODE)
+ stp->st_mode = IFDIR;
+ else
+ stp->st_mode = IFREG;
+ return (0);
+}
+
+/*
+ * Comparison routine for qsort.
+ */
+static int
+fcmp(f1, f2)
+ register const void *f1, *f2;
+{
+ return (strcmp(((struct afile *)f1)->fname,
+ ((struct afile *)f2)->fname));
+}
+
+/*
+ * respond to interrupts
+ */
+void
+onintr(signo)
+ int signo;
+{
+ if (command == 'i' && runshell)
+ longjmp(reset, 1);
+ if (reply("restore interrupted, continue") == FAIL)
+ done(1);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/4/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#include <ufs/ufs/dinode.h>
+#include <ufs/ffs/fs.h>
+#endif /* __linux__ */
+#include <protocols/dumprestore.h>
+
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#include <getopt.h>
+#endif
+
+#include "pathnames.h"
+#include "restore.h"
+#include "extern.h"
+
+int bflag = 0, cvtflag = 0, dflag = 0, vflag = 0, yflag = 0;
+int hflag = 1, mflag = 1, Nflag = 0;
+char command = '\0';
+long dumpnum = 1;
+long volno = 0;
+long ntrec;
+char *dumpmap;
+char *usedinomap;
+ino_t maxino;
+time_t dumptime;
+time_t dumpdate;
+FILE *terminal;
+int compare_ignore_not_found;
+char *filesys = NULL;
+char *tmpdir = _PATH_TMP;
+
+#ifdef __linux__
+char *__progname;
+#endif
+
+static void obsolete __P((int *, char **[]));
+static void usage __P((void));
+
+int
+main(argc, argv)
+ int argc;
+ char *argv[];
+{
+ int ch;
+ ino_t ino;
+ char *inputdev = _PATH_DEFTAPE;
+ char *symtbl = "./restoresymtable";
+ char *p, name[MAXPATHLEN];
+
+ if (argc < 2)
+ usage();
+
+#ifdef __linux__
+ __progname = argv[0];
+#endif
+
+ obsolete(&argc, &argv);
+ while ((ch = getopt(argc, argv, "b:CcdD:f:himNRrs:tT:vxy")) != EOF)
+ switch(ch) {
+ case 'b':
+ /* Change default tape blocksize. */
+ bflag = 1;
+ ntrec = strtol(optarg, &p, 10);
+ if (*p)
+ errx(1, "illegal blocksize -- %s", optarg);
+ if (ntrec <= 0)
+ errx(1, "block size must be greater than 0");
+ break;
+ case 'c':
+ cvtflag = 1;
+ break;
+ case 'D':
+ filesys = optarg;
+ break;
+ case 'T':
+ tmpdir = optarg;
+ break;
+ case 'd':
+ dflag = 1;
+ break;
+ case 'f':
+ inputdev = optarg;
+ break;
+ case 'h':
+ hflag = 0;
+ break;
+ case 'C':
+ case 'i':
+ case 'R':
+ case 'r':
+ case 't':
+ case 'x':
+ if (command != '\0')
+ errx(1,
+ "%c and %c options are mutually exclusive",
+ ch, command);
+ command = ch;
+ break;
+ case 'm':
+ mflag = 0;
+ break;
+ case 'N':
+ Nflag = 1;
+ break;
+ case 's':
+ /* Dumpnum (skip to) for multifile dump tapes. */
+ dumpnum = strtol(optarg, &p, 10);
+ if (*p)
+ errx(1, "illegal dump number -- %s", optarg);
+ if (dumpnum <= 0)
+ errx(1, "dump number must be greater than 0");
+ break;
+ case 'v':
+ vflag = 1;
+ break;
+ case 'y':
+ yflag = 1;
+ break;
+ default:
+ usage();
+ }
+ argc -= optind;
+ argv += optind;
+
+ if (command == '\0')
+ errx(1, "none of C, i, R, r, t or x options specified");
+
+ if (signal(SIGINT, onintr) == SIG_IGN)
+ (void) signal(SIGINT, SIG_IGN);
+ if (signal(SIGTERM, onintr) == SIG_IGN)
+ (void) signal(SIGTERM, SIG_IGN);
+ setlinebuf(stderr);
+
+ setinput(inputdev);
+
+ if (argc == 0) {
+ argc = 1;
+ *--argv = ".";
+ }
+
+ switch (command) {
+ /*
+ * Compare contents of tape.
+ */
+ case 'C': {
+ struct stat stbuf;
+
+ vprintf(stdout, "Begin compare restore\n");
+ compare_ignore_not_found = 0;
+ setup();
+ printf("filesys = %s\n", filesys);
+ if (stat(filesys, &stbuf) < 0) {
+ fprintf(stderr, "cannot stat directory %s: %s\n",
+ filesys, strerror(errno));
+ exit(1);
+ } else {
+ if (chdir(filesys) < 0) {
+ fprintf(stderr, "cannot cd to %s: %s\n",
+ filesys, strerror(errno));
+ exit(1);
+ }
+ }
+ compare_ignore_not_found = dumptime > 0;
+ initsymtable((char *)0);
+ extractdirs(0);
+ treescan(".", ROOTINO, nodeupdates);
+ compareleaves();
+ checkrestore();
+ break;
+ }
+
+ /*
+ * Interactive mode.
+ */
+ case 'i':
+ setup();
+ extractdirs(1);
+ initsymtable(NULL);
+ runcmdshell();
+ break;
+ /*
+ * Incremental restoration of a file system.
+ */
+ case 'r':
+ setup();
+ if (dumptime > 0) {
+ /*
+ * This is an incremental dump tape.
+ */
+ vprintf(stdout, "Begin incremental restore\n");
+ initsymtable(symtbl);
+ extractdirs(1);
+ removeoldleaves();
+ vprintf(stdout, "Calculate node updates.\n");
+ treescan(".", ROOTINO, nodeupdates);
+ findunreflinks();
+ removeoldnodes();
+ } else {
+ /*
+ * This is a level zero dump tape.
+ */
+ vprintf(stdout, "Begin level 0 restore\n");
+ initsymtable((char *)0);
+ extractdirs(1);
+ vprintf(stdout, "Calculate extraction list.\n");
+ treescan(".", ROOTINO, nodeupdates);
+ }
+ createleaves(symtbl);
+ createlinks();
+ setdirmodes(FORCE);
+ checkrestore();
+ if (dflag) {
+ vprintf(stdout, "Verify the directory structure\n");
+ treescan(".", ROOTINO, verifyfile);
+ }
+ dumpsymtable(symtbl, (long)1);
+ break;
+ /*
+ * Resume an incremental file system restoration.
+ */
+ case 'R':
+ initsymtable(symtbl);
+ skipmaps();
+ skipdirs();
+ createleaves(symtbl);
+ createlinks();
+ setdirmodes(FORCE);
+ checkrestore();
+ dumpsymtable(symtbl, (long)1);
+ break;
+ /*
+ * List contents of tape.
+ */
+ case 't':
+ setup();
+ extractdirs(0);
+ initsymtable((char *)0);
+ while (argc--) {
+ canon(*argv++, name);
+ ino = dirlookup(name);
+ if (ino == 0)
+ continue;
+ treescan(name, ino, listfile);
+ }
+ break;
+ /*
+ * Batch extraction of tape contents.
+ */
+ case 'x':
+ setup();
+ extractdirs(1);
+ initsymtable((char *)0);
+ while (argc--) {
+ canon(*argv++, name);
+ ino = dirlookup(name);
+ if (ino == 0)
+ continue;
+ if (mflag)
+ pathcheck(name);
+ treescan(name, ino, addfile);
+ }
+ createfiles();
+ createlinks();
+ setdirmodes(0);
+ if (dflag)
+ checkrestore();
+ break;
+ }
+ done(0);
+ /* NOTREACHED */
+}
+
+static void
+usage()
+{
+ (void)fprintf(stderr, "usage:\t%s\n\t%s\n\t%s\n\t%s\n\t%s\n",
+ "restore -i [-chmvy] [-b blocksize] [-f file] [-s fileno]",
+ "restore -r [-cvy] [-b blocksize] [-f file] [-s fileno]",
+ "restore -R [-cvy] [-b blocksize] [-f file] [-s fileno]",
+ "restore -x [-chmvy] [-b blocksize] [-f file] [-s fileno] [file ...]", "restore -t [-chvy] [-b blocksize] [-f file] [-s fileno] [file ...]");
+ done(1);
+}
+
+/*
+ * obsolete --
+ * Change set of key letters and ordered arguments into something
+ * getopt(3) will like.
+ */
+static void
+obsolete(argcp, argvp)
+ int *argcp;
+ char **argvp[];
+{
+ int argc, flags;
+ char *ap, **argv, *flagsp, **nargv, *p;
+
+ /* Setup. */
+ argv = *argvp;
+ argc = *argcp;
+
+ /* Return if no arguments or first argument has leading dash. */
+ ap = argv[1];
+ if (argc == 1 || *ap == '-')
+ return;
+
+ /* Allocate space for new arguments. */
+ if ((*argvp = nargv = malloc((argc + 1) * sizeof(char *))) == NULL ||
+ (p = flagsp = malloc(strlen(ap) + 2)) == NULL)
+ err(1, NULL);
+
+ *nargv++ = *argv;
+ argv += 2;
+
+ for (flags = 0; *ap; ++ap) {
+ switch (*ap) {
+ case 'b':
+ case 'f':
+ case 's':
+ if (*argv == NULL) {
+ warnx("option requires an argument -- %c", *ap);
+ usage();
+ }
+ if ((nargv[0] = malloc(strlen(*argv) + 2 + 1)) == NULL)
+ err(1, NULL);
+ nargv[0][0] = '-';
+ nargv[0][1] = *ap;
+ (void)strcpy(&nargv[0][2], *argv);
+ ++argv;
+ ++nargv;
+ break;
+ default:
+ if (!flags) {
+ *p++ = '-';
+ flags = 1;
+ }
+ *p++ = *ap;
+ break;
+ }
+ }
+
+ /* Terminate flags. */
+ if (flags) {
+ *p = '\0';
+ *nargv++ = flagsp;
+ }
+
+ /* Copy remaining arguments. */
+ while (*nargv++ = *argv++);
+
+ /* Update argument count. */
+ *argcp = nargv - *argvp - 1;
+}
--- /dev/null
+.\" Copyright (c) 1985, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)restore.8 8.4 (Berkeley) 5/1/95
+.\"
+.Dd May 1, 1995
+.Dt RESTORE 8
+.Os BSD 4
+.Sh NAME
+.Nm restore
+.Nd "restore files or file systems from backups made with dump"
+.Sh SYNOPSIS
+.Nm restore
+.Fl C
+.Op Fl cvy
+.Op Fl b Ar blocksize
+.Op Fl D Ar filesystem
+.Op Fl f Ar file
+.Op Fl s Ar fileno
+.Op Fl T Ar directory
+.Nm restore
+.Fl i
+.Op Fl chmNvy
+.Op Fl b Ar blocksize
+.Op Fl f Ar file
+.Op Fl s Ar fileno
+.Op Fl T Ar directory
+.Nm restore
+.Fl R
+.Op Fl cNvy
+.Op Fl b Ar blocksize
+.Op Fl f Ar file
+.Op Fl s Ar fileno
+.Op Fl T Ar directory
+.Nm restore
+.Fl r
+.Op Fl cNvy
+.Op Fl b Ar blocksize
+.Op Fl f Ar file
+.Op Fl s Ar fileno
+.Op Fl T Ar directory
+.Nm restore
+.Fl t
+.Op Fl chvy
+.Op Fl b Ar blocksize
+.Op Fl f Ar file
+.Op Fl s Ar fileno
+.Op Fl T Ar directory
+.Op file ...
+.Nm restore
+.Fl x
+.Op Fl chmNvy
+.Op Fl b Ar blocksize
+.Op Fl f Ar file
+.Op Fl s Ar fileno
+.Op Fl T Ar directory
+.Op file ...
+.Pp
+.in -\\n(iSu
+(The
+.Bx 4.3
+option syntax is implemented for backward compatibility, but
+is not documented here.)
+.Sh DESCRIPTION
+The
+.Nm restore
+command performs the inverse function of
+.Xr dump 8 .
+A full backup of a file system may be restored and
+subsequent incremental backups layered on top of it.
+Single files and
+directory subtrees may be restored from full or partial
+backups.
+.Nm Restore
+works across a network;
+to do this see the
+.Fl f
+flag described below.
+Other arguments to the command are file or directory
+names specifying the files that are to be restored.
+Unless the
+.Fl h
+flag is specified (see below),
+the appearance of a directory name refers to
+the files and (recursively) subdirectories of that directory.
+.Pp
+Exactly one of the following flags is required:
+.Bl -tag -width Ds
+.It Fl C
+This mode allows comparison of files from a dump.
+.Nm Restore
+reads the backup and compares its contents with files present on the
+disk.
+It first changes its working directory to the root of the filesystem
+that was dumped and compares the tape with the files in its new
+current directory.
+.It Fl i
+This mode allows interactive restoration of files from a dump.
+After reading in the directory information from the dump,
+.Nm restore
+provides a shell like interface that allows the user to move
+around the directory tree selecting files to be extracted.
+The available commands are given below;
+for those commands that require an argument,
+the default is the current directory.
+.Bl -tag -width Fl
+.It Ic add Op Ar arg
+The current directory or specified argument is added to the list of
+files to be extracted.
+If a directory is specified, then it and all its descendents are
+added to the extraction list
+(unless the
+.Fl h
+flag is specified on the command line).
+Files that are on the extraction list are prepended with a ``*''
+when they are listed by
+.Ic ls .
+.It Ic \&cd Ar arg
+Change the current working directory to the specified argument.
+.It Ic delete Op Ar arg
+The current directory or specified argument is deleted from the list of
+files to be extracted.
+If a directory is specified, then it and all its descendents are
+deleted from the extraction list
+(unless the
+.Fl h
+flag is specified on the command line).
+The most expedient way to extract most of the files from a directory
+is to add the directory to the extraction list and then delete
+those files that are not needed.
+.It Ic extract
+All the files that are on the extraction list are extracted
+from the dump.
+.Nm Restore
+will ask which volume the user wishes to mount.
+The fastest way to extract a few files is to
+start with the last volume, and work towards the first volume.
+.It Ic help
+List a summary of the available commands.
+.It Ic \&ls Op Ar arg
+List the current or specified directory.
+Entries that are directories are appended with a ``/''.
+Entries that have been marked for extraction are prepended with a ``*''.
+If the verbose
+flag is set the inode number of each entry is also listed.
+.It Ic pwd
+Print the full pathname of the current working directory.
+.It Ic quit
+Restore immediately exits,
+even if the extraction list is not empty.
+.It Ic setmodes
+All the directories that have been added to the extraction list
+have their owner, modes, and times set;
+nothing is extracted from the dump.
+This is useful for cleaning up after a restore has been prematurely aborted.
+.It Ic verbose
+The sense of the
+.Fl v
+flag is toggled.
+When set, the verbose flag causes the
+.Ic ls
+command to list the inode numbers of all entries.
+It also causes
+.Nm restore
+to print out information about each file as it is extracted.
+.El
+.It Fl R
+.Nm Restore
+requests a particular tape of a multi volume set on which to restart
+a full restore
+(see the
+.Fl r
+flag below).
+This is useful if the restore has been interrupted.
+.It Fl r
+Restore (rebuild a file system).
+The target file system should be made pristine with
+.Xr newfs 8 ,
+mounted and the user
+.Xr cd Ns 'd
+into the pristine file system
+before starting the restoration of the initial level 0 backup. If the
+level 0 restores successfully, the
+.Fl r
+flag may be used to restore
+any necessary incremental backups on top of the level 0.
+The
+.Fl r
+flag precludes an interactive file extraction and can be
+detrimental to one's health if not used carefully (not to mention
+the disk). An example:
+.Bd -literal -offset indent
+newfs /dev/rrp0g eagle
+mount /dev/rp0g /mnt
+cd /mnt
+
+restore rf /dev/rst8
+.Ed
+.Pp
+Note that
+.Nm restore
+leaves a file
+.Pa restoresymtable
+in the root directory to pass information between incremental
+restore passes.
+This file should be removed when the last incremental has been
+restored.
+.Pp
+.Nm Restore ,
+in conjunction with
+.Xr newfs 8
+and
+.Xr dump 8 ,
+may be used to modify file system parameters
+such as size or block size.
+.It Fl t
+The names of the specified files are listed if they occur
+on the backup.
+If no file argument is given,
+then the root directory is listed,
+which results in the entire content of the
+backup being listed,
+unless the
+.Fl h
+flag has been specified.
+Note that the
+.Fl t
+flag replaces the function of the old
+.Xr dumpdir 8
+program.
+.ne 1i
+.It Fl x
+The named files are read from the given media.
+If a named file matches a directory whose contents
+are on the backup
+and the
+.Fl h
+flag is not specified,
+the directory is recursively extracted.
+The owner, modification time,
+and mode are restored (if possible).
+If no file argument is given,
+then the root directory is extracted,
+which results in the entire content of the
+backup being extracted,
+unless the
+.Fl h
+flag has been specified.
+.El
+.Pp
+The following additional options may be specified:
+.Bl -tag -width Ds
+.It Fl b Ar blocksize
+The number of kilobytes per dump record.
+If the
+.Fl b
+option is not specified,
+.Nm restore
+tries to determine the block size dynamically.
+.It Fl c
+Normally,
+.Nm restore
+will try to determine dynamically whether the dump was made from an
+old (pre-4.4) or new format file sytem. The
+.Fl c
+flag disables this check, and only allows reading a dump in the old
+format.
+.It Fl D Ar filesystem
+The
+.Fl D
+flag allows the user to specify the filesystem name when using
+.Nm restore
+with the
+.Fl C
+option to check the backup.
+.It Fl f Ar file
+Read the backup from
+.Ar file ;
+.Ar file
+may be a special device file
+like
+.Pa /dev/rmt12
+(a tape drive),
+.Pa /dev/rsd1c
+(a disk drive),
+an ordinary file,
+or
+.Ql Fl
+(the standard input).
+If the name of the file is of the form
+.Dq host:file ,
+or
+.Dq user@host:file ,
+.Nm restore
+reads from the named file on the remote host using
+.Xr rmt 8 .
+.Pp
+.It Fl h
+Extract the actual directory,
+rather than the files that it references.
+This prevents hierarchical restoration of complete subtrees
+from the dump.
+.It Fl m
+Extract by inode numbers rather than by file name.
+This is useful if only a few files are being extracted,
+and one wants to avoid regenerating the complete pathname
+to the file.
+.It Fl N
+The
+.Fl N
+flag causes
+.Nm restore to only print file names. Files are not extracted.
+.It Fl s Ar fileno
+Read from the specified
+.Ar fileno
+on a multi-file tape.
+File numbering starts at 1.
+.It Fl T Ar directory
+The
+.Fl T
+flag allows the user to specify a directory to use for the storage of
+temporary files. The default value is /tmp. This flag is most useful
+when restoring files after having booted from a floppy. There might be little
+or no space on the floppy filesystem, but another source of space might exist.
+.It Fl v
+Normally
+.Nm restore
+does its work silently.
+The
+.Fl v
+(verbose)
+flag causes it to type the name of each file it treats
+preceded by its file type.
+.It Fl y
+Do not ask the user whether to abort the restore in the event of an error.
+Always try to skip over the bad block(s) and continue.
+.El
+.Sh DIAGNOSTICS
+Complaints if it gets a read error.
+If
+.Fl y
+has been specified, or the user responds
+.Ql y ,
+.Nm restore
+will attempt to continue the restore.
+.Pp
+If a backup was made using more than one tape volume,
+.Nm restore
+will notify the user when it is time to mount the next volume.
+If the
+.Fl x
+or
+.Fl i
+flag has been specified,
+.Nm restore
+will also ask which volume the user wishes to mount.
+The fastest way to extract a few files is to
+start with the last volume, and work towards the first volume.
+.Pp
+There are numerous consistency checks that can be listed by
+.Nm restore .
+Most checks are self-explanatory or can ``never happen''.
+Common errors are given below.
+.Pp
+.Bl -tag -width Ds -compact
+.It Converting to new file system format.
+A dump tape created from the old file system has been loaded.
+It is automatically converted to the new file system format.
+.Pp
+.It <filename>: not found on tape
+The specified file name was listed in the tape directory,
+but was not found on the tape.
+This is caused by tape read errors while looking for the file,
+and from using a dump tape created on an active file system.
+.Pp
+.It expected next file <inumber>, got <inumber>
+A file that was not listed in the directory showed up.
+This can occur when using a dump created on an active file system.
+.Pp
+.It Incremental dump too low
+When doing incremental restore,
+a dump that was written before the previous incremental dump,
+or that has too low an incremental level has been loaded.
+.Pp
+.It Incremental dump too high
+When doing incremental restore,
+a dump that does not begin its coverage where the previous incremental
+dump left off,
+or that has too high an incremental level has been loaded.
+.Pp
+.It Tape read error while restoring <filename>
+.It Tape read error while skipping over inode <inumber>
+.It Tape read error while trying to resynchronize
+A tape (or other media) read error has occurred.
+If a file name is specified,
+then its contents are probably partially wrong.
+If an inode is being skipped or the tape is trying to resynchronize,
+then no extracted files have been corrupted,
+though files may not be found on the tape.
+.Pp
+.It resync restore, skipped <num> blocks
+After a dump read error,
+.Nm restore
+may have to resynchronize itself.
+This message lists the number of blocks that were skipped over.
+.El
+.Sh FILES
+.Bl -tag -width "./restoresymtable" -compact
+.It Pa /dev/rmt?
+the default tape drive
+.It Pa /tmp/rstdir*
+file containing directories on the tape.
+.It Pa /tmp/rstmode*
+owner, mode, and time stamps for directories.
+.It Pa \&./restoresymtable
+information passed between incremental restores.
+.El
+.Sh SEE ALSO
+.Xr dump 8 ,
+.Xr newfs 8 ,
+.Xr mount 8 ,
+.Xr mkfs 8 ,
+.Xr rmt 8
+.Sh BUGS
+.Nm Restore
+can get confused when doing incremental restores from
+dumps that were made on active file systems.
+.Pp
+A level zero dump must be done after a full restore.
+Because restore runs in user code,
+it has no control over inode allocation;
+thus a full dump must be done to get a new set of directories
+reflecting the new inode numbering,
+even though the contents of the files is unchanged.
+.Sh HISTORY
+The
+.Nm restore
+command appeared in
+.Bx 4.2 .
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)restore.c 8.3 (Berkeley) 9/13/94";
+#endif /* not lint */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#include <ufs/ufs/dinode.h>
+#endif /* __linux__ */
+
+#include <stdio.h>
+#include <string.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "restore.h"
+#include "extern.h"
+
+static char *keyval __P((int));
+
+/*
+ * This implements the 't' option.
+ * List entries on the tape.
+ */
+long
+listfile(name, ino, type)
+ char *name;
+ ino_t ino;
+ int type;
+{
+ long descend = hflag ? GOOD : FAIL;
+
+ if (TSTINO(ino, dumpmap) == 0)
+ return (descend);
+ vprintf(stdout, "%s", type == LEAF ? "leaf" : "dir ");
+ fprintf(stdout, "%10d\t%s\n", ino, name);
+ return (descend);
+}
+
+/*
+ * This implements the 'x' option.
+ * Request that new entries be extracted.
+ */
+long
+addfile(name, ino, type)
+ char *name;
+ ino_t ino;
+ int type;
+{
+ register struct entry *ep;
+ long descend = hflag ? GOOD : FAIL;
+ char buf[100];
+
+ if (TSTINO(ino, dumpmap) == 0) {
+ dprintf(stdout, "%s: not on the tape\n", name);
+ return (descend);
+ }
+ if (ino == WINO && command == 'i' && !vflag)
+ return (descend);
+ if (!mflag) {
+ (void) sprintf(buf, "./%u", ino);
+ name = buf;
+ if (type == NODE) {
+ (void) genliteraldir(name, ino);
+ return (descend);
+ }
+ }
+ ep = lookupino(ino);
+ if (ep != NULL) {
+ if (strcmp(name, myname(ep)) == 0) {
+ ep->e_flags |= NEW;
+ return (descend);
+ }
+ type |= LINK;
+ }
+ ep = addentry(name, ino, type);
+ if (type == NODE)
+ newnode(ep);
+ ep->e_flags |= NEW;
+ return (descend);
+}
+
+/*
+ * This is used by the 'i' option to undo previous requests made by addfile.
+ * Delete entries from the request queue.
+ */
+/* ARGSUSED */
+long
+deletefile(name, ino, type)
+ char *name;
+ ino_t ino;
+ int type;
+{
+ long descend = hflag ? GOOD : FAIL;
+ struct entry *ep;
+
+ if (TSTINO(ino, dumpmap) == 0)
+ return (descend);
+ ep = lookupname(name);
+ if (ep != NULL) {
+ ep->e_flags &= ~NEW;
+ ep->e_flags |= REMOVED;
+ if (ep->e_type != NODE)
+ freeentry(ep);
+ }
+ return (descend);
+}
+
+/*
+ * The following four routines implement the incremental
+ * restore algorithm. The first removes old entries, the second
+ * does renames and calculates the extraction list, the third
+ * cleans up link names missed by the first two, and the final
+ * one deletes old directories.
+ *
+ * Directories cannot be immediately deleted, as they may have
+ * other files in them which need to be moved out first. As
+ * directories to be deleted are found, they are put on the
+ * following deletion list. After all deletions and renames
+ * are done, this list is actually deleted.
+ */
+static struct entry *removelist;
+
+/*
+ * Remove invalid whiteouts from the old tree.
+ * Remove unneeded leaves from the old tree.
+ * Remove directories from the lookup chains.
+ */
+void
+removeoldleaves()
+{
+ register struct entry *ep, *nextep;
+ register ino_t i, mydirino;
+
+ vprintf(stdout, "Mark entries to be removed.\n");
+ if (ep = lookupino(WINO)) {
+ vprintf(stdout, "Delete whiteouts\n");
+ for ( ; ep != NULL; ep = nextep) {
+ nextep = ep->e_links;
+ mydirino = ep->e_parent->e_ino;
+ /*
+ * We remove all whiteouts that are in directories
+ * that have been removed or that have been dumped.
+ */
+ if (TSTINO(mydirino, usedinomap) &&
+ !TSTINO(mydirino, dumpmap))
+ continue;
+#ifdef __linux__
+ (void)fprintf(stderr, "BUG! Should call delwhiteout\n");
+#else
+ delwhiteout(ep);
+#endif
+ freeentry(ep);
+ }
+ }
+ for (i = ROOTINO + 1; i < maxino; i++) {
+ ep = lookupino(i);
+ if (ep == NULL)
+ continue;
+ if (TSTINO(i, usedinomap))
+ continue;
+ for ( ; ep != NULL; ep = ep->e_links) {
+ dprintf(stdout, "%s: REMOVE\n", myname(ep));
+ if (ep->e_type == LEAF) {
+ removeleaf(ep);
+ freeentry(ep);
+ } else {
+ mktempname(ep);
+ deleteino(ep->e_ino);
+ ep->e_next = removelist;
+ removelist = ep;
+ }
+ }
+ }
+}
+
+/*
+ * For each directory entry on the incremental tape, determine which
+ * category it falls into as follows:
+ * KEEP - entries that are to be left alone.
+ * NEW - new entries to be added.
+ * EXTRACT - files that must be updated with new contents.
+ * LINK - new links to be added.
+ * Renames are done at the same time.
+ */
+long
+nodeupdates(name, ino, type)
+ char *name;
+ ino_t ino;
+ int type;
+{
+ register struct entry *ep, *np, *ip;
+ long descend = GOOD;
+ int lookuptype = 0;
+ int key = 0;
+ /* key values */
+# define ONTAPE 0x1 /* inode is on the tape */
+# define INOFND 0x2 /* inode already exists */
+# define NAMEFND 0x4 /* name already exists */
+# define MODECHG 0x8 /* mode of inode changed */
+
+ /*
+ * This routine is called once for each element in the
+ * directory hierarchy, with a full path name.
+ * The "type" value is incorrectly specified as LEAF for
+ * directories that are not on the dump tape.
+ *
+ * Check to see if the file is on the tape.
+ */
+ if (TSTINO(ino, dumpmap))
+ key |= ONTAPE;
+ /*
+ * Check to see if the name exists, and if the name is a link.
+ */
+ np = lookupname(name);
+ if (np != NULL) {
+ key |= NAMEFND;
+ ip = lookupino(np->e_ino);
+ if (ip == NULL)
+ panic("corrupted symbol table\n");
+ if (ip != np)
+ lookuptype = LINK;
+ }
+ /*
+ * Check to see if the inode exists, and if one of its links
+ * corresponds to the name (if one was found).
+ */
+ ip = lookupino(ino);
+ if (ip != NULL) {
+ key |= INOFND;
+ for (ep = ip->e_links; ep != NULL; ep = ep->e_links) {
+ if (ep == np) {
+ ip = ep;
+ break;
+ }
+ }
+ }
+ /*
+ * If both a name and an inode are found, but they do not
+ * correspond to the same file, then both the inode that has
+ * been found and the inode corresponding to the name that
+ * has been found need to be renamed. The current pathname
+ * is the new name for the inode that has been found. Since
+ * all files to be deleted have already been removed, the
+ * named file is either a now unneeded link, or it must live
+ * under a new name in this dump level. If it is a link, it
+ * can be removed. If it is not a link, it is given a
+ * temporary name in anticipation that it will be renamed
+ * when it is later found by inode number.
+ */
+ if (((key & (INOFND|NAMEFND)) == (INOFND|NAMEFND)) && ip != np) {
+ if (lookuptype == LINK) {
+ removeleaf(np);
+ freeentry(np);
+ } else {
+ dprintf(stdout, "name/inode conflict, mktempname %s\n",
+ myname(np));
+ mktempname(np);
+ }
+ np = NULL;
+ key &= ~NAMEFND;
+ }
+ if ((key & ONTAPE) &&
+ (((key & INOFND) && ip->e_type != type) ||
+ ((key & NAMEFND) && np->e_type != type)))
+ key |= MODECHG;
+
+ /*
+ * Decide on the disposition of the file based on its flags.
+ * Note that we have already handled the case in which
+ * a name and inode are found that correspond to different files.
+ * Thus if both NAMEFND and INOFND are set then ip == np.
+ */
+ switch (key) {
+
+ /*
+ * A previously existing file has been found.
+ * Mark it as KEEP so that other links to the inode can be
+ * detected, and so that it will not be reclaimed by the search
+ * for unreferenced names.
+ */
+ case INOFND|NAMEFND:
+ ip->e_flags |= KEEP;
+ dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+ flagvalues(ip));
+ break;
+
+ /*
+ * A file on the tape has a name which is the same as a name
+ * corresponding to a different file in the previous dump.
+ * Since all files to be deleted have already been removed,
+ * this file is either a now unneeded link, or it must live
+ * under a new name in this dump level. If it is a link, it
+ * can simply be removed. If it is not a link, it is given a
+ * temporary name in anticipation that it will be renamed
+ * when it is later found by inode number (see INOFND case
+ * below). The entry is then treated as a new file.
+ */
+ case ONTAPE|NAMEFND:
+ case ONTAPE|NAMEFND|MODECHG:
+ if (lookuptype == LINK) {
+ removeleaf(np);
+ freeentry(np);
+ } else {
+ mktempname(np);
+ }
+ /* fall through */
+
+ /*
+ * A previously non-existent file.
+ * Add it to the file system, and request its extraction.
+ * If it is a directory, create it immediately.
+ * (Since the name is unused there can be no conflict)
+ */
+ case ONTAPE:
+ ep = addentry(name, ino, type);
+ if (type == NODE)
+ newnode(ep);
+ ep->e_flags |= NEW|KEEP;
+ dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+ flagvalues(ep));
+ break;
+
+ /*
+ * A file with the same inode number, but a different
+ * name has been found. If the other name has not already
+ * been found (indicated by the KEEP flag, see above) then
+ * this must be a new name for the file, and it is renamed.
+ * If the other name has been found then this must be a
+ * link to the file. Hard links to directories are not
+ * permitted, and are either deleted or converted to
+ * symbolic links. Finally, if the file is on the tape,
+ * a request is made to extract it.
+ */
+ case ONTAPE|INOFND:
+ if (type == LEAF && (ip->e_flags & KEEP) == 0)
+ ip->e_flags |= EXTRACT;
+ /* fall through */
+ case INOFND:
+ if ((ip->e_flags & KEEP) == 0) {
+ renameit(myname(ip), name);
+ moveentry(ip, name);
+ ip->e_flags |= KEEP;
+ dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+ flagvalues(ip));
+ break;
+ }
+ if (ip->e_type == NODE) {
+ descend = FAIL;
+ fprintf(stderr,
+ "deleted hard link %s to directory %s\n",
+ name, myname(ip));
+ break;
+ }
+ ep = addentry(name, ino, type|LINK);
+ ep->e_flags |= NEW;
+ dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
+ flagvalues(ep));
+ break;
+
+ /*
+ * A previously known file which is to be updated. If it is a link,
+ * then all names referring to the previous file must be removed
+ * so that the subset of them that remain can be recreated.
+ */
+ case ONTAPE|INOFND|NAMEFND:
+ if (lookuptype == LINK) {
+ removeleaf(np);
+ freeentry(np);
+ ep = addentry(name, ino, type|LINK);
+ if (type == NODE)
+ newnode(ep);
+ ep->e_flags |= NEW|KEEP;
+ dprintf(stdout, "[%s] %s: %s|LINK\n", keyval(key), name,
+ flagvalues(ep));
+ break;
+ }
+ if (type == LEAF && lookuptype != LINK)
+ np->e_flags |= EXTRACT;
+ np->e_flags |= KEEP;
+ dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+ flagvalues(np));
+ break;
+
+ /*
+ * An inode is being reused in a completely different way.
+ * Normally an extract can simply do an "unlink" followed
+ * by a "creat". Here we must do effectively the same
+ * thing. The complications arise because we cannot really
+ * delete a directory since it may still contain files
+ * that we need to rename, so we delete it from the symbol
+ * table, and put it on the list to be deleted eventually.
+ * Conversely if a directory is to be created, it must be
+ * done immediately, rather than waiting until the
+ * extraction phase.
+ */
+ case ONTAPE|INOFND|MODECHG:
+ case ONTAPE|INOFND|NAMEFND|MODECHG:
+ if (ip->e_flags & KEEP) {
+ badentry(ip, "cannot KEEP and change modes");
+ break;
+ }
+ if (ip->e_type == LEAF) {
+ /* changing from leaf to node */
+ removeleaf(ip);
+ freeentry(ip);
+ ip = addentry(name, ino, type);
+ newnode(ip);
+ } else {
+ /* changing from node to leaf */
+ if ((ip->e_flags & TMPNAME) == 0)
+ mktempname(ip);
+ deleteino(ip->e_ino);
+ ip->e_next = removelist;
+ removelist = ip;
+ ip = addentry(name, ino, type);
+ }
+ ip->e_flags |= NEW|KEEP;
+ dprintf(stdout, "[%s] %s: %s\n", keyval(key), name,
+ flagvalues(ip));
+ break;
+
+ /*
+ * A hard link to a diirectory that has been removed.
+ * Ignore it.
+ */
+ case NAMEFND:
+ dprintf(stdout, "[%s] %s: Extraneous name\n", keyval(key),
+ name);
+ descend = FAIL;
+ break;
+
+ /*
+ * If we find a directory entry for a file that is not on
+ * the tape, then we must have found a file that was created
+ * while the dump was in progress. Since we have no contents
+ * for it, we discard the name knowing that it will be on the
+ * next incremental tape.
+ */
+ case NULL:
+ if (compare_ignore_not_found) break;
+ fprintf(stderr, "%s: (inode %d) not found on tape\n",
+ name, ino);
+ break;
+
+ /*
+ * If any of these arise, something is grievously wrong with
+ * the current state of the symbol table.
+ */
+ case INOFND|NAMEFND|MODECHG:
+ case NAMEFND|MODECHG:
+ case INOFND|MODECHG:
+ fprintf(stderr, "[%s] %s: inconsistent state\n", keyval(key),
+ name);
+ break;
+
+ /*
+ * These states "cannot" arise for any state of the symbol table.
+ */
+ case ONTAPE|MODECHG:
+ case MODECHG:
+ default:
+ panic("[%s] %s: impossible state\n", keyval(key), name);
+ break;
+ }
+ return (descend);
+}
+
+/*
+ * Calculate the active flags in a key.
+ */
+static char *
+keyval(key)
+ int key;
+{
+ static char keybuf[32];
+
+ (void) strcpy(keybuf, "|NIL");
+ keybuf[0] = '\0';
+ if (key & ONTAPE)
+ (void) strcat(keybuf, "|ONTAPE");
+ if (key & INOFND)
+ (void) strcat(keybuf, "|INOFND");
+ if (key & NAMEFND)
+ (void) strcat(keybuf, "|NAMEFND");
+ if (key & MODECHG)
+ (void) strcat(keybuf, "|MODECHG");
+ return (&keybuf[1]);
+}
+
+/*
+ * Find unreferenced link names.
+ */
+void
+findunreflinks()
+{
+ register struct entry *ep, *np;
+ register ino_t i;
+
+ vprintf(stdout, "Find unreferenced names.\n");
+ for (i = ROOTINO; i < maxino; i++) {
+ ep = lookupino(i);
+ if (ep == NULL || ep->e_type == LEAF || TSTINO(i, dumpmap) == 0)
+ continue;
+ for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
+ if (np->e_flags == 0) {
+ dprintf(stdout,
+ "%s: remove unreferenced name\n",
+ myname(np));
+ removeleaf(np);
+ freeentry(np);
+ }
+ }
+ }
+ /*
+ * Any leaves remaining in removed directories is unreferenced.
+ */
+ for (ep = removelist; ep != NULL; ep = ep->e_next) {
+ for (np = ep->e_entries; np != NULL; np = np->e_sibling) {
+ if (np->e_type == LEAF) {
+ if (np->e_flags != 0)
+ badentry(np, "unreferenced with flags");
+ dprintf(stdout,
+ "%s: remove unreferenced name\n",
+ myname(np));
+ removeleaf(np);
+ freeentry(np);
+ }
+ }
+ }
+}
+
+/*
+ * Remove old nodes (directories).
+ * Note that this routine runs in O(N*D) where:
+ * N is the number of directory entries to be removed.
+ * D is the maximum depth of the tree.
+ * If N == D this can be quite slow. If the list were
+ * topologically sorted, the deletion could be done in
+ * time O(N).
+ */
+void
+removeoldnodes()
+{
+ register struct entry *ep, **prev;
+ long change;
+
+ vprintf(stdout, "Remove old nodes (directories).\n");
+ do {
+ change = 0;
+ prev = &removelist;
+ for (ep = removelist; ep != NULL; ep = *prev) {
+ if (ep->e_entries != NULL) {
+ prev = &ep->e_next;
+ continue;
+ }
+ *prev = ep->e_next;
+ removenode(ep);
+ freeentry(ep);
+ change++;
+ }
+ } while (change);
+ for (ep = removelist; ep != NULL; ep = ep->e_next)
+ badentry(ep, "cannot remove, non-empty");
+}
+
+/* Compare the file specified in `ep' (which is on tape) to the */
+/* current copy of this file on disk. If do_compare is 0, then just */
+/* make our caller think we did it--this is used to handle hard links */
+/* to files and devices. */
+compare_entry(struct entry *ep, int do_compare)
+{
+ if ((ep->e_flags & (NEW|EXTRACT)) == 0)
+ badentry(ep, "unexpected file on tape");
+ if (do_compare) (void) comparefile(myname(ep));
+ ep->e_flags &= ~(NEW|EXTRACT);
+}
+
+/*
+ * This is the routine used to compare files for the 'C' command.
+ */
+void
+compareleaves()
+{
+ register struct entry *ep;
+ ino_t first;
+ long curvol;
+
+ first = lowerbnd(ROOTINO);
+ curvol = volno;
+ while (curfile.ino < maxino) {
+ first = lowerbnd(first);
+ /*
+ * If the next available file is not the one which we
+ * expect then we have missed one or more files. Since
+ * we do not request files that were not on the tape,
+ * the lost files must have been due to a tape read error,
+ * or a file that was removed while the dump was in progress.
+ */
+ while (first < curfile.ino) {
+ ep = lookupino(first);
+ if (ep == NULL)
+ panic("%d: bad first\n", first);
+ fprintf(stderr, "%s: not found on tape\n", myname(ep));
+ ep->e_flags &= ~(NEW|EXTRACT);
+ first = lowerbnd(first);
+ }
+ /*
+ * If we find files on the tape that have no corresponding
+ * directory entries, then we must have found a file that
+ * was created while the dump was in progress. Since we have
+ * no name for it, we discard it knowing that it will be
+ * on the next incremental tape.
+ */
+ if (first != curfile.ino) {
+ fprintf(stderr, "expected next file %d, got %d\n",
+ first, curfile.ino);
+ skipfile();
+ goto next;
+ }
+ ep = lookupino(curfile.ino);
+ if (ep == NULL)
+ panic("unknown file on tape\n");
+ compare_entry(ep, 1);
+ for (ep = ep->e_links; ep != NULL; ep = ep->e_links) {
+ compare_entry(ep, 0);
+ }
+
+ /*
+ * We checkpoint the restore after every tape reel, so
+ * as to simplify the amount of work re quired by the
+ * 'R' command.
+ */
+ next:
+ if (curvol != volno) {
+ skipmaps();
+ curvol = volno;
+ }
+ }
+}
+
+/*
+ * This is the routine used to extract files for the 'r' command.
+ * Extract new leaves.
+ */
+void
+createleaves(symtabfile)
+ char *symtabfile;
+{
+ register struct entry *ep;
+ ino_t first;
+ long curvol;
+
+ if (command == 'R') {
+ vprintf(stdout, "Continue extraction of new leaves\n");
+ } else {
+ vprintf(stdout, "Extract new leaves.\n");
+ dumpsymtable(symtabfile, volno);
+ }
+ first = lowerbnd(ROOTINO);
+ curvol = volno;
+ while (curfile.ino < maxino) {
+ first = lowerbnd(first);
+ /*
+ * If the next available file is not the one which we
+ * expect then we have missed one or more files. Since
+ * we do not request files that were not on the tape,
+ * the lost files must have been due to a tape read error,
+ * or a file that was removed while the dump was in progress.
+ */
+ while (first < curfile.ino) {
+ ep = lookupino(first);
+ if (ep == NULL)
+ panic("%d: bad first\n", first);
+ fprintf(stderr, "%s: not found on tape\n", myname(ep));
+ ep->e_flags &= ~(NEW|EXTRACT);
+ first = lowerbnd(first);
+ }
+ /*
+ * If we find files on the tape that have no corresponding
+ * directory entries, then we must have found a file that
+ * was created while the dump was in progress. Since we have
+ * no name for it, we discard it knowing that it will be
+ * on the next incremental tape.
+ */
+ if (first != curfile.ino) {
+ fprintf(stderr, "expected next file %d, got %d\n",
+ first, curfile.ino);
+ skipfile();
+ goto next;
+ }
+ ep = lookupino(curfile.ino);
+ if (ep == NULL)
+ panic("unknown file on tape\n");
+ if ((ep->e_flags & (NEW|EXTRACT)) == 0)
+ badentry(ep, "unexpected file on tape");
+ /*
+ * If the file is to be extracted, then the old file must
+ * be removed since its type may change from one leaf type
+ * to another (eg "file" to "character special").
+ */
+ if ((ep->e_flags & EXTRACT) != 0) {
+ removeleaf(ep);
+ ep->e_flags &= ~REMOVED;
+ }
+ (void) extractfile(myname(ep));
+ ep->e_flags &= ~(NEW|EXTRACT);
+ /*
+ * We checkpoint the restore after every tape reel, so
+ * as to simplify the amount of work re quired by the
+ * 'R' command.
+ */
+ next:
+ if (curvol != volno) {
+ dumpsymtable(symtabfile, volno);
+ skipmaps();
+ curvol = volno;
+ }
+ }
+}
+
+/*
+ * This is the routine used to extract files for the 'x' and 'i' commands.
+ * Efficiently extract a subset of the files on a tape.
+ */
+void
+createfiles()
+{
+ register ino_t first, next, last;
+ register struct entry *ep;
+ long curvol;
+
+ vprintf(stdout, "Extract requested files\n");
+ curfile.action = SKIP;
+ getvol((long)1);
+ skipmaps();
+ skipdirs();
+ first = lowerbnd(ROOTINO);
+ last = upperbnd(maxino - 1);
+ for (;;) {
+ first = lowerbnd(first);
+ last = upperbnd(last);
+ /*
+ * Check to see if any files remain to be extracted
+ */
+ if (first > last)
+ return;
+ /*
+ * Reject any volumes with inodes greater
+ * than the last one needed
+ */
+ while (curfile.ino > last) {
+ curfile.action = SKIP;
+ getvol((long)0);
+ skipmaps();
+ skipdirs();
+ }
+ /*
+ * Decide on the next inode needed.
+ * Skip across the inodes until it is found
+ * or an out of order volume change is encountered
+ */
+ next = lowerbnd(curfile.ino);
+ do {
+ curvol = volno;
+ while (next > curfile.ino && volno == curvol)
+ skipfile();
+ skipmaps();
+ skipdirs();
+ } while (volno == curvol + 1);
+ /*
+ * If volume change out of order occurred the
+ * current state must be recalculated
+ */
+ if (volno != curvol)
+ continue;
+ /*
+ * If the current inode is greater than the one we were
+ * looking for then we missed the one we were looking for.
+ * Since we only attempt to extract files listed in the
+ * dump map, the lost files must have been due to a tape
+ * read error, or a file that was removed while the dump
+ * was in progress. Thus we report all requested files
+ * between the one we were looking for, and the one we
+ * found as missing, and delete their request flags.
+ */
+ while (next < curfile.ino) {
+ ep = lookupino(next);
+ if (ep == NULL)
+ panic("corrupted symbol table\n");
+ fprintf(stderr, "%s: not found on tape\n", myname(ep));
+ ep->e_flags &= ~NEW;
+ next = lowerbnd(next);
+ }
+ /*
+ * The current inode is the one that we are looking for,
+ * so extract it per its requested name.
+ */
+ if (next == curfile.ino && next <= last) {
+ ep = lookupino(next);
+ if (ep == NULL)
+ panic("corrupted symbol table\n");
+ (void) extractfile(myname(ep));
+ ep->e_flags &= ~NEW;
+ if (volno != curvol)
+ skipmaps();
+ }
+ }
+}
+
+/*
+ * Add links.
+ */
+void
+createlinks()
+{
+ register struct entry *np, *ep;
+ register ino_t i;
+ char name[BUFSIZ];
+
+ if (ep = lookupino(WINO)) {
+ vprintf(stdout, "Add whiteouts\n");
+ for ( ; ep != NULL; ep = ep->e_links) {
+ if ((ep->e_flags & NEW) == 0)
+ continue;
+#ifdef __linux__
+ (void)fprintf(stderr, "BUG! Should call addwhiteout\n");
+#else
+ (void) addwhiteout(myname(ep));
+#endif
+ ep->e_flags &= ~NEW;
+ }
+ }
+ vprintf(stdout, "Add links\n");
+ for (i = ROOTINO; i < maxino; i++) {
+ ep = lookupino(i);
+ if (ep == NULL)
+ continue;
+ for (np = ep->e_links; np != NULL; np = np->e_links) {
+ if ((np->e_flags & NEW) == 0)
+ continue;
+ (void) strcpy(name, myname(ep));
+ if (ep->e_type == NODE) {
+ (void) linkit(name, myname(np), SYMLINK);
+ } else {
+ (void) linkit(name, myname(np), HARDLINK);
+ }
+ np->e_flags &= ~NEW;
+ }
+ }
+}
+
+/*
+ * Check the symbol table.
+ * We do this to insure that all the requested work was done, and
+ * that no temporary names remain.
+ */
+void
+checkrestore()
+{
+ register struct entry *ep;
+ register ino_t i;
+
+ vprintf(stdout, "Check the symbol table.\n");
+ for (i = WINO; i < maxino; i++) {
+ for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
+ ep->e_flags &= ~KEEP;
+ if (ep->e_type == NODE)
+ ep->e_flags &= ~(NEW|EXISTED);
+ if (ep->e_flags /* != NULL */)
+ badentry(ep, "incomplete operations");
+ }
+ }
+}
+
+/*
+ * Compare with the directory structure on the tape
+ * A paranoid check that things are as they should be.
+ */
+long
+verifyfile(name, ino, type)
+ char *name;
+ ino_t ino;
+ int type;
+{
+ struct entry *np, *ep;
+ long descend = GOOD;
+
+ ep = lookupname(name);
+ if (ep == NULL) {
+ fprintf(stderr, "Warning: missing name %s\n", name);
+ return (FAIL);
+ }
+ np = lookupino(ino);
+ if (np != ep)
+ descend = FAIL;
+ for ( ; np != NULL; np = np->e_links)
+ if (np == ep)
+ break;
+ if (np == NULL)
+ panic("missing inumber %d\n", ino);
+ if (ep->e_type == LEAF && type != LEAF)
+ badentry(ep, "type should be LEAF");
+ return (descend);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * @(#)restore.h 8.3 (Berkeley) 9/13/94
+ */
+
+/*
+ * Flags
+ */
+extern int cvtflag; /* convert from old to new tape format */
+extern int bflag; /* set input block size */
+extern int dflag; /* print out debugging info */
+extern int hflag; /* restore heirarchies */
+extern int mflag; /* restore by name instead of inode number */
+extern int Nflag; /* do not write the disk */
+extern int vflag; /* print out actions taken */
+extern int yflag; /* always try to recover from tape errors */
+/*
+ * Global variables
+ */
+extern char *dumpmap; /* map of inodes on this dump tape */
+extern char *usedinomap; /* map of inodes to be deleted */
+extern ino_t maxino; /* highest numbered inode in this file system */
+extern long dumpnum; /* location of the dump on this tape */
+extern long volno; /* current volume being read */
+extern long ntrec; /* number of TP_BSIZE records per tape block */
+extern time_t dumptime; /* time that this dump begins */
+extern time_t dumpdate; /* time that this dump was made */
+extern char command; /* opration being performed */
+extern FILE *terminal; /* file descriptor for the terminal input */
+extern int oldinofmt; /* reading tape with old format inodes */
+extern int Bcvt; /* need byte swapping on inodes and dirs */
+extern int compare_ignore_not_found;
+ /* used to compare incremental dumps, */
+ /* so messages about "not found" files */
+ /* isn't seen. */
+extern char *filesys; /* name of dumped filesystem */
+extern char *tmpdir; /* name of temp directory */
+
+/*
+ * Each file in the file system is described by one of these entries
+ */
+struct entry {
+ char *e_name; /* the current name of this entry */
+ u_char e_namlen; /* length of this name */
+ char e_type; /* type of this entry, see below */
+ short e_flags; /* status flags, see below */
+ ino_t e_ino; /* inode number in previous file sys */
+ long e_index; /* unique index (for dumpped table) */
+ struct entry *e_parent; /* pointer to parent directory (..) */
+ struct entry *e_sibling; /* next element in this directory (.) */
+ struct entry *e_links; /* hard links to this inode */
+ struct entry *e_entries; /* for directories, their entries */
+ struct entry *e_next; /* hash chain list */
+};
+/* types */
+#define LEAF 1 /* non-directory entry */
+#define NODE 2 /* directory entry */
+#define LINK 4 /* synthesized type, stripped by addentry */
+/* flags */
+#define EXTRACT 0x0001 /* entry is to be replaced from the tape */
+#define NEW 0x0002 /* a new entry to be extracted */
+#define KEEP 0x0004 /* entry is not to change */
+#define REMOVED 0x0010 /* entry has been removed */
+#define TMPNAME 0x0020 /* entry has been given a temporary name */
+#define EXISTED 0x0040 /* directory already existed during extract */
+
+/*
+ * Constants associated with entry structs
+ */
+#define HARDLINK 1
+#define SYMLINK 2
+#define TMPHDR "RSTTMP"
+
+/*
+ * The entry describes the next file available on the tape
+ */
+struct context {
+ char *name; /* name of file */
+ ino_t ino; /* inumber of file */
+#ifdef __linux__
+ struct new_bsd_inode *dip; /* pointer to inode */
+#else
+ struct dinode *dip; /* pointer to inode */
+#endif
+ char action; /* action being taken on this file */
+} curfile;
+/* actions */
+#define USING 1 /* extracting from the tape */
+#define SKIP 2 /* skipping */
+#define UNKNOWN 3 /* disposition or starting point is unknown */
+
+/*
+ * Definitions for library routines operating on directories.
+ */
+typedef struct rstdirdesc RST_DIR;
+
+/*
+ * Flags to setdirmodes.
+ */
+#define FORCE 0x0001
+
+/*
+ * Useful macros
+ */
+#define TSTINO(ino, map) \
+ (map[(u_int)((ino) - 1) / NBBY] & (1 << ((u_int)((ino) - 1) % NBBY)))
+#define SETINO(ino, map) \
+ map[(u_int)((ino) - 1) / NBBY] |= 1 << ((u_int)((ino) - 1) % NBBY)
+
+#define dprintf if (dflag) fprintf
+#define vprintf if (vflag) fprintf
+
+#define GOOD 1
+#define FAIL 0
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)symtab.c 8.3 (Berkeley) 4/28/95";
+#endif /* not lint */
+
+/*
+ * These routines maintain the symbol table which tracks the state
+ * of the file system being restored. They provide lookup by either
+ * name or inode number. They also provide for creation, deletion,
+ * and renaming of entries. Because of the dynamic nature of pathnames,
+ * names should not be saved, but always constructed just before they
+ * are needed, by calling "myname".
+ */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#include <ufs/ufs/dinode.h>
+#endif /* __linux__ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "restore.h"
+#include "extern.h"
+
+/*
+ * The following variables define the inode symbol table.
+ * The primary hash table is dynamically allocated based on
+ * the number of inodes in the file system (maxino), scaled by
+ * HASHFACTOR. The variable "entry" points to the hash table;
+ * the variable "entrytblsize" indicates its size (in entries).
+ */
+#define HASHFACTOR 5
+static struct entry **entry;
+static long entrytblsize;
+
+static void addino __P((ino_t, struct entry *));
+static struct entry *lookupparent __P((char *));
+static void removeentry __P((struct entry *));
+
+/*
+ * Look up an entry by inode number
+ */
+struct entry *
+lookupino(inum)
+ ino_t inum;
+{
+ register struct entry *ep;
+
+ if (inum < WINO || inum >= maxino)
+ return (NULL);
+ for (ep = entry[inum % entrytblsize]; ep != NULL; ep = ep->e_next)
+ if (ep->e_ino == inum)
+ return (ep);
+ return (NULL);
+}
+
+/*
+ * Add an entry into the entry table
+ */
+static void
+addino(inum, np)
+ ino_t inum;
+ struct entry *np;
+{
+ struct entry **epp;
+
+ if (inum < WINO || inum >= maxino)
+ panic("addino: out of range %d\n", inum);
+ epp = &entry[inum % entrytblsize];
+ np->e_ino = inum;
+ np->e_next = *epp;
+ *epp = np;
+ if (dflag)
+ for (np = np->e_next; np != NULL; np = np->e_next)
+ if (np->e_ino == inum)
+ badentry(np, "duplicate inum");
+}
+
+/*
+ * Delete an entry from the entry table
+ */
+void
+deleteino(inum)
+ ino_t inum;
+{
+ register struct entry *next;
+ struct entry **prev;
+
+ if (inum < WINO || inum >= maxino)
+ panic("deleteino: out of range %d\n", inum);
+ prev = &entry[inum % entrytblsize];
+ for (next = *prev; next != NULL; next = next->e_next) {
+ if (next->e_ino == inum) {
+ next->e_ino = 0;
+ *prev = next->e_next;
+ return;
+ }
+ prev = &next->e_next;
+ }
+ panic("deleteino: %d not found\n", inum);
+}
+
+/*
+ * Look up an entry by name
+ */
+struct entry *
+lookupname(name)
+ char *name;
+{
+ register struct entry *ep;
+ register char *np, *cp;
+ char buf[MAXPATHLEN];
+
+ cp = name;
+ for (ep = lookupino(ROOTINO); ep != NULL; ep = ep->e_entries) {
+ for (np = buf; *cp != '/' && *cp != '\0'; )
+ *np++ = *cp++;
+ *np = '\0';
+ for ( ; ep != NULL; ep = ep->e_sibling)
+ if (strcmp(ep->e_name, buf) == 0)
+ break;
+ if (ep == NULL)
+ break;
+ if (*cp++ == '\0')
+ return (ep);
+ }
+ return (NULL);
+}
+
+/*
+ * Look up the parent of a pathname
+ */
+static struct entry *
+lookupparent(name)
+ char *name;
+{
+ struct entry *ep;
+ char *tailindex;
+
+ tailindex = strrchr(name, '/');
+ if (tailindex == NULL)
+ return (NULL);
+ *tailindex = '\0';
+ ep = lookupname(name);
+ *tailindex = '/';
+ if (ep == NULL)
+ return (NULL);
+ if (ep->e_type != NODE)
+ panic("%s is not a directory\n", name);
+ return (ep);
+}
+
+/*
+ * Determine the current pathname of a node or leaf
+ */
+char *
+myname(ep)
+ register struct entry *ep;
+{
+ register char *cp;
+ static char namebuf[MAXPATHLEN];
+
+ for (cp = &namebuf[MAXPATHLEN - 2]; cp > &namebuf[ep->e_namlen]; ) {
+ cp -= ep->e_namlen;
+ memmove(cp, ep->e_name, (long)ep->e_namlen);
+ if (ep == lookupino(ROOTINO))
+ return (cp);
+ *(--cp) = '/';
+ ep = ep->e_parent;
+ }
+ panic("%s: pathname too long\n", cp);
+ return(cp);
+}
+
+/*
+ * Unused symbol table entries are linked together on a freelist
+ * headed by the following pointer.
+ */
+static struct entry *freelist = NULL;
+
+/*
+ * add an entry to the symbol table
+ */
+struct entry *
+addentry(name, inum, type)
+ char *name;
+ ino_t inum;
+ int type;
+{
+ register struct entry *np, *ep;
+
+ if (freelist != NULL) {
+ np = freelist;
+ freelist = np->e_next;
+ memset(np, 0, (long)sizeof(struct entry));
+ } else {
+ np = (struct entry *)calloc(1, sizeof(struct entry));
+ if (np == NULL)
+ panic("no memory to extend symbol table\n");
+ }
+ np->e_type = type & ~LINK;
+ ep = lookupparent(name);
+ if (ep == NULL) {
+ if (inum != ROOTINO || lookupino(ROOTINO) != NULL)
+ panic("bad name to addentry %s\n", name);
+ np->e_name = savename(name);
+ np->e_namlen = strlen(name);
+ np->e_parent = np;
+ addino(ROOTINO, np);
+ return (np);
+ }
+ np->e_name = savename(strrchr(name, '/') + 1);
+ np->e_namlen = strlen(np->e_name);
+ np->e_parent = ep;
+ np->e_sibling = ep->e_entries;
+ ep->e_entries = np;
+ if (type & LINK) {
+ ep = lookupino(inum);
+ if (ep == NULL)
+ panic("link to non-existant name\n");
+ np->e_ino = inum;
+ np->e_links = ep->e_links;
+ ep->e_links = np;
+ } else if (inum != 0) {
+ if (lookupino(inum) != NULL)
+ panic("duplicate entry\n");
+ addino(inum, np);
+ }
+ return (np);
+}
+
+/*
+ * delete an entry from the symbol table
+ */
+void
+freeentry(ep)
+ register struct entry *ep;
+{
+ register struct entry *np;
+ ino_t inum;
+
+ if (ep->e_flags != REMOVED)
+ badentry(ep, "not marked REMOVED");
+ if (ep->e_type == NODE) {
+ if (ep->e_links != NULL)
+ badentry(ep, "freeing referenced directory");
+ if (ep->e_entries != NULL)
+ badentry(ep, "freeing non-empty directory");
+ }
+ if (ep->e_ino != 0) {
+ np = lookupino(ep->e_ino);
+ if (np == NULL)
+ badentry(ep, "lookupino failed");
+ if (np == ep) {
+ inum = ep->e_ino;
+ deleteino(inum);
+ if (ep->e_links != NULL)
+ addino(inum, ep->e_links);
+ } else {
+ for (; np != NULL; np = np->e_links) {
+ if (np->e_links == ep) {
+ np->e_links = ep->e_links;
+ break;
+ }
+ }
+ if (np == NULL)
+ badentry(ep, "link not found");
+ }
+ }
+ removeentry(ep);
+ freename(ep->e_name);
+ ep->e_next = freelist;
+ freelist = ep;
+}
+
+/*
+ * Relocate an entry in the tree structure
+ */
+void
+moveentry(ep, newname)
+ register struct entry *ep;
+ char *newname;
+{
+ struct entry *np;
+ char *cp;
+
+ np = lookupparent(newname);
+ if (np == NULL)
+ badentry(ep, "cannot move ROOT");
+ if (np != ep->e_parent) {
+ removeentry(ep);
+ ep->e_parent = np;
+ ep->e_sibling = np->e_entries;
+ np->e_entries = ep;
+ }
+ cp = strrchr(newname, '/') + 1;
+ freename(ep->e_name);
+ ep->e_name = savename(cp);
+ ep->e_namlen = strlen(cp);
+ if (strcmp(gentempname(ep), ep->e_name) == 0)
+ ep->e_flags |= TMPNAME;
+ else
+ ep->e_flags &= ~TMPNAME;
+}
+
+/*
+ * Remove an entry in the tree structure
+ */
+static void
+removeentry(ep)
+ register struct entry *ep;
+{
+ register struct entry *np;
+
+ np = ep->e_parent;
+ if (np->e_entries == ep) {
+ np->e_entries = ep->e_sibling;
+ } else {
+ for (np = np->e_entries; np != NULL; np = np->e_sibling) {
+ if (np->e_sibling == ep) {
+ np->e_sibling = ep->e_sibling;
+ break;
+ }
+ }
+ if (np == NULL)
+ badentry(ep, "cannot find entry in parent list");
+ }
+}
+
+/*
+ * Table of unused string entries, sorted by length.
+ *
+ * Entries are allocated in STRTBLINCR sized pieces so that names
+ * of similar lengths can use the same entry. The value of STRTBLINCR
+ * is chosen so that every entry has at least enough space to hold
+ * a "struct strtbl" header. Thus every entry can be linked onto an
+ * apprpriate free list.
+ *
+ * NB. The macro "allocsize" below assumes that "struct strhdr"
+ * has a size that is a power of two.
+ */
+struct strhdr {
+ struct strhdr *next;
+};
+
+#define STRTBLINCR (sizeof(struct strhdr))
+#define allocsize(size) (((size) + 1 + STRTBLINCR - 1) & ~(STRTBLINCR - 1))
+
+static struct strhdr strtblhdr[allocsize(NAME_MAX) / STRTBLINCR];
+
+/*
+ * Allocate space for a name. It first looks to see if it already
+ * has an appropriate sized entry, and if not allocates a new one.
+ */
+char *
+savename(name)
+ char *name;
+{
+ struct strhdr *np;
+ long len;
+ char *cp;
+
+ if (name == NULL)
+ panic("bad name\n");
+ len = strlen(name);
+ np = strtblhdr[len / STRTBLINCR].next;
+ if (np != NULL) {
+ strtblhdr[len / STRTBLINCR].next = np->next;
+ cp = (char *)np;
+ } else {
+ cp = malloc((unsigned)allocsize(len));
+ if (cp == NULL)
+ panic("no space for string table\n");
+ }
+ (void) strcpy(cp, name);
+ return (cp);
+}
+
+/*
+ * Free space for a name. The resulting entry is linked onto the
+ * appropriate free list.
+ */
+void
+freename(name)
+ char *name;
+{
+ struct strhdr *tp, *np;
+
+ tp = &strtblhdr[strlen(name) / STRTBLINCR];
+ np = (struct strhdr *)name;
+ np->next = tp->next;
+ tp->next = np;
+}
+
+/*
+ * Useful quantities placed at the end of a dumped symbol table.
+ */
+struct symtableheader {
+ long volno;
+ long stringsize;
+ long entrytblsize;
+ time_t dumptime;
+ time_t dumpdate;
+ ino_t maxino;
+ long ntrec;
+};
+
+/*
+ * dump a snapshot of the symbol table
+ */
+void
+dumpsymtable(filename, checkpt)
+ char *filename;
+ long checkpt;
+{
+ register struct entry *ep, *tep;
+ register ino_t i;
+ struct entry temp, *tentry;
+ long mynum = 1, stroff = 0;
+ FILE *fd;
+ struct symtableheader hdr;
+
+ vprintf(stdout, "Check pointing the restore\n");
+ if (Nflag)
+ return;
+ if ((fd = fopen(filename, "w")) == NULL) {
+ fprintf(stderr, "fopen: %s\n", strerror(errno));
+ panic("cannot create save file %s for symbol table\n",
+ filename);
+ }
+ clearerr(fd);
+ /*
+ * Assign indicies to each entry
+ * Write out the string entries
+ */
+ for (i = WINO; i < maxino; i++) {
+ for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
+ ep->e_index = mynum++;
+ (void) fwrite(ep->e_name, sizeof(char),
+ (int)allocsize(ep->e_namlen), fd);
+ }
+ }
+ /*
+ * Convert pointers to indexes, and output
+ */
+ tep = &temp;
+ stroff = 0;
+ for (i = WINO; i < maxino; i++) {
+ for (ep = lookupino(i); ep != NULL; ep = ep->e_links) {
+ memmove(tep, ep, (long)sizeof(struct entry));
+ tep->e_name = (char *)stroff;
+ stroff += allocsize(ep->e_namlen);
+ tep->e_parent = (struct entry *)ep->e_parent->e_index;
+ if (ep->e_links != NULL)
+ tep->e_links =
+ (struct entry *)ep->e_links->e_index;
+ if (ep->e_sibling != NULL)
+ tep->e_sibling =
+ (struct entry *)ep->e_sibling->e_index;
+ if (ep->e_entries != NULL)
+ tep->e_entries =
+ (struct entry *)ep->e_entries->e_index;
+ if (ep->e_next != NULL)
+ tep->e_next =
+ (struct entry *)ep->e_next->e_index;
+ (void) fwrite((char *)tep, sizeof(struct entry), 1, fd);
+ }
+ }
+ /*
+ * Convert entry pointers to indexes, and output
+ */
+ for (i = 0; i < entrytblsize; i++) {
+ if (entry[i] == NULL)
+ tentry = NULL;
+ else
+ tentry = (struct entry *)entry[i]->e_index;
+ (void) fwrite((char *)&tentry, sizeof(struct entry *), 1, fd);
+ }
+ hdr.volno = checkpt;
+ hdr.maxino = maxino;
+ hdr.entrytblsize = entrytblsize;
+ hdr.stringsize = stroff;
+ hdr.dumptime = dumptime;
+ hdr.dumpdate = dumpdate;
+ hdr.ntrec = ntrec;
+ (void) fwrite((char *)&hdr, sizeof(struct symtableheader), 1, fd);
+ if (ferror(fd)) {
+ fprintf(stderr, "fwrite: %s\n", strerror(errno));
+ panic("output error to file %s writing symbol table\n",
+ filename);
+ }
+ (void) fclose(fd);
+}
+
+/*
+ * Initialize a symbol table from a file
+ */
+void
+initsymtable(filename)
+ char *filename;
+{
+ char *base;
+ long tblsize;
+ register struct entry *ep;
+ struct entry *baseep, *lep;
+ struct symtableheader hdr;
+ struct stat stbuf;
+ register long i;
+ int fd;
+
+ vprintf(stdout, "Initialize symbol table.\n");
+ if (filename == NULL) {
+ entrytblsize = maxino / HASHFACTOR;
+ entry = (struct entry **)
+ calloc((unsigned)entrytblsize, sizeof(struct entry *));
+ if (entry == (struct entry **)NULL)
+ panic("no memory for entry table\n");
+ ep = addentry(".", ROOTINO, NODE);
+ ep->e_flags |= NEW;
+ return;
+ }
+ if ((fd = open(filename, O_RDONLY, 0)) < 0) {
+ fprintf(stderr, "open: %s\n", strerror(errno));
+ panic("cannot open symbol table file %s\n", filename);
+ }
+ if (fstat(fd, &stbuf) < 0) {
+ fprintf(stderr, "stat: %s\n", strerror(errno));
+ panic("cannot stat symbol table file %s\n", filename);
+ }
+ tblsize = stbuf.st_size - sizeof(struct symtableheader);
+ base = calloc(sizeof(char), (unsigned)tblsize);
+ if (base == NULL)
+ panic("cannot allocate space for symbol table\n");
+ if (read(fd, base, (int)tblsize) < 0 ||
+ read(fd, (char *)&hdr, sizeof(struct symtableheader)) < 0) {
+ fprintf(stderr, "read: %s\n", strerror(errno));
+ panic("cannot read symbol table file %s\n", filename);
+ }
+ switch (command) {
+ case 'r':
+ /*
+ * For normal continuation, insure that we are using
+ * the next incremental tape
+ */
+ if (hdr.dumpdate != dumptime) {
+ if (hdr.dumpdate < dumptime)
+ fprintf(stderr, "Incremental tape too low\n");
+ else
+ fprintf(stderr, "Incremental tape too high\n");
+ done(1);
+ }
+ break;
+ case 'R':
+ /*
+ * For restart, insure that we are using the same tape
+ */
+ curfile.action = SKIP;
+ dumptime = hdr.dumptime;
+ dumpdate = hdr.dumpdate;
+ if (!bflag)
+ newtapebuf(hdr.ntrec);
+ getvol(hdr.volno);
+ break;
+ default:
+ panic("initsymtable called from command %c\n", command);
+ break;
+ }
+ maxino = hdr.maxino;
+ entrytblsize = hdr.entrytblsize;
+ entry = (struct entry **)
+ (base + tblsize - (entrytblsize * sizeof(struct entry *)));
+ baseep = (struct entry *)(base + hdr.stringsize - sizeof(struct entry));
+ lep = (struct entry *)entry;
+ for (i = 0; i < entrytblsize; i++) {
+ if (entry[i] == NULL)
+ continue;
+ entry[i] = &baseep[(long)entry[i]];
+ }
+ for (ep = &baseep[1]; ep < lep; ep++) {
+ ep->e_name = base + (long)ep->e_name;
+ ep->e_parent = &baseep[(long)ep->e_parent];
+ if (ep->e_sibling != NULL)
+ ep->e_sibling = &baseep[(long)ep->e_sibling];
+ if (ep->e_links != NULL)
+ ep->e_links = &baseep[(long)ep->e_links];
+ if (ep->e_entries != NULL)
+ ep->e_entries = &baseep[(long)ep->e_entries];
+ if (ep->e_next != NULL)
+ ep->e_next = &baseep[(long)ep->e_next];
+ }
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ * (c) UNIX System Laboratories, Inc.
+ * All or some portions of this file are derived from material licensed
+ * to the University of California by American Telephone and Telegraph
+ * Co. or Unix System Laboratories, Inc. and are reproduced herein with
+ * the permission of UNIX System Laboratories, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)tape.c 8.9 (Berkeley) 5/1/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/file.h>
+#include <sys/ioctl.h>
+#include <sys/mtio.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#include <ufs/ufs/dinode.h>
+#endif /* __linux__ */
+#include <protocols/dumprestore.h>
+
+#include <errno.h>
+#include <setjmp.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "restore.h"
+#include "extern.h"
+#include "pathnames.h"
+
+static long fssize = MAXBSIZE;
+static int mt = -1;
+static int pipein = 0;
+static char magtape[BUFSIZ];
+static int blkcnt;
+static int numtrec;
+static char *tapebuf;
+static union u_spcl endoftapemark;
+static long blksread; /* blocks read since last header */
+static long tpblksread = 0; /* TP_BSIZE blocks read */
+static long tapesread;
+static jmp_buf restart;
+static int gettingfile = 0; /* restart has a valid frame */
+static char *host = NULL;
+
+static int ofile;
+static char *map;
+static char lnkbuf[MAXPATHLEN + 1];
+static int pathlen;
+
+int oldinofmt; /* old inode format conversion required */
+int Bcvt; /* Swap Bytes (for CCI or sun) */
+static int Qcvt; /* Swap quads (for sun) */
+
+#define FLUSHTAPEBUF() blkcnt = ntrec + 1
+
+static void accthdr __P((struct s_spcl *));
+static int checksum __P((int *));
+static void findinode __P((struct s_spcl *));
+static void findtapeblksize __P((void));
+static int gethead __P((struct s_spcl *));
+static void readtape __P((char *));
+static void setdumpnum __P((void));
+static u_long swabl __P((u_long));
+static u_char *swablong __P((u_char *, int));
+static u_char *swabshort __P((u_char *, int));
+static void terminateinput __P((void));
+static void xtrfile __P((char *, long));
+static void xtrlnkfile __P((char *, long));
+static void xtrlnkskip __P((char *, long));
+static void xtrmap __P((char *, long));
+static void xtrmapskip __P((char *, long));
+static void xtrskip __P((char *, long));
+
+/*
+ * Set up an input source
+ */
+void
+setinput(source)
+ char *source;
+{
+ FLUSHTAPEBUF();
+ if (bflag)
+ newtapebuf(ntrec);
+ else
+ newtapebuf(NTREC > HIGHDENSITYTREC ? NTREC : HIGHDENSITYTREC);
+ terminal = stdin;
+
+#ifdef RRESTORE
+ if (strchr(source, ':')) {
+ host = source;
+ source = strchr(host, ':');
+ *source++ = '\0';
+ if (rmthost(host) == 0)
+ done(1);
+ } else
+#endif
+ if (strcmp(source, "-") == 0) {
+ /*
+ * Since input is coming from a pipe we must establish
+ * our own connection to the terminal.
+ */
+ terminal = fopen(_PATH_TTY, "r");
+ if (terminal == NULL) {
+ (void)fprintf(stderr, "cannot open %s: %s\n",
+ _PATH_TTY, strerror(errno));
+ terminal = fopen(_PATH_DEVNULL, "r");
+ if (terminal == NULL) {
+ (void)fprintf(stderr, "cannot open %s: %s\n",
+ _PATH_DEVNULL, strerror(errno));
+ done(1);
+ }
+ }
+ pipein++;
+ }
+ setuid(getuid()); /* no longer need or want root privileges */
+ (void) strcpy(magtape, source);
+}
+
+void
+newtapebuf(size)
+ long size;
+{
+ static tapebufsize = -1;
+
+ ntrec = size;
+ if (size <= tapebufsize)
+ return;
+ if (tapebuf != NULL)
+ free(tapebuf);
+ tapebuf = malloc(size * TP_BSIZE);
+ if (tapebuf == NULL) {
+ fprintf(stderr, "Cannot allocate space for tape buffer\n");
+ done(1);
+ }
+ tapebufsize = size;
+}
+
+/*
+ * Verify that the tape drive can be accessed and
+ * that it actually is a dump tape.
+ */
+void
+setup()
+{
+ int i, j, *ip;
+ struct stat stbuf;
+
+ vprintf(stdout, "Verify tape and initialize maps\n");
+#ifdef RRESTORE
+ if (host)
+ mt = rmtopen(magtape, 0);
+ else
+#endif
+ if (pipein)
+ mt = 0;
+ else
+ mt = open(magtape, O_RDONLY, 0);
+ if (mt < 0) {
+ fprintf(stderr, "%s: %s\n", magtape, strerror(errno));
+ done(1);
+ }
+ volno = 1;
+ setdumpnum();
+ FLUSHTAPEBUF();
+ if (!pipein && !bflag)
+ findtapeblksize();
+ if (gethead(&spcl) == FAIL) {
+ blkcnt--; /* push back this block */
+ blksread--;
+ tpblksread--;
+ cvtflag++;
+ if (gethead(&spcl) == FAIL) {
+ fprintf(stderr, "Tape is not a dump tape\n");
+ done(1);
+ }
+ fprintf(stderr, "Converting to new file system format.\n");
+ }
+ if (pipein) {
+ endoftapemark.s_spcl.c_magic = cvtflag ? OFS_MAGIC : NFS_MAGIC;
+ endoftapemark.s_spcl.c_type = TS_END;
+ ip = (int *)&endoftapemark;
+ j = sizeof(union u_spcl) / sizeof(int);
+ i = 0;
+ do
+ i += *ip++;
+ while (--j);
+ endoftapemark.s_spcl.c_checksum = CHECKSUM - i;
+ }
+ if (vflag || command == 't' || command == 'C')
+ printdumpinfo();
+ if (filesys == NULL) {
+ filesys = spcl.c_filesys;
+ }
+ dumptime = spcl.c_ddate;
+ dumpdate = spcl.c_date;
+ if (stat(".", &stbuf) < 0) {
+ fprintf(stderr, "cannot stat .: %s\n", strerror(errno));
+ done(1);
+ }
+ if (stbuf.st_blksize > 0 && stbuf.st_blksize <= MAXBSIZE)
+ fssize = stbuf.st_blksize;
+ if (((fssize - 1) & fssize) != 0) {
+ fprintf(stderr, "bad block size %d\n", fssize);
+ done(1);
+ }
+ if (spcl.c_volume != 1) {
+ fprintf(stderr, "Tape is not volume 1 of the dump\n");
+ done(1);
+ }
+ if (gethead(&spcl) == FAIL) {
+ dprintf(stdout, "header read failed at %d blocks\n", blksread);
+ panic("no header after volume mark!\n");
+ }
+ findinode(&spcl);
+ if (spcl.c_type != TS_CLRI) {
+ fprintf(stderr, "Cannot find file removal list\n");
+ done(1);
+ }
+ maxino = (spcl.c_count * TP_BSIZE * NBBY) + 1;
+ dprintf(stdout, "maxino = %d\n", maxino);
+ map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
+ if (map == NULL)
+ panic("no memory for active inode map\n");
+ usedinomap = map;
+ curfile.action = USING;
+ getfile(xtrmap, xtrmapskip);
+ if (spcl.c_type != TS_BITS) {
+ fprintf(stderr, "Cannot find file dump list\n");
+ done(1);
+ }
+ map = calloc((unsigned)1, (unsigned)howmany(maxino, NBBY));
+ if (map == (char *)NULL)
+ panic("no memory for file dump list\n");
+ dumpmap = map;
+ curfile.action = USING;
+ getfile(xtrmap, xtrmapskip);
+ /*
+ * If there may be whiteout entries on the tape, pretend that the
+ * whiteout inode exists, so that the whiteout entries can be
+ * extracted.
+ */
+ if (oldinofmt == 0)
+ SETINO(WINO, dumpmap);
+}
+
+/*
+ * Prompt user to load a new dump volume.
+ * "Nextvol" is the next suggested volume to use.
+ * This suggested volume is enforced when doing full
+ * or incremental restores, but can be overrridden by
+ * the user when only extracting a subset of the files.
+ */
+void
+getvol(nextvol)
+ long nextvol;
+{
+ long newvol, savecnt, wantnext, i;
+ union u_spcl tmpspcl;
+# define tmpbuf tmpspcl.s_spcl
+ char buf[TP_BSIZE];
+
+ if (nextvol == 1) {
+ tapesread = 0;
+ gettingfile = 0;
+ }
+ if (pipein) {
+ if (nextvol != 1)
+ panic("Changing volumes on pipe input?\n");
+ if (volno == 1)
+ return;
+ goto gethdr;
+ }
+ savecnt = blksread;
+again:
+ if (pipein)
+ done(1); /* pipes do not get a second chance */
+ if (command == 'R' || command == 'r' || curfile.action != SKIP) {
+ newvol = nextvol;
+ wantnext = 1;
+ } else {
+ newvol = 0;
+ wantnext = 0;
+ }
+ while (newvol <= 0) {
+ if (tapesread == 0) {
+ fprintf(stderr, "%s%s%s%s%s",
+ "You have not read any tapes yet.\n",
+ "Unless you know which volume your",
+ " file(s) are on you should start\n",
+ "with the last volume and work",
+ " towards the first.\n");
+ } else {
+ fprintf(stderr, "You have read volumes");
+ strcpy(buf, ": ");
+ for (i = 1; i < 32; i++)
+ if (tapesread & (1 << i)) {
+ fprintf(stderr, "%s%d", buf, i);
+ strcpy(buf, ", ");
+ }
+ fprintf(stderr, "\n");
+ }
+ do {
+ fprintf(stderr, "Specify next volume #: ");
+ (void) fflush(stderr);
+ (void) fgets(buf, BUFSIZ, terminal);
+ } while (!feof(terminal) && buf[0] == '\n');
+ if (feof(terminal))
+ done(1);
+ newvol = atoi(buf);
+ if (newvol <= 0) {
+ fprintf(stderr,
+ "Volume numbers are positive numerics\n");
+ }
+ }
+ if (newvol == volno) {
+ tapesread |= 1 << volno;
+ return;
+ }
+ closemt();
+ fprintf(stderr, "Mount tape volume %d\n", newvol);
+ fprintf(stderr, "Enter ``none'' if there are no more tapes\n");
+ fprintf(stderr, "otherwise enter tape name (default: %s) ", magtape);
+ (void) fflush(stderr);
+ (void) fgets(buf, BUFSIZ, terminal);
+ if (feof(terminal))
+ done(1);
+ if (!strcmp(buf, "none\n")) {
+ terminateinput();
+ return;
+ }
+ if (buf[0] != '\n') {
+ (void) strcpy(magtape, buf);
+ magtape[strlen(magtape) - 1] = '\0';
+ }
+#ifdef RRESTORE
+ if (host)
+ mt = rmtopen(magtape, 0);
+ else
+#endif
+ mt = open(magtape, O_RDONLY, 0);
+
+ if (mt == -1) {
+ fprintf(stderr, "Cannot open %s\n", magtape);
+ volno = -1;
+ goto again;
+ }
+gethdr:
+ volno = newvol;
+ setdumpnum();
+ FLUSHTAPEBUF();
+ if (gethead(&tmpbuf) == FAIL) {
+ dprintf(stdout, "header read failed at %d blocks\n", blksread);
+ fprintf(stderr, "tape is not dump tape\n");
+ volno = 0;
+ goto again;
+ }
+ if (tmpbuf.c_volume != volno) {
+ fprintf(stderr, "Wrong volume (%d)\n", tmpbuf.c_volume);
+ volno = 0;
+ goto again;
+ }
+ if (tmpbuf.c_date != dumpdate || tmpbuf.c_ddate != dumptime) {
+#ifdef __linux__
+ fprintf(stderr, "Wrong dump date\n\tgot: %s",
+ ctime4(&tmpbuf.c_date));
+ fprintf(stderr, "\twanted: %s", ctime4(&dumpdate));
+#else
+ fprintf(stderr, "Wrong dump date\n\tgot: %s",
+ ctime(&tmpbuf.c_date));
+ fprintf(stderr, "\twanted: %s", ctime(&dumpdate));
+#endif
+ volno = 0;
+ goto again;
+ }
+ tapesread |= 1 << volno;
+ blksread = savecnt;
+ /*
+ * If continuing from the previous volume, skip over any
+ * blocks read already at the end of the previous volume.
+ *
+ * If coming to this volume at random, skip to the beginning
+ * of the next record.
+ */
+ dprintf(stdout, "read %ld recs, tape starts with %ld\n",
+ tpblksread, tmpbuf.c_firstrec);
+ if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER)) {
+ if (!wantnext) {
+ tpblksread = tmpbuf.c_firstrec;
+ for (i = tmpbuf.c_count; i > 0; i--)
+ readtape(buf);
+ } else if (tmpbuf.c_firstrec > 0 &&
+ tmpbuf.c_firstrec < tpblksread - 1) {
+ /*
+ * -1 since we've read the volume header
+ */
+ i = tpblksread - tmpbuf.c_firstrec - 1;
+ dprintf(stderr, "Skipping %d duplicate record%s.\n",
+ i, i > 1 ? "s" : "");
+ while (--i >= 0)
+ readtape(buf);
+ }
+ }
+ if (curfile.action == USING) {
+ if (volno == 1)
+ panic("active file into volume 1\n");
+ return;
+ }
+ /*
+ * Skip up to the beginning of the next record
+ */
+ if (tmpbuf.c_type == TS_TAPE && (tmpbuf.c_flags & DR_NEWHEADER))
+ for (i = tmpbuf.c_count; i > 0; i--)
+ readtape(buf);
+ (void) gethead(&spcl);
+ findinode(&spcl);
+ if (gettingfile) {
+ gettingfile = 0;
+ longjmp(restart, 1);
+ }
+}
+
+/*
+ * Handle unexpected EOF.
+ */
+static void
+terminateinput()
+{
+
+ if (gettingfile && curfile.action == USING) {
+ printf("Warning: %s %s\n",
+ "End-of-input encountered while extracting", curfile.name);
+ }
+ curfile.name = "<name unknown>";
+ curfile.action = UNKNOWN;
+ curfile.dip = NULL;
+ curfile.ino = maxino;
+ if (gettingfile) {
+ gettingfile = 0;
+ longjmp(restart, 1);
+ }
+}
+
+/*
+ * handle multiple dumps per tape by skipping forward to the
+ * appropriate one.
+ */
+static void
+setdumpnum()
+{
+ struct mtop tcom;
+
+ if (dumpnum == 1 || volno != 1)
+ return;
+ if (pipein) {
+ fprintf(stderr, "Cannot have multiple dumps on pipe input\n");
+ done(1);
+ }
+ tcom.mt_op = MTFSF;
+ tcom.mt_count = dumpnum - 1;
+#ifdef RRESTORE
+ if (host)
+ rmtioctl(MTFSF, dumpnum - 1);
+ else
+#endif
+ if (ioctl(mt, (int)MTIOCTOP, (char *)&tcom) < 0)
+ fprintf(stderr, "ioctl MTFSF: %s\n", strerror(errno));
+}
+
+void
+printdumpinfo()
+{
+#ifdef __linux__
+ fprintf(stdout, "Dump date: %s", ctime4(&spcl.c_date));
+ fprintf(stdout, "Dumped from: %s",
+ (spcl.c_ddate == 0) ? "the epoch\n" : ctime4(&spcl.c_ddate));
+#else
+ fprintf(stdout, "Dump date: %s", ctime(&spcl.c_date));
+ fprintf(stdout, "Dumped from: %s",
+ (spcl.c_ddate == 0) ? "the epoch\n" : ctime(&spcl.c_ddate));
+#endif
+ if (spcl.c_host[0] == '\0')
+ return;
+ fprintf(stderr, "Level %d dump of %s on %s:%s\n",
+ spcl.c_level, spcl.c_filesys, spcl.c_host, spcl.c_dev);
+ fprintf(stderr, "Label: %s\n", spcl.c_label);
+}
+
+int
+extractfile(name)
+ char *name;
+{
+ int flags;
+ mode_t mode;
+ struct timeval timep[2];
+ struct entry *ep;
+#ifdef __linux__
+ int err;
+ uid_t uid;
+ gid_t gid;
+#endif
+
+ curfile.name = name;
+ curfile.action = USING;
+#ifdef __linux__
+ timep[0].tv_sec = curfile.dip->di_atime.tv_sec;
+ timep[0].tv_usec = curfile.dip->di_atime.tv_usec;
+ timep[1].tv_sec = curfile.dip->di_mtime.tv_sec;
+ timep[1].tv_usec = curfile.dip->di_mtime.tv_usec;
+#else /* __linux__ */
+ timep[0].tv_sec = curfile.dip->di_atime;
+ timep[0].tv_usec = curfile.dip->di_atimensec / 1000;
+ timep[1].tv_sec = curfile.dip->di_mtime;
+ timep[1].tv_usec = curfile.dip->di_mtimensec / 1000;
+#endif /* __linux__ */
+ mode = curfile.dip->di_mode;
+ flags = curfile.dip->di_flags;
+ switch (mode & IFMT) {
+
+ default:
+ fprintf(stderr, "%s: unknown file mode 0%o\n", name, mode);
+ skipfile();
+ return (FAIL);
+
+ case IFSOCK:
+ vprintf(stdout, "skipped socket %s\n", name);
+ skipfile();
+ return (GOOD);
+
+ case IFDIR:
+ if (mflag) {
+ ep = lookupname(name);
+ if (ep == NULL || ep->e_flags & EXTRACT)
+ panic("unextracted directory %s\n", name);
+ skipfile();
+ return (GOOD);
+ }
+ vprintf(stdout, "extract file %s\n", name);
+ return (genliteraldir(name, curfile.ino));
+
+ case IFLNK:
+ lnkbuf[0] = '\0';
+ pathlen = 0;
+#ifdef __linux__
+ uid = curfile.dip->di_uid;
+ gid = curfile.dip->di_gid;
+#endif
+ getfile(xtrlnkfile, xtrlnkskip);
+ if (pathlen == 0) {
+ vprintf(stdout,
+ "%s: zero length symbolic link (ignored)\n", name);
+ return (GOOD);
+ }
+#ifdef __linux__
+ err = linkit(lnkbuf, name, SYMLINK);
+ if (err == GOOD)
+ (void) chown(name, uid, gid);
+ return (err);
+#else
+ return (linkit(lnkbuf, name, SYMLINK));
+#endif
+
+ case IFCHR:
+ case IFBLK:
+ vprintf(stdout, "extract special file %s\n", name);
+ if (Nflag) {
+ skipfile();
+ return (GOOD);
+ }
+ if (mknod(name, mode, (int)curfile.dip->di_rdev) < 0) {
+ fprintf(stderr, "%s: cannot create special file: %s\n",
+ name, strerror(errno));
+ skipfile();
+ return (FAIL);
+ }
+ (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+ (void) chmod(name, mode);
+#ifdef __linux__
+ (void) fsetflags(name, flags);
+#else
+ (void) chflags(name, flags);
+#endif
+ skipfile();
+ utimes(name, timep);
+ return (GOOD);
+
+ case IFIFO:
+ vprintf(stdout, "extract fifo %s\n", name);
+ if (Nflag) {
+ skipfile();
+ return (GOOD);
+ }
+ if (mkfifo(name, mode) < 0) {
+ fprintf(stderr, "%s: cannot create fifo: %s\n",
+ name, strerror(errno));
+ skipfile();
+ return (FAIL);
+ }
+ (void) chown(name, curfile.dip->di_uid, curfile.dip->di_gid);
+ (void) chmod(name, mode);
+#ifdef __linux__
+ (void) fsetflags(name, flags);
+#else
+ (void) chflags(name, flags);
+#endif
+ skipfile();
+ utimes(name, timep);
+ return (GOOD);
+
+ case IFREG:
+ vprintf(stdout, "extract file %s\n", name);
+ if (Nflag) {
+ skipfile();
+ return (GOOD);
+ }
+ if ((ofile = open(name, O_WRONLY | O_CREAT | O_TRUNC,
+ 0666)) < 0) {
+ fprintf(stderr, "%s: cannot create file: %s\n",
+ name, strerror(errno));
+ skipfile();
+ return (FAIL);
+ }
+ (void) fchown(ofile, curfile.dip->di_uid, curfile.dip->di_gid);
+ (void) fchmod(ofile, mode);
+#ifdef __linux__
+ (void) fsetflags(ofile, flags);
+#else
+ (void) fchflags(ofile, flags);
+#endif
+ getfile(xtrfile, xtrskip);
+ (void) close(ofile);
+ utimes(name, timep);
+ return (GOOD);
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * skip over bit maps on the tape
+ */
+void
+skipmaps()
+{
+
+ while (spcl.c_type == TS_BITS || spcl.c_type == TS_CLRI)
+ skipfile();
+}
+
+/*
+ * skip over a file on the tape
+ */
+void
+skipfile()
+{
+
+ curfile.action = SKIP;
+ getfile(xtrnull, xtrnull);
+}
+
+/*
+ * Extract a file from the tape.
+ * When an allocated block is found it is passed to the fill function;
+ * when an unallocated block (hole) is found, a zeroed buffer is passed
+ * to the skip function.
+ */
+void
+getfile(fill, skip)
+ void (*fill) __P((char *, long));
+ void (*skip) __P((char *, long));
+{
+ register int i;
+ int curblk = 0;
+ quad_t size = spcl.c_dinode.di_size;
+ int last_write_was_hole = 0;
+ long origsize = size;
+ static char clearedbuf[MAXBSIZE];
+ char buf[MAXBSIZE / TP_BSIZE][TP_BSIZE];
+ char junk[TP_BSIZE];
+
+ if (spcl.c_type == TS_END)
+ panic("ran off end of tape\n");
+ if (spcl.c_magic != NFS_MAGIC)
+ panic("not at beginning of a file\n");
+ if (!gettingfile && setjmp(restart) != 0)
+ return;
+ gettingfile++;
+loop:
+ for (i = 0; i < spcl.c_count; i++) {
+ if (spcl.c_addr[i]) {
+ readtape(&buf[curblk++][0]);
+ if (curblk == fssize / TP_BSIZE) {
+ (*fill)((char *)buf, (long)(size > TP_BSIZE ?
+ fssize : (curblk - 1) * TP_BSIZE + size));
+ curblk = 0;
+ last_write_was_hole = 0;
+ }
+ } else {
+ if (curblk > 0) {
+ (*fill)((char *)buf, (long)(size > TP_BSIZE ?
+ curblk * TP_BSIZE :
+ (curblk - 1) * TP_BSIZE + size));
+ curblk = 0;
+ }
+ (*skip)(clearedbuf, (long)(size > TP_BSIZE ?
+ TP_BSIZE : size));
+ last_write_was_hole = 1;
+ }
+ if ((size -= TP_BSIZE) <= 0) {
+ for (i++; i < spcl.c_count; i++)
+ if (spcl.c_addr[i])
+ readtape(junk);
+ break;
+ }
+ }
+ if (gethead(&spcl) == GOOD && size > 0) {
+ if (spcl.c_type == TS_ADDR)
+ goto loop;
+ dprintf(stdout,
+ "Missing address (header) block for %s at %d blocks\n",
+ curfile.name, blksread);
+ }
+ if (curblk > 0) {
+ (*fill)((char *)buf, (curblk * TP_BSIZE) + size);
+ last_write_was_hole = 0;
+ }
+ if (last_write_was_hole) {
+ ftruncate(ofile, origsize);
+ }
+ findinode(&spcl);
+ gettingfile = 0;
+}
+
+/*
+ * Write out the next block of a file.
+ */
+static void
+xtrfile(buf, size)
+ char *buf;
+ long size;
+{
+
+ if (Nflag)
+ return;
+ if (write(ofile, buf, (int) size) == -1) {
+ fprintf(stderr,
+ "write error extracting inode %d, name %s\nwrite: %s\n",
+ curfile.ino, curfile.name, strerror(errno));
+ done(1);
+ }
+}
+
+/*
+ * Skip over a hole in a file.
+ */
+/* ARGSUSED */
+static void
+xtrskip(buf, size)
+ char *buf;
+ long size;
+{
+
+ if (lseek(ofile, size, SEEK_CUR) == -1) {
+ fprintf(stderr,
+ "seek error extracting inode %d, name %s\nlseek: %s\n",
+ curfile.ino, curfile.name, strerror(errno));
+ done(1);
+ }
+}
+
+/*
+ * Collect the next block of a symbolic link.
+ */
+static void
+xtrlnkfile(buf, size)
+ char *buf;
+ long size;
+{
+
+ pathlen += size;
+ if (pathlen > MAXPATHLEN) {
+ fprintf(stderr, "symbolic link name: %s->%s%s; too long %d\n",
+ curfile.name, lnkbuf, buf, pathlen);
+ done(1);
+ }
+ (void) strcat(lnkbuf, buf);
+}
+
+/*
+ * Skip over a hole in a symbolic link (should never happen).
+ */
+/* ARGSUSED */
+static void
+xtrlnkskip(buf, size)
+ char *buf;
+ long size;
+{
+
+ fprintf(stderr, "unallocated block in symbolic link %s\n",
+ curfile.name);
+ done(1);
+}
+
+/*
+ * Collect the next block of a bit map.
+ */
+static void
+xtrmap(buf, size)
+ char *buf;
+ long size;
+{
+
+ memmove(map, buf, size);
+ map += size;
+}
+
+/*
+ * Skip over a hole in a bit map (should never happen).
+ */
+/* ARGSUSED */
+static void
+xtrmapskip(buf, size)
+ char *buf;
+ long size;
+{
+
+ panic("hole in map\n");
+ map += size;
+}
+
+/*
+ * Noop, when an extraction function is not needed.
+ */
+/* ARGSUSED */
+void
+xtrnull(buf, size)
+ char *buf;
+ long size;
+{
+
+ return;
+}
+
+int
+do_cmpfiles(int fd_tape, int fd_disk, long size)
+{
+#ifndef BUFSIZE
+#define BUFSIZE 1024
+#endif
+ static char buf_tape[BUFSIZ];
+ static char buf_disk[BUFSIZ];
+ int left = size;
+ int n_tape;
+ int n_disk;
+
+ while (size > 0) {
+ if ((n_tape = read(fd_tape, buf_tape, BUFSIZE)) < 1) {
+ close(fd_tape), close(fd_disk);
+ panic("do_cmpfiles: unexpected EOF[1]");
+ }
+ if ((n_disk = read(fd_disk, buf_disk, BUFSIZE)) < 1) {
+ close(fd_tape), close(fd_disk);
+ panic("do_cmpfiles: unexpected EOF[2]");
+ }
+ if (n_tape != n_disk) {
+ close(fd_tape), close(fd_disk);
+ panic("do_cmpfiles: sizes different!");
+ }
+ if (memcmp(buf_tape, buf_disk, n_tape) != 0) return (1);
+ size -= n_tape;
+ }
+ return (0);
+}
+
+/* for debugging compare problems */
+#undef COMPARE_FAIL_KEEP_FILE
+
+#ifdef COMPARE_FAIL_KEEP_FILE
+/* return true if tapefile should be unlinked after compare */
+int
+#else
+void
+#endif
+cmpfiles(char *tapefile, char *diskfile, struct stat *sbuf_disk)
+{
+ struct stat sbuf_tape;
+ int fd_tape, fd_disk;
+
+ if (stat(tapefile, &sbuf_tape) != 0) {
+ panic("Can't lstat tmp file %s: %s\n", tapefile,
+ strerror(errno));
+ }
+
+ if (sbuf_disk->st_size != sbuf_tape.st_size) {
+ fprintf(stderr,
+ "%s: size changed from %d to %d.\n",
+ diskfile, sbuf_tape.st_size, sbuf_disk->st_size);
+#ifdef COMPARE_FAIL_KEEP_FILE
+ return (0);
+#else
+ return;
+#endif
+ }
+
+ if ((fd_tape = open(tapefile, O_RDONLY)) < 0) {
+ panic("Can't open %s: %s\n", tapefile, strerror(errno));
+ }
+ if ((fd_disk = open(diskfile, O_RDONLY)) < 0) {
+ close(fd_tape);
+ panic("Can't open %s: %s\n", diskfile, strerror(errno));
+ }
+
+ if (do_cmpfiles(fd_tape, fd_disk, sbuf_tape.st_size)) {
+ fprintf(stderr, "%s: tape and disk copies are different\n",
+ diskfile);
+ close(fd_tape);
+ close(fd_disk);
+#ifdef COMPARE_FAIL_KEEP_FILE
+ /* rename the file to live in /tmp */
+ /* rename `tapefile' to /tmp/<basename of diskfile> */
+ {
+ char *p = strrchr(diskfile, '/');
+ char newname[MAXPATHLEN];
+ if (!p) {
+ panic("can't find / in %s\n", diskfile);
+ }
+ sprintf(newname, "%s/debug/%s", tmpdir, p + 1);
+ if (rename(tapefile, newname)) {
+ panic("rename from %s to %s failed: %s\n",
+ tapefile, newname,
+ strerror(errno));
+ } else {
+ fprintf(stderr, "*** %s saved to %s\n",
+ tapefile, newname);
+ }
+ }
+
+ /* don't unlink the file (it's not there anymore */
+ /* anyway) */
+ return (0);
+#else
+ return;
+#endif
+ }
+ close(fd_tape);
+ close(fd_disk);
+#ifdef COMPARE_FAIL_KEEP_FILE
+ return (1);
+#endif
+}
+
+static char tmpfilename[128];
+
+void
+comparefile(name)
+ char *name;
+{
+ static char *tmpfile = NULL;
+ int mode;
+ struct stat sb, stemp;
+ int r;
+
+ if ((r = lstat(name, &sb)) != 0) {
+ fprintf(stderr, "%s: does not exist (%d, %d).\n", name, r, errno);
+ skipfile();
+ return;
+ }
+
+ curfile.name = name;
+ mode = curfile.dip->di_mode;
+
+ vprintf(stdout, "comparing %s (size: %d, mode: 0%o)\n", name,
+ sb.st_size, mode);
+
+ if (sb.st_mode != mode) {
+ fprintf(stderr, "%s: mode changed from 0%o to 0%o.\n",
+ name, mode & 07777, sb.st_mode & 07777);
+ }
+ switch (mode & IFMT) {
+ default:
+ skipfile();
+ return;
+
+ case IFSOCK:
+ skipfile();
+ return;
+
+ case IFDIR:
+ skipfile();
+ return;
+
+ case IFLNK: {
+ char lbuf[MAXPATHLEN + 1];
+ int lsize;
+
+ if (!(sb.st_mode & S_IFLNK)) {
+ fprintf(stderr, "%s: is no longer a symbolic link\n",
+ name);
+ return;
+ }
+ lnkbuf[0] = '\0';
+ pathlen = 0;
+ getfile(xtrlnkfile, xtrlnkskip);
+ if (pathlen == 0) {
+ fprintf(stderr,
+ "%s: zero length symbolic link (ignored)\n",
+ name);
+ return;
+ }
+ if ((lsize = readlink(name, lbuf, MAXPATHLEN)) < 0) {
+ panic("readlink of %s failed: %s", name,
+ strerror(errno));
+ }
+ lbuf[lsize] = 0;
+ if (strcmp(lbuf, lnkbuf) != 0) {
+ fprintf(stderr,
+ "%s: symbolic link changed from %s to %s.\n",
+ name, lnkbuf, lbuf);
+ return;
+ }
+ return;
+ }
+
+ case IFCHR:
+ case IFBLK:
+ if (!(sb.st_mode & (S_IFCHR|S_IFBLK))) {
+ fprintf(stderr, "%s: no longer a special file\n",
+ name);
+ skipfile();
+ return;
+ }
+
+ if (sb.st_rdev != (int)curfile.dip->di_rdev) {
+ fprintf(stderr,
+ "%s: device changed from %d,%d to %d,%d.\n",
+ name,
+ ((int)curfile.dip->di_rdev >> 8) & 0xf,
+ (int)curfile.dip->di_rdev & 0xf,
+ (sb.st_rdev >> 8) & 0xf,
+ sb.st_rdev & 0xf);
+ }
+ skipfile();
+ return;
+
+ case IFREG:
+ if (tmpfile == NULL) {
+ /* argument to mktemp() must not be in RO space: */
+ sprintf(tmpfilename, "%s/restoreCXXXXXX", tmpdir);
+ tmpfile = mktemp(&tmpfilename[0]);
+ }
+ if ((stat(tmpfile, &stemp) == 0) && (unlink(tmpfile) != 0)) {
+ panic("cannot delete tmp file %s: %s\n",
+ tmpfile, strerror(errno));
+ }
+ if ((ofile = creat(tmpfile, 0600)) < 0) {
+ panic("cannot create file temp file %s: %s\n",
+ name, strerror(errno));
+ }
+ getfile(xtrfile, xtrskip);
+ (void) close(ofile);
+#ifdef COMPARE_FAIL_KEEP_FILE
+ if (cmpfiles(tmpfile, name, &sb))
+ unlink(tmpfile);
+#else
+ cmpfiles(tmpfile, name, &sb);
+ unlink(tmpfile);
+#endif
+ return;
+ }
+ /* NOTREACHED */
+}
+
+/*
+ * Read TP_BSIZE blocks from the input.
+ * Handle read errors, and end of media.
+ */
+static void
+readtape(buf)
+ char *buf;
+{
+ long rd, newvol, i;
+ int cnt, seek_failed;
+
+ if (blkcnt < numtrec) {
+ memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
+ blksread++;
+ tpblksread++;
+ return;
+ }
+ for (i = 0; i < ntrec; i++)
+ ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+ if (numtrec == 0)
+ numtrec = ntrec;
+ cnt = ntrec * TP_BSIZE;
+ rd = 0;
+getmore:
+#ifdef RRESTORE
+ if (host)
+ i = rmtread(&tapebuf[rd], cnt);
+ else
+#endif
+ i = read(mt, &tapebuf[rd], cnt);
+ /*
+ * Check for mid-tape short read error.
+ * If found, skip rest of buffer and start with the next.
+ */
+ if (!pipein && numtrec < ntrec && i > 0) {
+ dprintf(stdout, "mid-media short read error.\n");
+ numtrec = ntrec;
+ }
+ /*
+ * Handle partial block read.
+ */
+ if (pipein && i == 0 && rd > 0)
+ i = rd;
+ else if (i > 0 && i != ntrec * TP_BSIZE) {
+ if (pipein) {
+ rd += i;
+ cnt -= i;
+ if (cnt > 0)
+ goto getmore;
+ i = rd;
+ } else {
+ /*
+ * Short read. Process the blocks read.
+ */
+ if (i % TP_BSIZE != 0)
+ vprintf(stdout,
+ "partial block read: %d should be %d\n",
+ i, ntrec * TP_BSIZE);
+ numtrec = i / TP_BSIZE;
+ }
+ }
+ /*
+ * Handle read error.
+ */
+ if (i < 0) {
+ fprintf(stderr, "Tape read error while ");
+ switch (curfile.action) {
+ default:
+ fprintf(stderr, "trying to set up tape\n");
+ break;
+ case UNKNOWN:
+ fprintf(stderr, "trying to resynchronize\n");
+ break;
+ case USING:
+ fprintf(stderr, "restoring %s\n", curfile.name);
+ break;
+ case SKIP:
+ fprintf(stderr, "skipping over inode %d\n",
+ curfile.ino);
+ break;
+ }
+ if (!yflag && !reply("continue"))
+ done(1);
+ i = ntrec * TP_BSIZE;
+ memset(tapebuf, 0, i);
+#ifdef RRESTORE
+ if (host)
+ seek_failed = (rmtseek(i, 1) < 0);
+ else
+#endif
+ seek_failed = (lseek(mt, i, SEEK_CUR) == (off_t)-1);
+
+ if (seek_failed) {
+ fprintf(stderr,
+ "continuation failed: %s\n", strerror(errno));
+ done(1);
+ }
+ }
+ /*
+ * Handle end of tape.
+ */
+ if (i == 0) {
+ vprintf(stdout, "End-of-tape encountered\n");
+ if (!pipein) {
+ newvol = volno + 1;
+ volno = 0;
+ numtrec = 0;
+ getvol(newvol);
+ readtape(buf);
+ return;
+ }
+ if (rd % TP_BSIZE != 0)
+ panic("partial block read: %d should be %d\n",
+ rd, ntrec * TP_BSIZE);
+ terminateinput();
+ memmove(&tapebuf[rd], &endoftapemark, (long)TP_BSIZE);
+ }
+ blkcnt = 0;
+ memmove(buf, &tapebuf[(blkcnt++ * TP_BSIZE)], (long)TP_BSIZE);
+ blksread++;
+ tpblksread++;
+}
+
+static void
+findtapeblksize()
+{
+ register long i;
+
+ for (i = 0; i < ntrec; i++)
+ ((struct s_spcl *)&tapebuf[i * TP_BSIZE])->c_magic = 0;
+ blkcnt = 0;
+#ifdef RRESTORE
+ if (host)
+ i = rmtread(tapebuf, ntrec * TP_BSIZE);
+ else
+#endif
+ i = read(mt, tapebuf, ntrec * TP_BSIZE);
+
+ if (i <= 0) {
+ fprintf(stderr, "tape read error: %s\n", strerror(errno));
+ done(1);
+ }
+ if (i % TP_BSIZE != 0) {
+ fprintf(stderr, "Tape block size (%d) %s (%d)\n",
+ i, "is not a multiple of dump block size", TP_BSIZE);
+ done(1);
+ }
+ ntrec = i / TP_BSIZE;
+ numtrec = ntrec;
+ vprintf(stdout, "Tape block size is %d\n", ntrec);
+}
+
+void
+closemt()
+{
+
+ if (mt < 0)
+ return;
+#ifdef RRESTORE
+ if (host)
+ rmtclose();
+ else
+#endif
+ (void) close(mt);
+}
+
+/*
+ * Read the next block from the tape.
+ * Check to see if it is one of several vintage headers.
+ * If it is an old style header, convert it to a new style header.
+ * If it is not any valid header, return an error.
+ */
+static int
+gethead(buf)
+ struct s_spcl *buf;
+{
+ long i;
+ union {
+ quad_t qval;
+ long val[2];
+ } qcvt;
+ union u_ospcl {
+ char dummy[TP_BSIZE];
+ struct s_ospcl {
+ long c_type;
+ long c_date;
+ long c_ddate;
+ long c_volume;
+ long c_tapea;
+ u_short c_inumber;
+ long c_magic;
+ long c_checksum;
+ struct odinode {
+ unsigned short odi_mode;
+ u_short odi_nlink;
+ u_short odi_uid;
+ u_short odi_gid;
+ long odi_size;
+ long odi_rdev;
+ char odi_addr[36];
+ long odi_atime;
+ long odi_mtime;
+ long odi_ctime;
+ } c_dinode;
+ long c_count;
+ char c_addr[256];
+ } s_ospcl;
+ } u_ospcl;
+
+ if (!cvtflag) {
+ readtape((char *)buf);
+ if (buf->c_magic != NFS_MAGIC) {
+ if (swabl(buf->c_magic) != NFS_MAGIC)
+ return (FAIL);
+ if (!Bcvt) {
+ vprintf(stdout, "Note: Doing Byte swapping\n");
+ Bcvt = 1;
+ }
+ }
+ if (checksum((int *)buf) == FAIL)
+ return (FAIL);
+ if (Bcvt)
+ swabst((u_char *)"8l4s31l", (u_char *)buf);
+ goto good;
+ }
+ readtape((char *)(&u_ospcl.s_ospcl));
+ memset((char *)buf, 0, (long)TP_BSIZE);
+ buf->c_type = u_ospcl.s_ospcl.c_type;
+ buf->c_date = u_ospcl.s_ospcl.c_date;
+ buf->c_ddate = u_ospcl.s_ospcl.c_ddate;
+ buf->c_volume = u_ospcl.s_ospcl.c_volume;
+ buf->c_tapea = u_ospcl.s_ospcl.c_tapea;
+ buf->c_inumber = u_ospcl.s_ospcl.c_inumber;
+ buf->c_checksum = u_ospcl.s_ospcl.c_checksum;
+ buf->c_magic = u_ospcl.s_ospcl.c_magic;
+ buf->c_dinode.di_mode = u_ospcl.s_ospcl.c_dinode.odi_mode;
+ buf->c_dinode.di_nlink = u_ospcl.s_ospcl.c_dinode.odi_nlink;
+ buf->c_dinode.di_uid = u_ospcl.s_ospcl.c_dinode.odi_uid;
+ buf->c_dinode.di_gid = u_ospcl.s_ospcl.c_dinode.odi_gid;
+ buf->c_dinode.di_size = u_ospcl.s_ospcl.c_dinode.odi_size;
+ buf->c_dinode.di_rdev = u_ospcl.s_ospcl.c_dinode.odi_rdev;
+#ifdef __linux__
+ buf->c_dinode.di_atime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_atime;
+ buf->c_dinode.di_mtime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_mtime;
+ buf->c_dinode.di_ctime.tv_sec = u_ospcl.s_ospcl.c_dinode.odi_ctime;
+#else /* __linux__ */
+ buf->c_dinode.di_atime = u_ospcl.s_ospcl.c_dinode.odi_atime;
+ buf->c_dinode.di_mtime = u_ospcl.s_ospcl.c_dinode.odi_mtime;
+ buf->c_dinode.di_ctime = u_ospcl.s_ospcl.c_dinode.odi_ctime;
+#endif /* __linux__ */
+ buf->c_count = u_ospcl.s_ospcl.c_count;
+ memmove(buf->c_addr, u_ospcl.s_ospcl.c_addr, (long)256);
+ if (u_ospcl.s_ospcl.c_magic != OFS_MAGIC ||
+ checksum((int *)(&u_ospcl.s_ospcl)) == FAIL)
+ return(FAIL);
+ buf->c_magic = NFS_MAGIC;
+
+good:
+ if ((buf->c_dinode.di_size == 0 || buf->c_dinode.di_size > 0xfffffff) &&
+ (buf->c_dinode.di_mode & IFMT) == IFDIR && Qcvt == 0) {
+ qcvt.qval = buf->c_dinode.di_size;
+ if (qcvt.val[0] || qcvt.val[1]) {
+ printf("Note: Doing Quad swapping\n");
+ Qcvt = 1;
+ }
+ }
+ if (Qcvt) {
+ qcvt.qval = buf->c_dinode.di_size;
+ i = qcvt.val[1];
+ qcvt.val[1] = qcvt.val[0];
+ qcvt.val[0] = i;
+ buf->c_dinode.di_size = qcvt.qval;
+ }
+
+ switch (buf->c_type) {
+
+ case TS_CLRI:
+ case TS_BITS:
+ /*
+ * Have to patch up missing information in bit map headers
+ */
+ buf->c_inumber = 0;
+ buf->c_dinode.di_size = buf->c_count * TP_BSIZE;
+ for (i = 0; i < buf->c_count; i++)
+ buf->c_addr[i]++;
+ break;
+
+ case TS_TAPE:
+ if ((buf->c_flags & DR_NEWINODEFMT) == 0)
+ oldinofmt = 1;
+ /* fall through */
+ case TS_END:
+ buf->c_inumber = 0;
+ break;
+
+ case TS_INODE:
+ case TS_ADDR:
+ break;
+
+ default:
+ panic("gethead: unknown inode type %d\n", buf->c_type);
+ break;
+ }
+ /*
+ * If we are restoring a filesystem with old format inodes,
+ * copy the uid/gid to the new location.
+ */
+ if (oldinofmt) {
+ buf->c_dinode.di_uid = buf->c_dinode.di_ouid;
+ buf->c_dinode.di_gid = buf->c_dinode.di_ogid;
+ }
+ if (dflag)
+ accthdr(buf);
+ return(GOOD);
+}
+
+/*
+ * Check that a header is where it belongs and predict the next header
+ */
+static void
+accthdr(header)
+ struct s_spcl *header;
+{
+ static ino_t previno = 0x7fffffff;
+ static int prevtype;
+ static long predict;
+ long blks, i;
+
+ if (header->c_type == TS_TAPE) {
+ fprintf(stderr, "Volume header (%s inode format) ",
+ oldinofmt ? "old" : "new");
+ if (header->c_firstrec)
+ fprintf(stderr, "begins with record %d",
+ header->c_firstrec);
+ fprintf(stderr, "\n");
+ previno = 0x7fffffff;
+ return;
+ }
+ if (previno == 0x7fffffff)
+ goto newcalc;
+ switch (prevtype) {
+ case TS_BITS:
+ fprintf(stderr, "Dumped inodes map header");
+ break;
+ case TS_CLRI:
+ fprintf(stderr, "Used inodes map header");
+ break;
+ case TS_INODE:
+ fprintf(stderr, "File header, ino %d", previno);
+ break;
+ case TS_ADDR:
+ fprintf(stderr, "File continuation header, ino %d", previno);
+ break;
+ case TS_END:
+ fprintf(stderr, "End of tape header");
+ break;
+ }
+ if (predict != blksread - 1)
+ fprintf(stderr, "; predicted %d blocks, got %d blocks",
+ predict, blksread - 1);
+ fprintf(stderr, "\n");
+newcalc:
+ blks = 0;
+ if (header->c_type != TS_END)
+ for (i = 0; i < header->c_count; i++)
+ if (header->c_addr[i] != 0)
+ blks++;
+ predict = blks;
+ blksread = 0;
+ prevtype = header->c_type;
+ previno = header->c_inumber;
+}
+
+/*
+ * Find an inode header.
+ * Complain if had to skip, and complain is set.
+ */
+static void
+findinode(header)
+ struct s_spcl *header;
+{
+ static long skipcnt = 0;
+ long i;
+ char buf[TP_BSIZE];
+
+ curfile.name = "<name unknown>";
+ curfile.action = UNKNOWN;
+ curfile.dip = NULL;
+ curfile.ino = 0;
+ do {
+ if (header->c_magic != NFS_MAGIC) {
+ skipcnt++;
+ while (gethead(header) == FAIL ||
+ header->c_date != dumpdate)
+ skipcnt++;
+ }
+ switch (header->c_type) {
+
+ case TS_ADDR:
+ /*
+ * Skip up to the beginning of the next record
+ */
+ for (i = 0; i < header->c_count; i++)
+ if (header->c_addr[i])
+ readtape(buf);
+ while (gethead(header) == FAIL ||
+ header->c_date != dumpdate)
+ skipcnt++;
+ break;
+
+ case TS_INODE:
+ curfile.dip = &header->c_dinode;
+ curfile.ino = header->c_inumber;
+ break;
+
+ case TS_END:
+ curfile.ino = maxino;
+ break;
+
+ case TS_CLRI:
+ curfile.name = "<file removal list>";
+ break;
+
+ case TS_BITS:
+ curfile.name = "<file dump list>";
+ break;
+
+ case TS_TAPE:
+ panic("unexpected tape header\n");
+ /* NOTREACHED */
+
+ default:
+ panic("unknown tape header type %d\n", spcl.c_type);
+ /* NOTREACHED */
+
+ }
+ } while (header->c_type == TS_ADDR);
+ if (skipcnt > 0)
+ fprintf(stderr, "resync restore, skipped %d blocks\n", skipcnt);
+ skipcnt = 0;
+}
+
+static int
+checksum(buf)
+ register int *buf;
+{
+ register int i, j;
+
+ j = sizeof(union u_spcl) / sizeof(int);
+ i = 0;
+ if(!Bcvt) {
+ do
+ i += *buf++;
+ while (--j);
+ } else {
+ /* What happens if we want to read restore tapes
+ for a 16bit int machine??? */
+ do
+ i += swabl(*buf++);
+ while (--j);
+ }
+
+ if (i != CHECKSUM) {
+ fprintf(stderr, "Checksum error %o, inode %d file %s\n", i,
+ curfile.ino, curfile.name);
+ return(FAIL);
+ }
+ return(GOOD);
+}
+
+#ifdef RRESTORE
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+msg(const char *fmt, ...)
+#else
+msg(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+ (void)vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+#endif /* RRESTORE */
+
+static u_char *
+swabshort(sp, n)
+ register u_char *sp;
+ register int n;
+{
+ char c;
+
+ while (--n >= 0) {
+ c = sp[0]; sp[0] = sp[1]; sp[1] = c;
+ sp += 2;
+ }
+ return (sp);
+}
+
+static u_char *
+swablong(sp, n)
+ register u_char *sp;
+ register int n;
+{
+ char c;
+
+ while (--n >= 0) {
+ c = sp[0]; sp[0] = sp[3]; sp[3] = c;
+ c = sp[2]; sp[2] = sp[1]; sp[1] = c;
+ sp += 4;
+ }
+ return (sp);
+}
+
+void
+swabst(cp, sp)
+ register u_char *cp, *sp;
+{
+ int n = 0;
+
+ while (*cp) {
+ switch (*cp) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ n = (n * 10) + (*cp++ - '0');
+ continue;
+
+ case 's': case 'w': case 'h':
+ if (n == 0)
+ n = 1;
+ sp = swabshort(sp, n);
+ break;
+
+ case 'l':
+ if (n == 0)
+ n = 1;
+ sp = swablong(sp, n);
+ break;
+
+ default: /* Any other character, like 'b' counts as byte. */
+ if (n == 0)
+ n = 1;
+ sp += n;
+ break;
+ }
+ cp++;
+ n = 0;
+ }
+}
+
+static u_long
+swabl(x)
+ u_long x;
+{
+ swabst((u_char *)"l", (u_char *)&x);
+ return (x);
+}
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char sccsid[] = "@(#)utilities.c 8.5 (Berkeley) 4/28/95";
+#endif /* not lint */
+
+#include <sys/param.h>
+#include <sys/stat.h>
+
+#ifdef __linux__
+#include <sys/time.h>
+#include <linux/ext2_fs.h>
+#include <bsdcompat.h>
+#else /* __linux__ */
+#include <ufs/ufs/dinode.h>
+#include <ufs/ufs/dir.h>
+#endif /* __linux__ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#ifdef __linux__
+#include <ext2fs/ext2fs.h>
+#endif
+
+#include "restore.h"
+#include "extern.h"
+
+/*
+ * Insure that all the components of a pathname exist.
+ */
+void
+pathcheck(name)
+ char *name;
+{
+ register char *cp;
+ struct entry *ep;
+ char *start;
+
+ start = strrchr(name, '/');
+ if (start == 0)
+ return;
+ for (cp = start; *cp != '\0'; cp++) {
+ if (*cp != '/')
+ continue;
+ *cp = '\0';
+ ep = lookupname(name);
+ if (ep == NULL) {
+ /* Safe; we know the pathname exists in the dump. */
+ ep = addentry(name, pathsearch(name)->d_ino, NODE);
+ newnode(ep);
+ }
+ ep->e_flags |= NEW|KEEP;
+ *cp = '/';
+ }
+}
+
+/*
+ * Change a name to a unique temporary name.
+ */
+void
+mktempname(ep)
+ register struct entry *ep;
+{
+ char oldname[MAXPATHLEN];
+
+ if (ep->e_flags & TMPNAME)
+ badentry(ep, "mktempname: called with TMPNAME");
+ ep->e_flags |= TMPNAME;
+ (void) strcpy(oldname, myname(ep));
+ freename(ep->e_name);
+ ep->e_name = savename(gentempname(ep));
+ ep->e_namlen = strlen(ep->e_name);
+ renameit(oldname, myname(ep));
+}
+
+/*
+ * Generate a temporary name for an entry.
+ */
+char *
+gentempname(ep)
+ struct entry *ep;
+{
+ static char name[MAXPATHLEN];
+ struct entry *np;
+ long i = 0;
+
+ for (np = lookupino(ep->e_ino);
+ np != NULL && np != ep; np = np->e_links)
+ i++;
+ if (np == NULL)
+ badentry(ep, "not on ino list");
+ (void) sprintf(name, "%s%d%d", TMPHDR, i, ep->e_ino);
+ return (name);
+}
+
+/*
+ * Rename a file or directory.
+ */
+void
+renameit(from, to)
+ char *from, *to;
+{
+ if (!Nflag && rename(from, to) < 0) {
+ fprintf(stderr, "warning: cannot rename %s to %s: %s\n",
+ from, to, strerror(errno));
+ return;
+ }
+ vprintf(stdout, "rename %s to %s\n", from, to);
+}
+
+/*
+ * Create a new node (directory).
+ */
+void
+newnode(np)
+ struct entry *np;
+{
+ char *cp;
+
+ if (np->e_type != NODE)
+ badentry(np, "newnode: not a node");
+ cp = myname(np);
+ if (command == 'C') return;
+ if (!Nflag && mkdir(cp, 0777) < 0) {
+ np->e_flags |= EXISTED;
+ fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
+ return;
+ }
+ vprintf(stdout, "Make node %s\n", cp);
+}
+
+/*
+ * Remove an old node (directory).
+ */
+void
+removenode(ep)
+ register struct entry *ep;
+{
+ char *cp;
+
+ if (ep->e_type != NODE)
+ badentry(ep, "removenode: not a node");
+ if (ep->e_entries != NULL)
+ badentry(ep, "removenode: non-empty directory");
+ ep->e_flags |= REMOVED;
+ ep->e_flags &= ~TMPNAME;
+ cp = myname(ep);
+ if (!Nflag && rmdir(cp) < 0) {
+ fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
+ return;
+ }
+ vprintf(stdout, "Remove node %s\n", cp);
+}
+
+/*
+ * Remove a leaf.
+ */
+void
+removeleaf(ep)
+ register struct entry *ep;
+{
+ char *cp;
+
+ if (command == 'C') return;
+
+ if (ep->e_type != LEAF)
+ badentry(ep, "removeleaf: not a leaf");
+ ep->e_flags |= REMOVED;
+ ep->e_flags &= ~TMPNAME;
+ cp = myname(ep);
+ if (!Nflag && unlink(cp) < 0) {
+ fprintf(stderr, "warning: %s: %s\n", cp, strerror(errno));
+ return;
+ }
+ vprintf(stdout, "Remove leaf %s\n", cp);
+}
+
+/*
+ * Create a link.
+ */
+int
+linkit(existing, new, type)
+ char *existing, *new;
+ int type;
+{
+
+ if (type == SYMLINK) {
+ if (!Nflag && symlink(existing, new) < 0) {
+ fprintf(stderr,
+ "warning: cannot create symbolic link %s->%s: %s\n",
+ new, existing, strerror(errno));
+ return (FAIL);
+ }
+ } else if (type == HARDLINK) {
+ if (!Nflag && link(existing, new) < 0) {
+ fprintf(stderr,
+ "warning: cannot create hard link %s->%s: %s\n",
+ new, existing, strerror(errno));
+ return (FAIL);
+ }
+ } else {
+ panic("linkit: unknown type %d\n", type);
+ return (FAIL);
+ }
+ vprintf(stdout, "Create %s link %s->%s\n",
+ type == SYMLINK ? "symbolic" : "hard", new, existing);
+ return (GOOD);
+}
+
+#ifndef __linux__
+/*
+ * Create a whiteout
+ */
+int
+addwhiteout(name)
+ char *name;
+{
+
+ if (!Nflag && mknod(name, S_IFWHT, 0) < 0) {
+ fprintf(stderr, "warning: cannot create whiteout %s: %s\n",
+ name, strerror(errno));
+ return (FAIL);
+ }
+ vprintf(stdout, "Create whiteout %s\n", name);
+ return (GOOD);
+}
+
+/*
+ * Delete a whiteout.
+ */
+void
+delwhiteout(ep)
+ register struct entry *ep;
+{
+ char *name;
+
+ if (ep->e_type != LEAF)
+ badentry(ep, "delwhiteout: not a leaf");
+ ep->e_flags |= REMOVED;
+ ep->e_flags &= ~TMPNAME;
+ name = myname(ep);
+ if (!Nflag && undelete(name) < 0) {
+ fprintf(stderr, "warning: cannot delete whiteout %s: %s\n",
+ name, strerror(errno));
+ return;
+ }
+ vprintf(stdout, "Delete whiteout %s\n", name);
+}
+#endif
+
+/*
+ * find lowest number file (above "start") that needs to be extracted
+ */
+ino_t
+lowerbnd(start)
+ ino_t start;
+{
+ register struct entry *ep;
+
+ for ( ; start < maxino; start++) {
+ ep = lookupino(start);
+ if (ep == NULL || ep->e_type == NODE)
+ continue;
+ if (ep->e_flags & (NEW|EXTRACT))
+ return (start);
+ }
+ return (start);
+}
+
+/*
+ * find highest number file (below "start") that needs to be extracted
+ */
+ino_t
+upperbnd(start)
+ ino_t start;
+{
+ register struct entry *ep;
+
+ for ( ; start > ROOTINO; start--) {
+ ep = lookupino(start);
+ if (ep == NULL || ep->e_type == NODE)
+ continue;
+ if (ep->e_flags & (NEW|EXTRACT))
+ return (start);
+ }
+ return (start);
+}
+
+/*
+ * report on a badly formed entry
+ */
+void
+badentry(ep, msg)
+ register struct entry *ep;
+ char *msg;
+{
+
+ fprintf(stderr, "bad entry: %s\n", msg);
+ fprintf(stderr, "name: %s\n", myname(ep));
+ fprintf(stderr, "parent name %s\n", myname(ep->e_parent));
+ if (ep->e_sibling != NULL)
+ fprintf(stderr, "sibling name: %s\n", myname(ep->e_sibling));
+ if (ep->e_entries != NULL)
+ fprintf(stderr, "next entry name: %s\n", myname(ep->e_entries));
+ if (ep->e_links != NULL)
+ fprintf(stderr, "next link name: %s\n", myname(ep->e_links));
+ if (ep->e_next != NULL)
+ fprintf(stderr,
+ "next hashchain name: %s\n", myname(ep->e_next));
+ fprintf(stderr, "entry type: %s\n",
+ ep->e_type == NODE ? "NODE" : "LEAF");
+ fprintf(stderr, "inode number: %ld\n", ep->e_ino);
+ panic("flags: %s\n", flagvalues(ep));
+}
+
+/*
+ * Construct a string indicating the active flag bits of an entry.
+ */
+char *
+flagvalues(ep)
+ register struct entry *ep;
+{
+ static char flagbuf[BUFSIZ];
+
+ (void) strcpy(flagbuf, "|NIL");
+ flagbuf[0] = '\0';
+ if (ep->e_flags & REMOVED)
+ (void) strcat(flagbuf, "|REMOVED");
+ if (ep->e_flags & TMPNAME)
+ (void) strcat(flagbuf, "|TMPNAME");
+ if (ep->e_flags & EXTRACT)
+ (void) strcat(flagbuf, "|EXTRACT");
+ if (ep->e_flags & NEW)
+ (void) strcat(flagbuf, "|NEW");
+ if (ep->e_flags & KEEP)
+ (void) strcat(flagbuf, "|KEEP");
+ if (ep->e_flags & EXISTED)
+ (void) strcat(flagbuf, "|EXISTED");
+ return (&flagbuf[1]);
+}
+
+/*
+ * Check to see if a name is on a dump tape.
+ */
+ino_t
+dirlookup(name)
+ const char *name;
+{
+ struct direct *dp;
+ ino_t ino;
+
+ ino = ((dp = pathsearch(name)) == NULL) ? 0 : dp->d_ino;
+
+ if (ino == 0 || TSTINO(ino, dumpmap) == 0)
+ fprintf(stderr, "%s is not on the tape\n", name);
+ return (ino);
+}
+
+/*
+ * Elicit a reply.
+ */
+int
+reply(question)
+ char *question;
+{
+ char c;
+
+ do {
+ fprintf(stderr, "%s? [yn] ", question);
+ (void) fflush(stderr);
+ c = getc(terminal);
+ while (c != '\n' && getc(terminal) != '\n')
+ if (feof(terminal))
+ return (FAIL);
+ } while (c != 'y' && c != 'n');
+ if (c == 'y')
+ return (GOOD);
+ return (FAIL);
+}
+
+/*
+ * handle unexpected inconsistencies
+ */
+#if __STDC__
+#include <stdarg.h>
+#else
+#include <varargs.h>
+#endif
+
+void
+#if __STDC__
+panic(const char *fmt, ...)
+#else
+panic(fmt, va_alist)
+ char *fmt;
+ va_dcl
+#endif
+{
+ va_list ap;
+#if __STDC__
+ va_start(ap, fmt);
+#else
+ va_start(ap);
+#endif
+
+ vfprintf(stderr, fmt, ap);
+ if (yflag)
+ return;
+ if (reply("abort") == GOOD) {
+ if (reply("dump core") == GOOD)
+ abort();
+ done(1);
+ }
+}
--- /dev/null
+top_srcdir= @top_srcdir@
+srcdir= @srcdir@
+
+@MCONFIG@
+
+CFLAGS= @CCOPTS@ -pipe $(GINC) $(INC) $(DEFS)
+LDFLAGS:= $(LDFLAGS) @STATIC@
+LIBS= $(GLIBS)
+
+#DEBUG= -DFDEBUG -DTDEBUG -DWRITEDEBUG
+#INC= -I../compat/include
+#CFLAGS= -pipe $(DEFS) $(DEBUG) $(INC) $(GINC) $(OPT)
+#DEPLIBS= ../compat/lib/libcompat.a
+#LIBS= $(GLIBS) -L../compat/lib -lcompat
+
+PROG= rmt
+SRCS= rmt.c
+OBJS= rmt.o
+MAN8= rmt.8
+
+all:: $(PROG)
+
+$(PROG): $(OBJS) $(DEPLIBS)
+ $(CC) $(CFLAGS) $(LDFLAGS) -o $(PROG) $(OBJS) $(LIBS)
+
+install:: $(PROG)
+ $(INSTALLBIN) $(PROG) $(BINDIR)
+ $(INSTALLMAN) $(srcdir)/$(MAN8) $(MANDIR)
+
+clean::
+ rm -f $(PROG) \#* *.s *.o *.a *~ core
+
+distclean:: clean
+ rm -f Makefile Makefile.old .depend
+
+# +++ Dependency line eater +++
+#
+# Makefile dependencies follow. This must be the last section in
+# the Makefile.in file
+#
+
--- /dev/null
+.\" Copyright (c) 1983, 1991, 1993
+.\" The Regents of the University of California. All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\" notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\" notice, this list of conditions and the following disclaimer in the
+.\" documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\" must display the following acknowledgement:
+.\" This product includes software developed by the University of
+.\" California, Berkeley and its contributors.
+.\" 4. Neither the name of the University nor the names of its contributors
+.\" may be used to endorse or promote products derived from this software
+.\" without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+.\" SUCH DAMAGE.
+.\"
+.\" @(#)rmt.8 8.3 (Berkeley) 12/11/93
+.\"
+.Dd June 1, 1994
+.Dt RMT 8
+.Os BSD 4.2
+.Sh NAME
+.Nm rmt
+.Nd remote magtape protocol module
+.Sh SYNOPSIS
+.Nm rmt
+.Sh DESCRIPTION
+.Nm Rmt
+is a program used by the remote dump and restore programs
+in manipulating a magnetic tape drive through an interprocess
+communication connection.
+.Nm Rmt
+is normally started up with an
+.Xr rexec 3
+or
+.Xr rcmd 3
+call.
+.Pp
+The
+.Nm rmt
+program accepts requests specific to the manipulation of
+magnetic tapes, performs the commands, then responds with
+a status indication. All responses are in
+.Tn ASCII
+and in
+one of two forms.
+Successful commands have responses of:
+.Bd -filled -offset indent
+.Sm off
+.Sy A Ar number No \en
+.Sm on
+.Ed
+.Pp
+.Ar Number
+is an
+.Tn ASCII
+representation of a decimal number.
+Unsuccessful commands are responded to with:
+.Bd -filled -offset indent
+.Sm off
+.Xo Sy E Ar error-number
+.No \en Ar error-message
+.No \en
+.Xc
+.Sm on
+.Ed
+.Pp
+.Ar Error-number
+is one of the possible error
+numbers described in
+.Xr intro 2
+and
+.Ar error-message
+is the corresponding error string as printed
+from a call to
+.Xr perror 3 .
+The protocol is comprised of the
+following commands, which are sent as indicated - no spaces are supplied
+between the command and its arguments, or between its arguments, and
+.Ql \en
+indicates that a newline should be supplied:
+.Bl -tag -width Ds
+.Sm off
+.It Xo Sy \&O Ar device
+.No \en Ar mode No \en
+.Xc
+Open the specified
+.Ar device
+using the indicated
+.Ar mode .
+.Ar Device
+is a full pathname and
+.Ar mode
+is an
+.Tn ASCII
+representation of a decimal
+number suitable for passing to
+.Xr open 2 .
+If a device had already been opened, it is
+closed before a new open is performed.
+.It Xo Sy C Ar device No \en
+.Xc
+Close the currently open device. The
+.Ar device
+specified is ignored.
+.It Xo Sy L
+.Ar whence No \en
+.Ar offset No \en
+.Xc
+.Sm on
+Perform an
+.Xr lseek 2
+operation using the specified parameters.
+The response value is that returned from the
+.Xr lseek
+call.
+.Sm off
+.It Sy W Ar count No \en
+.Sm on
+Write data onto the open device.
+.Nm Rmt
+reads
+.Ar count
+bytes from the connection, aborting if
+a premature end-of-file is encountered.
+The response value is that returned from
+the
+.Xr write 2
+call.
+.Sm off
+.It Sy R Ar count No \en
+.Sm on
+Read
+.Ar count
+bytes of data from the open device.
+If
+.Ar count
+exceeds the size of the data buffer (10 kilobytes), it is
+truncated to the data buffer size.
+.Nm rmt
+then performs the requested
+.Xr read 2
+and responds with
+.Sm off
+.Sy A Ar count-read No \en
+.Sm on
+if the read was
+successful; otherwise an error in the
+standard format is returned. If the read
+was successful, the data read is then sent.
+.Sm off
+.It Xo Sy I Ar operation
+.No \en Ar count No \en
+.Xc
+.Sm on
+Perform a
+.Dv MTIOCOP
+.Xr ioctl 2
+command using the specified parameters.
+The parameters are interpreted as the
+.Tn ASCII
+representations of the decimal values
+to place in the
+.Ar mt_op
+and
+.Ar mt_count
+fields of the structure used in the
+.Xr ioctl
+call. The return value is the
+.Ar count
+parameter when the operation is successful.
+.ne 1i
+.It Sy S
+Return the status of the open device, as
+obtained with a
+.Dv MTIOCGET
+.Xr ioctl
+call. If the operation was successful,
+an ``ack'' is sent with the size of the
+status buffer, then the status buffer is
+sent (in binary).
+.El
+.Sm on
+.Pp
+Any other command causes
+.Nm rmt
+to exit.
+.Sh DIAGNOSTICS
+All responses are of the form described above.
+.Sh SEE ALSO
+.Xr rcmd 3 ,
+.Xr rexec 3 ,
+.Xr mtio 4 ,
+.Xr rdump 8 ,
+.Xr rrestore 8
+.Sh BUGS
+People should be discouraged from using this for a remote
+file access protocol.
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Bx 4.2 .
--- /dev/null
+/*
+ * Ported to Linux's Second Extended File System as part of the
+ * dump and restore backup suit
+ * Remy Card <card@Linux.EU.Org>, 1994, 1995, 1996
+ *
+ */
+
+/*
+ * Copyright (c) 1983, 1993
+ * The Regents of the University of California. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of
+ * California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef lint
+static char copyright[] =
+"@(#) Copyright (c) 1983, 1993\n\
+ The Regents of the University of California. All rights reserved.\n";
+#endif /* not lint */
+
+#ifndef lint
+static char sccsid[] = "@(#)rmt.c 8.1 (Berkeley) 6/6/93";
+#endif /* not lint */
+
+/*
+ * rmt
+ */
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/mtio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sgtty.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+int tape = -1;
+
+char *record;
+int maxrecsize = -1;
+
+#define SSIZE 64
+char device[SSIZE];
+char count[SSIZE], mode[SSIZE], pos[SSIZE], op[SSIZE];
+
+char resp[BUFSIZ];
+
+FILE *debug;
+#define DEBUG(f) if (debug) fprintf(debug, f)
+#define DEBUG1(f,a) if (debug) fprintf(debug, f, a)
+#define DEBUG2(f,a1,a2) if (debug) fprintf(debug, f, a1, a2)
+
+char *checkbuf __P((char *, int));
+void error __P((int));
+void getstring __P((char *));
+
+int
+main(argc, argv)
+ int argc;
+ char **argv;
+{
+ int rval;
+ char c;
+ int n, i, cc;
+
+ argc--, argv++;
+ if (argc > 0) {
+ debug = fopen(*argv, "w");
+ if (debug == 0)
+ exit(1);
+ (void)setbuf(debug, (char *)0);
+ }
+top:
+ errno = 0;
+ rval = 0;
+ if (read(0, &c, 1) != 1)
+ exit(0);
+ switch (c) {
+
+ case 'O':
+ if (tape >= 0)
+ (void) close(tape);
+ getstring(device);
+ getstring(mode);
+ DEBUG2("rmtd: O %s %s\n", device, mode);
+ tape = open(device, atoi(mode));
+ if (tape < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'C':
+ DEBUG("rmtd: C\n");
+ getstring(device); /* discard */
+ if (close(tape) < 0)
+ goto ioerror;
+ tape = -1;
+ goto respond;
+
+ case 'L':
+ getstring(count);
+ getstring(pos);
+ DEBUG2("rmtd: L %s %s\n", count, pos);
+ rval = lseek(tape, (off_t)atol(count), atoi(pos));
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'W':
+ getstring(count);
+ n = atoi(count);
+ DEBUG1("rmtd: W %s\n", count);
+ record = checkbuf(record, n);
+ for (i = 0; i < n; i += cc) {
+ cc = read(0, &record[i], n - i);
+ if (cc <= 0) {
+ DEBUG("rmtd: premature eof\n");
+ exit(2);
+ }
+ }
+ rval = write(tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ goto respond;
+
+ case 'R':
+ getstring(count);
+ DEBUG1("rmtd: R %s\n", count);
+ n = atoi(count);
+ record = checkbuf(record, n);
+ rval = read(tape, record, n);
+ if (rval < 0)
+ goto ioerror;
+ (void)sprintf(resp, "A%d\n", rval);
+ (void)write(1, resp, strlen(resp));
+ (void)write(1, record, rval);
+ goto top;
+
+ case 'I':
+ getstring(op);
+ getstring(count);
+ DEBUG2("rmtd: I %s %s\n", op, count);
+ { struct mtop mtop;
+ mtop.mt_op = atoi(op);
+ mtop.mt_count = atoi(count);
+ if (ioctl(tape, MTIOCTOP, (char *)&mtop) < 0)
+ goto ioerror;
+ rval = mtop.mt_count;
+ }
+ goto respond;
+
+ case 'S': /* status */
+ DEBUG("rmtd: S\n");
+ { struct mtget mtget;
+ if (ioctl(tape, MTIOCGET, (char *)&mtget) < 0)
+ goto ioerror;
+ rval = sizeof (mtget);
+ (void)sprintf(resp, "A%d\n", rval);
+ (void)write(1, resp, strlen(resp));
+ (void)write(1, (char *)&mtget, sizeof (mtget));
+ goto top;
+ }
+
+ default:
+ DEBUG1("rmtd: garbage command %c\n", c);
+ exit(3);
+ }
+respond:
+ DEBUG1("rmtd: A %d\n", rval);
+ (void)sprintf(resp, "A%d\n", rval);
+ (void)write(1, resp, strlen(resp));
+ goto top;
+ioerror:
+ error(errno);
+ goto top;
+}
+
+void
+getstring(bp)
+ char *bp;
+{
+ int i;
+ char *cp = bp;
+
+ for (i = 0; i < SSIZE; i++) {
+ if (read(0, cp+i, 1) != 1)
+ exit(0);
+ if (cp[i] == '\n')
+ break;
+ }
+ cp[i] = '\0';
+}
+
+char *
+checkbuf(record, size)
+ char *record;
+ int size;
+{
+
+ if (size <= maxrecsize)
+ return (record);
+ if (record != 0)
+ free(record);
+ record = malloc(size);
+ if (record == 0) {
+ DEBUG("rmtd: cannot allocate buffer space\n");
+ exit(4);
+ }
+ maxrecsize = size;
+ while (size > 1024 &&
+ setsockopt(0, SOL_SOCKET, SO_RCVBUF, &size, sizeof (size)) < 0)
+ size -= 1024;
+ return (record);
+}
+
+void
+error(num)
+ int num;
+{
+
+ DEBUG2("rmtd: E %d (%s)\n", num, strerror(num));
+ (void)sprintf(resp, "E%d\n%s\n", num, strerror(num));
+ (void)write(1, resp, strlen(resp));
+}