From 1227625a12a66e0ded78a1997c2d23f23202a382 Mon Sep 17 00:00:00 2001 From: Stelian Pop Date: Mon, 11 Oct 1999 12:20:19 +0000 Subject: [PATCH] Initial revision --- CHANGES | 119 ++ COPYRIGHT | 39 + INSTALL | 15 + KNOWNBUGS | 11 + MCONFIG.in | 97 ++ Makefile.in | 23 + README | 9 + THANKS | 30 + TODO | 13 + acconfig.h | 5 + common/Makefile.in | 26 + common/dumprmt.c | 390 +++++ compat/include/bsdcompat.h | 232 +++ compat/include/err.h | 69 + compat/include/fstab.h | 87 + compat/include/glob.h | 97 ++ compat/include/pathnames.h | 49 + compat/include/protocols/dumprestore.h | 123 ++ compat/include/tzfile.h | 158 ++ compat/lib/Makefile.in | 31 + compat/lib/err.c | 211 +++ compat/lib/fstab.c | 175 ++ compat/lib/glob.c | 853 ++++++++++ config.guess | 565 +++++++ config.h.in | 37 + config.sub | 866 ++++++++++ configure | 2144 ++++++++++++++++++++++++ configure.in | 245 +++ debian-patch | 178 ++ depfix.sed | 33 + dump-0.2.announce | 41 + dump-0.2a.announce | 27 + dump-0.2b.announce | 28 + dump-0.2c.announce | 12 + dump-0.2d.announce | 12 + dump-0.2e.announce | 19 + dump-0.3.announce | 32 + dump-0.4b1.announce | 35 + dump.lsm | 18 + dump/Makefile.in | 49 + dump/dump.8 | 364 ++++ dump/dump.h | 244 +++ dump/itime.c | 296 ++++ dump/main.c | 711 ++++++++ dump/optr.c | 586 +++++++ dump/tape.c | 915 ++++++++++ dump/traverse.c | 1100 ++++++++++++ dump/unctime.c | 113 ++ install-sh | 238 +++ linux-1.2.x.patch | 17 + restore/Makefile.in | 50 + restore/dirs.c | 817 +++++++++ restore/extern.h | 117 ++ restore/interactive.c | 812 +++++++++ restore/main.c | 417 +++++ restore/restore.8 | 467 ++++++ restore/restore.c | 952 +++++++++++ restore/restore.h | 156 ++ restore/symtab.c | 645 +++++++ restore/tape.c | 1689 +++++++++++++++++++ restore/utilities.c | 456 +++++ rmt/Makefile.in | 41 + rmt/rmt.8 | 218 +++ rmt/rmt.c | 251 +++ 64 files changed, 18875 insertions(+) create mode 100644 CHANGES create mode 100644 COPYRIGHT create mode 100644 INSTALL create mode 100644 KNOWNBUGS create mode 100644 MCONFIG.in create mode 100644 Makefile.in create mode 100644 README create mode 100644 THANKS create mode 100644 TODO create mode 100644 acconfig.h create mode 100644 common/Makefile.in create mode 100644 common/dumprmt.c create mode 100644 compat/include/bsdcompat.h create mode 100644 compat/include/err.h create mode 100644 compat/include/fstab.h create mode 100644 compat/include/glob.h create mode 100644 compat/include/pathnames.h create mode 100644 compat/include/protocols/dumprestore.h create mode 100644 compat/include/tzfile.h create mode 100644 compat/lib/Makefile.in create mode 100644 compat/lib/err.c create mode 100644 compat/lib/fstab.c create mode 100644 compat/lib/glob.c create mode 100755 config.guess create mode 100644 config.h.in create mode 100755 config.sub create mode 100755 configure create mode 100644 configure.in create mode 100644 debian-patch create mode 100644 depfix.sed create mode 100644 dump-0.2.announce create mode 100644 dump-0.2a.announce create mode 100644 dump-0.2b.announce create mode 100644 dump-0.2c.announce create mode 100644 dump-0.2d.announce create mode 100644 dump-0.2e.announce create mode 100644 dump-0.3.announce create mode 100644 dump-0.4b1.announce create mode 100644 dump.lsm create mode 100644 dump/Makefile.in create mode 100644 dump/dump.8 create mode 100644 dump/dump.h create mode 100644 dump/itime.c create mode 100644 dump/main.c create mode 100644 dump/optr.c create mode 100644 dump/tape.c create mode 100644 dump/traverse.c create mode 100644 dump/unctime.c create mode 100755 install-sh create mode 100644 linux-1.2.x.patch create mode 100644 restore/Makefile.in create mode 100644 restore/dirs.c create mode 100644 restore/extern.h create mode 100644 restore/interactive.c create mode 100644 restore/main.c create mode 100644 restore/restore.8 create mode 100644 restore/restore.c create mode 100644 restore/restore.h create mode 100644 restore/symtab.c create mode 100644 restore/tape.c create mode 100644 restore/utilities.c create mode 100644 rmt/Makefile.in create mode 100644 rmt/rmt.8 create mode 100644 rmt/rmt.c diff --git a/CHANGES b/CHANGES new file mode 100644 index 0000000..301bf72 --- /dev/null +++ b/CHANGES @@ -0,0 +1,119 @@ + +Changes between versions 0.4b3 and 0.4b4 +======================================== + +1. Dump now runs correctly on kernels 2.1.x + Fix made by Gerald Peters + +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. diff --git a/COPYRIGHT b/COPYRIGHT new file mode 100644 index 0000000..ce4bd12 --- /dev/null +++ b/COPYRIGHT @@ -0,0 +1,39 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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. + */ diff --git a/INSTALL b/INSTALL new file mode 100644 index 0000000..c8caa1f --- /dev/null +++ b/INSTALL @@ -0,0 +1,15 @@ + + 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. diff --git a/KNOWNBUGS b/KNOWNBUGS new file mode 100644 index 0000000..61d3a3e --- /dev/null +++ b/KNOWNBUGS @@ -0,0 +1,11 @@ +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. diff --git a/MCONFIG.in b/MCONFIG.in new file mode 100644 index 0000000..f3ab85f --- /dev/null +++ b/MCONFIG.in @@ -0,0 +1,97 @@ +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 diff --git a/Makefile.in b/Makefile.in new file mode 100644 index 0000000..68e861e --- /dev/null +++ b/Makefile.in @@ -0,0 +1,23 @@ +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 +# + diff --git a/README b/README new file mode 100644 index 0000000..24b7fc5 --- /dev/null +++ b/README @@ -0,0 +1,9 @@ + + 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. diff --git a/THANKS b/THANKS new file mode 100644 index 0000000..1ffb24a --- /dev/null +++ b/THANKS @@ -0,0 +1,30 @@ +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 , by using +the Ext2fs library, written by Theodore Ts'o . + +Kevin Layer added the comparison code in restore. + +Doug Paul helped me to make dump able to backup 2GB+ +filesystems. + +David Frey (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 diff --git a/TODO b/TODO new file mode 100644 index 0000000..03a2efc --- /dev/null +++ b/TODO @@ -0,0 +1,13 @@ +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. diff --git a/acconfig.h b/acconfig.h new file mode 100644 index 0000000..761eb13 --- /dev/null +++ b/acconfig.h @@ -0,0 +1,5 @@ +/* Define to __s64 if does not define */ +#undef quad_t + +/* Define to __u64 if does not define */ +#undef u_quad_t diff --git a/common/Makefile.in b/common/Makefile.in new file mode 100644 index 0000000..d6a3348 --- /dev/null +++ b/common/Makefile.in @@ -0,0 +1,26 @@ +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 +# + diff --git a/common/dumprmt.c b/common/dumprmt.c new file mode 100644 index 0000000..cdb79c1 --- /dev/null +++ b/common/dumprmt.c @@ -0,0 +1,390 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#include +#include +#ifdef __linux__ +#include +#include +#else +#ifdef sunos +#include + +#include +#else +#include +#endif +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#include +#include +#endif + +#ifdef __linux__ +#include +#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(); +} diff --git a/compat/include/bsdcompat.h b/compat/include/bsdcompat.h new file mode 100644 index 0000000..c697cab --- /dev/null +++ b/compat/include/bsdcompat.h @@ -0,0 +1,232 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 1994, 1995, 1996 + * + */ + +#include + +#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 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 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] diff --git a/compat/include/err.h b/compat/include/err.h new file mode 100644 index 0000000..6b23d13 --- /dev/null +++ b/compat/include/err.h @@ -0,0 +1,69 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 + +#include + +#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_ */ diff --git a/compat/include/fstab.h b/compat/include/fstab.h new file mode 100644 index 0000000..5b00e7a --- /dev/null +++ b/compat/include/fstab.h @@ -0,0 +1,87 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 + +__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_ */ diff --git a/compat/include/glob.h b/compat/include/glob.h new file mode 100644 index 0000000..5cb9c54 --- /dev/null +++ b/compat/include/glob.h @@ -0,0 +1,97 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 + +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_ */ diff --git a/compat/include/pathnames.h b/compat/include/pathnames.h new file mode 100644 index 0000000..a4f4267 --- /dev/null +++ b/compat/include/pathnames.h @@ -0,0 +1,49 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 + +#define _PATH_DEFTAPE "/dev/rmt8" +#define _PATH_DTMP "/etc/dtmp" +#define _PATH_DUMPDATES "/etc/dumpdates" +#define _PATH_LOCK "/tmp/dumplockXXXXXX" +#define _PATH_RMT "rmt" diff --git a/compat/include/protocols/dumprestore.h b/compat/include/protocols/dumprestore.h new file mode 100644 index 0000000..ef74c39 --- /dev/null +++ b/compat/include/protocols/dumprestore.h @@ -0,0 +1,123 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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_ */ diff --git a/compat/include/tzfile.h b/compat/include/tzfile.h new file mode 100644 index 0000000..a9f934c --- /dev/null +++ b/compat/include/tzfile.h @@ -0,0 +1,158 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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_ */ diff --git a/compat/lib/Makefile.in b/compat/lib/Makefile.in new file mode 100644 index 0000000..c5ba683 --- /dev/null +++ b/compat/lib/Makefile.in @@ -0,0 +1,31 @@ +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 +# + diff --git a/compat/lib/err.c b/compat/lib/err.c new file mode 100644 index 0000000..71aaadc --- /dev/null +++ b/compat/lib/err.c @@ -0,0 +1,211 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#include +#include + +#ifdef __STDC__ +#include +#else +#include +#endif + +#include + +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 diff --git a/compat/lib/fstab.c b/compat/lib/fstab.c new file mode 100644 index 0000000..0cd2250 --- /dev/null +++ b/compat/lib/fstab.c @@ -0,0 +1,175 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#include +#include +#include +#include + +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); +} diff --git a/compat/lib/glob.c b/compat/lib/glob.c new file mode 100644 index 0000000..ba6f22f --- /dev/null +++ b/compat/lib/glob.c @@ -0,0 +1,853 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 diff --git a/config.guess b/config.guess new file mode 100755 index 0000000..2ff0eba --- /dev/null +++ b/config.guess @@ -0,0 +1,565 @@ +#! /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 . +# 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 + + 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 + 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 </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' /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 < +# include +#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 + 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 diff --git a/config.h.in b/config.h.in new file mode 100644 index 0000000..817ce66 --- /dev/null +++ b/config.h.in @@ -0,0 +1,37 @@ +/* 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 does not define */ +#undef quad_t + +/* Define to __u64 if 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 diff --git a/config.sub b/config.sub new file mode 100755 index 0000000..93371be --- /dev/null +++ b/config.sub @@ -0,0 +1,866 @@ +#! /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 diff --git a/configure b/configure new file mode 100755 index 0000000..53be0bb --- /dev/null +++ b/configure @@ -0,0 +1,2144 @@ +#! /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 <&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 <&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 < +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 < +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 +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 <&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 < +/* 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 <&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 < +#include +#include +#include +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 +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 +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 < +#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 < +#if STDC_HEADERS +#include +#include +#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 < +#if STDC_HEADERS +#include +#include +#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 </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 < 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 <> $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 <> $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 <> $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 <> $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 + diff --git a/configure.in b/configure.in new file mode 100644 index 0000000..3ef741e --- /dev/null +++ b/configure.in @@ -0,0 +1,245 @@ +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) diff --git a/debian-patch b/debian-patch new file mode 100644 index 0000000..b0349f2 --- /dev/null +++ b/debian-patch @@ -0,0 +1,178 @@ +--- 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 , 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 , 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 , 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); ++ } + } + } + diff --git a/depfix.sed b/depfix.sed new file mode 100644 index 0000000..1bcf112 --- /dev/null +++ b/depfix.sed @@ -0,0 +1,33 @@ +# +# 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\ + diff --git a/dump-0.2.announce b/dump-0.2.announce new file mode 100644 index 0000000..9ddec37 --- /dev/null +++ b/dump-0.2.announce @@ -0,0 +1,41 @@ + + 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 diff --git a/dump-0.2a.announce b/dump-0.2a.announce new file mode 100644 index 0000000..130ac8a --- /dev/null +++ b/dump-0.2a.announce @@ -0,0 +1,27 @@ + + 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 , Bob Snyder +, and Florian La Roche for +their reports and their help! + +-- +Remy Card +Remy.Card@freenix.fr diff --git a/dump-0.2b.announce b/dump-0.2b.announce new file mode 100644 index 0000000..b378ec4 --- /dev/null +++ b/dump-0.2b.announce @@ -0,0 +1,28 @@ + + 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 , Bob Snyder +, and Florian La Roche for +their reports and their help! + +-- +Remy Card +Remy.Card@freenix.fr diff --git a/dump-0.2c.announce b/dump-0.2c.announce new file mode 100644 index 0000000..d0da6b7 --- /dev/null +++ b/dump-0.2c.announce @@ -0,0 +1,12 @@ + + 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 diff --git a/dump-0.2d.announce b/dump-0.2d.announce new file mode 100644 index 0000000..afc10d5 --- /dev/null +++ b/dump-0.2d.announce @@ -0,0 +1,12 @@ + + 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 + 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 diff --git a/dump-0.2e.announce b/dump-0.2e.announce new file mode 100644 index 0000000..cdf5c0b --- /dev/null +++ b/dump-0.2e.announce @@ -0,0 +1,19 @@ + + 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 + 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! diff --git a/dump-0.3.announce b/dump-0.3.announce new file mode 100644 index 0000000..c5ebc2a --- /dev/null +++ b/dump-0.3.announce @@ -0,0 +1,32 @@ + + 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 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 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 + for sending me a patch much cleaner than mine :-) + + Kevin Layer 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! diff --git a/dump-0.4b1.announce b/dump-0.4b1.announce new file mode 100644 index 0000000..9054672 --- /dev/null +++ b/dump-0.4b1.announce @@ -0,0 +1,35 @@ + + 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 + diff --git a/dump.lsm b/dump.lsm new file mode 100644 index 0000000..6aadaf4 --- /dev/null +++ b/dump.lsm @@ -0,0 +1,18 @@ +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 diff --git a/dump/Makefile.in b/dump/Makefile.in new file mode 100644 index 0000000..71435b0 --- /dev/null +++ b/dump/Makefile.in @@ -0,0 +1,49 @@ +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 +# + diff --git a/dump/dump.8 b/dump/dump.8 new file mode 100644 index 0000000..fae652b --- /dev/null +++ b/dump/dump.8 @@ -0,0 +1,364 @@ +.\" 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. diff --git a/dump/dump.h b/dump/dump.h new file mode 100644 index 0000000..73882dc --- /dev/null +++ b/dump/dump.h @@ -0,0 +1,244 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#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 +#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 diff --git a/dump/itime.c b/dump/itime.c new file mode 100644 index 0000000..f83459c --- /dev/null +++ b/dump/itime.c @@ -0,0 +1,296 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#ifdef __linux__ +#include +#include +#include +#else +#ifdef sunos +#include + +#include +#include +#include +#else +#include +#endif +#endif + +#include + +#include +#include +#include +#ifdef __STDC__ +#include +#include +#include +#endif + +#ifdef __linux__ +#include +#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); +} diff --git a/dump/main.c b/dump/main.c new file mode 100644 index 0000000..c09e6b8 --- /dev/null +++ b/dump/main.c @@ -0,0 +1,711 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#ifdef __linux__ +#include +#include +#include +#else +#ifdef sunos +#include + +#include +#include +#else +#include +#include +#endif +#endif + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#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; +} diff --git a/dump/optr.c b/dump/optr.c new file mode 100644 index 0000000..4d23242 --- /dev/null +++ b/dump/optr.c @@ -0,0 +1,586 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include + +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#include +#include +#endif +#include +#ifdef __STDC__ +#include +#endif +#include +#ifndef __STDC__ +#include +#endif + +#ifdef __linux__ +#include +#include +#include +#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); +} diff --git a/dump/tape.c b/dump/tape.c new file mode 100644 index 0000000..ce15056 --- /dev/null +++ b/dump/tape.c @@ -0,0 +1,915 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#include +#ifdef __linux__ +#include +#include +#else /* __linux__ */ +#ifdef sunos +#include + +#include +#include +#else +#include +#include +#endif +#endif /* __linux__ */ + +#include + +#include +#include +#include +#include +#include +#ifdef __STDC__ +#include +#include +#include +#else +int write(), read(); +#endif + +#ifdef __linux__ +#include +#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); +} diff --git a/dump/traverse.c b/dump/traverse.c new file mode 100644 index 0000000..ccc03f7 --- /dev/null +++ b/dump/traverse.c @@ -0,0 +1,1100 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#ifdef __linux__ +#include +#include +#include +#include +#else /* __linux__ */ +#ifdef sunos +#include + +#include +#include +#include +#else +#include +#include +#include +#endif +#endif /* __linux__ */ + +#include + +#include +#include +#ifdef __STDC__ +#include +#include +#endif + +#ifdef __linux__ +#include +#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); + } +} diff --git a/dump/unctime.c b/dump/unctime.c new file mode 100644 index 0000000..eccc509 --- /dev/null +++ b/dump/unctime.c @@ -0,0 +1,113 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 + +#include +#include +#ifdef __STDC__ +#include +#include +#endif + +#ifndef __P +#include +#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); +} diff --git a/install-sh b/install-sh new file mode 100755 index 0000000..89fc9b0 --- /dev/null +++ b/install-sh @@ -0,0 +1,238 @@ +#! /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 diff --git a/linux-1.2.x.patch b/linux-1.2.x.patch new file mode 100644 index 0000000..a313a0c --- /dev/null +++ b/linux-1.2.x.patch @@ -0,0 +1,17 @@ +--- 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; + } diff --git a/restore/Makefile.in b/restore/Makefile.in new file mode 100644 index 0000000..dff9e1f --- /dev/null +++ b/restore/Makefile.in @@ -0,0 +1,50 @@ +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 +# + diff --git a/restore/dirs.c b/restore/dirs.c new file mode 100644 index 0000000..78285ad --- /dev/null +++ b/restore/dirs.c @@ -0,0 +1,817 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#include + +#ifdef __linux__ +#include +#include +#else /* __linux__ */ +#include +#include +#include +#endif /* __linux__ */ +#include + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#else +#include +#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 = ""; + 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); +} diff --git a/restore/extern.h b/restore/extern.h new file mode 100644 index 0000000..54b37ab --- /dev/null +++ b/restore/extern.h @@ -0,0 +1,117 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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)); diff --git a/restore/interactive.c b/restore/interactive.c new file mode 100644 index 0000000..c7b730b --- /dev/null +++ b/restore/interactive.c @@ -0,0 +1,812 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include + +#ifdef __linux__ +#include +#include +#else /* __linux__ */ +#include +#include +#include +#endif /* __linux__ */ +#include + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#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 +#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); +} diff --git a/restore/main.c b/restore/main.c new file mode 100644 index 0000000..6f4098d --- /dev/null +++ b/restore/main.c @@ -0,0 +1,417 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include + +#ifdef __linux__ +#include +#include +#else /* __linux__ */ +#include +#include +#endif /* __linux__ */ +#include + +#include +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#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; +} diff --git a/restore/restore.8 b/restore/restore.8 new file mode 100644 index 0000000..785a6c3 --- /dev/null +++ b/restore/restore.8 @@ -0,0 +1,467 @@ +.\" 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 : 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 , got +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 +.It Tape read error while skipping over inode +.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 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 . diff --git a/restore/restore.c b/restore/restore.c new file mode 100644 index 0000000..533ae5b --- /dev/null +++ b/restore/restore.c @@ -0,0 +1,952 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include + +#ifdef __linux__ +#include +#include +#include +#else /* __linux__ */ +#include +#endif /* __linux__ */ + +#include +#include + +#ifdef __linux__ +#include +#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); +} diff --git a/restore/restore.h b/restore/restore.h new file mode 100644 index 0000000..1cef2d9 --- /dev/null +++ b/restore/restore.h @@ -0,0 +1,156 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 diff --git a/restore/symtab.c b/restore/symtab.c new file mode 100644 index 0000000..d9d9a2e --- /dev/null +++ b/restore/symtab.c @@ -0,0 +1,645 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include + +#ifdef __linux__ +#include +#include +#include +#else /* __linux__ */ +#include +#endif /* __linux__ */ + +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#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]; + } +} diff --git a/restore/tape.c b/restore/tape.c new file mode 100644 index 0000000..b00c4bb --- /dev/null +++ b/restore/tape.c @@ -0,0 +1,1689 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#include +#include + +#ifdef __linux__ +#include +#include +#include +#else /* __linux__ */ +#include +#endif /* __linux__ */ +#include + +#include +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#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 = ""; + 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/ */ + { + 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 = ""; + 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 = ""; + break; + + case TS_BITS: + curfile.name = ""; + 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 +#else +#include +#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); +} diff --git a/restore/utilities.c b/restore/utilities.c new file mode 100644 index 0000000..54b7dc1 --- /dev/null +++ b/restore/utilities.c @@ -0,0 +1,456 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include + +#ifdef __linux__ +#include +#include +#include +#else /* __linux__ */ +#include +#include +#endif /* __linux__ */ + +#include +#include +#include +#include +#include + +#ifdef __linux__ +#include +#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 +#else +#include +#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); + } +} diff --git a/rmt/Makefile.in b/rmt/Makefile.in new file mode 100644 index 0000000..8cc2286 --- /dev/null +++ b/rmt/Makefile.in @@ -0,0 +1,41 @@ +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 +# + diff --git a/rmt/rmt.8 b/rmt/rmt.8 new file mode 100644 index 0000000..7bee3db --- /dev/null +++ b/rmt/rmt.8 @@ -0,0 +1,218 @@ +.\" 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 . diff --git a/rmt/rmt.c b/rmt/rmt.c new file mode 100644 index 0000000..74116b0 --- /dev/null +++ b/rmt/rmt.c @@ -0,0 +1,251 @@ +/* + * Ported to Linux's Second Extended File System as part of the + * dump and restore backup suit + * Remy Card , 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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)); +} -- 2.39.2