rdup-1.1.15/000077500000000000000000000000001303430127500125475ustar00rootroot00000000000000rdup-1.1.15/.travis.yml000066400000000000000000000003721303430127500146620ustar00rootroot00000000000000language: c compiler: - clang - gcc install: - sudo apt-get -qq update - sudo apt-get install -y libarchive-dev nettle-dev dejagnu expect mcrypt script: - rm -Rf ~/.gnupg # Skip gpg tests - autoreconf && ./configure && make && make check rdup-1.1.15/AUTHORS000066400000000000000000000006371303430127500136250ustar00rootroot00000000000000# Authors: * Miek Gieben * Tom Hendrikx # Ideas/Patches/Testing * Aaron Bader * Boris Goldowsky * Bram de Kruijff - testing/feedback * Charlie Kester * Erland Isaksson * Fabio Rossi * Freek Kauffmann * Ghostcorps (at) gmail.com * Jan Spakula * John Goerzen * Mark J Hewitt - original perl scripts * Rado Hrabcak * Robert Haskins - Solaris testing/feedback * Timur Vafin * Alejandro Pulver * Richard Kojedzinszky rdup-1.1.15/ChangeLog000066400000000000000000000122321303430127500143210ustar00rootroot00000000000000xx Yyy 2013: 1.1.15 Miek Gieben * [rdup] Change -P so any arguments are executed with 'sh -c', this removes the 7 option limit (Alexander Neumann) * [rdup-tr] Fix crashes with filename encryption and symlinks (reported by Jakob Fink) * [rdup-tr] Fix memory leak * [rdup] Fix the linked list that tracks the child's PIDs. * [rdup] Drop -a option, it's racy and must proper or not at all. 19 Jan 2013: 1.1.14 Miek Gieben * [rdup] check for the existence of ._rdup_. files and parse its contents to restore the actual files' ownership (Miek Gieben) * [rdup-up] save user/group info in ._rdup_. files when chown(1)ing has failed. Useful when backing up via sshfs. See rdup(1) "Non-root backups" (Miek Gieben) * [rdup-up] add -u flag to suppress creating these ._rdup_. files. (useful when restoring) (Miek Gieben) * [rdup] add -u flag to suppress interpreting these ._rdup_. files. (Miek Gieben) * [rdup-tr] compile fix when compiling with gcc 4.7 (reported by D. L.) * [rdup-tr] honor the TMPDIR environment variable (Miek Gieben) * [rdup] Don't look at the device ID when deciding if a file needs to be backed up (See https://github.com/miekg/rdup/issues/3) 18 Feb 2012: 1.1.13 Miek Gieben * Make rdup-tr compile when libnettle was not found (Miek Gieben) * Fix for very large inodes and filesizes (Kojedzinszky Richard) * Fix tar/pax output when the filesize of files changes (rdup -Pgzip for instance) (Reported by: Alejandro Pulver). This created files padded with zero bytes. 21 Jan 2012: 1.1.12 Miek Gieben * Test suite fixed * Fix Debian bug 627617 18 Feb 2011. 1.1.11 Miek Gieben * Polish * rdup-up: added -q option. Be quiet when chown fails even when root (handy for backups on sshfs) 05 Dec 2010: 1.1.10 Miek Gieben * One memleak fix removed (Tom Hendrikx) 04 Dec 2010: 1.1.9 Miek Gieben * Fix whooping amount of memleaks (rdup-tr, rdup-up) (Crispin Boylan) 24 Oct 2010: 1.1.8 Miek Gieben * rdup: Check for two more I/O errors when reading files * rdup: Permission fix for AIX (Crispin Boylan) * autoconf: Fix dirfd detection on mac OS X (still does not work) 21 Jun 2010: 1.1.7 Miek Gieben * rdup-up: also create named pipes (fifo) 18 May 2010: 1.1.6 Miek Gieben * rdup-simple: cleanups + portability 09 Apr 2010: 1.1.5 Miek Gieben * compile fix 04 Apr 2010: 1.1.4 Miek Gieben * re-touch timestamp after the backup is made when -a is used, otherwise it is done before the backup * spring cleaning, remove/clean BUGBUGs and some dead code and polish the documentation a bit * revert changes in mkpath.c to make FreeBSD happy * fix hardlinks in tar/pax output (they must come last) 22 Mar 2010: 1.1.3 Miek Gieben * rdup: fix reset atime (-a) * rdup-simple: add -a (reset atime flag) * documentation bugfixes 14 Mar 2010: 1.1.2 Miek Gieben * rdup: remove sig_atomic_t (build fix for ubuntu 8.04) (reported by Andrew Ittner) * rdup-up: fixed nasty bug in dir.c dir_parent() (leave caller's string alone) * rdup-up: rm.c: also use dir_parent() * tests: a 'fail'ing gpg test is now 'unresolved' * Added contrib/ directory and added prune.rb script (prune.rb provided by Matthias-Christian Ott) 2 Mar 2010: 1.1.1 Miek Gieben * tests: Skip gpg test when gpg is not found (Tom) * rdup: Rename strmode() to rdup_strmode for FreeBSD (Charlie Kester) * rdup: Dont descend when toplevel directory is a symlink (same behavoir as Gnu tar) (Reported by Charlie Kester) * rdup: reap our childeren with waitpid() (Oliver Dain) * build: Building fix on rpm distros (SuSE/Fedora) (Sven Hartrumpf) * build: add --enable-debug to build debug build 24 Jan 2010: 1.1.0 Miek Gieben * Release! * Tweaks and merges from the master branch * Remember: installs in /usr/local 22 Dec 2009: 1.1.0-rc1 Miek Gieben * First release of the 1.1.0 branch * format change: %U, %G and %t added * default install path: /usr/local/ * rdup: -a restore atime when reading files * rdup: -P is moved from rdup-tr Todo: * documentation * more testing 14 Dec 2009: 1.1.0-dev1 Miek * rdup added: - -a: reset atime * rdup-up: - set mtime * revert back to libnettle - and back to AES encryption 09 Aug 2009: 1.1.0-dev0 Miek * Format change: add username, groupname and mtime Always output the files' contents %U username %G groupname %t is mtime of the fs object * Adapt all utils to this format change - rdup now handles -P itself - rdup is the only tool that accesses the files - rdup-tr does not do -P anymore - rdup-tr only processes from stdin to stdout - rdup-up only processes stdin * Loads of code cleanups * Use OpenSSL in favor of libnettle - AES encryption is replaced by blowfish * Change default install path /usr/local (Sebastian Kügler) rdup-1.1.15/DEPENDENCIES000066400000000000000000000012471303430127500143240ustar00rootroot00000000000000rdup is a small program, which depends on a number of a other programs and tools to make it all work. The dependencies are listed here: Mandatory: * libglib (core C gtk library) * libpcre (Perl regular expressions) * libnettle (Nettle - small crypto library) * libarchive (Create tar/cpio/etc archive - used in rdup-tr) If libarchive is not found rdup-tr is not built. To build from git: autoconf && ./configure && make && make install from tar.bz2: ./configure && make && make install To run the testsuite: make check DejaGNU is used for the testsuite. Some small shell scripts are included in the sh/ directory they depend on bash, GNU date and GNU cp. rdup-1.1.15/GNUmakefile.in000066400000000000000000000063731303430127500152370ustar00rootroot00000000000000OBJ=crawler.o rdup.o gfunc.o getdelim.o signal.o usage.o sha1.o regexp.o abspath.o link.o reverse.o protocol.o msg.o common.o names.o child.o chown.o OBJ_TR=rdup-tr.o signal.o getdelim.o usage-tr.o entry.o link.o protocol.o msg.o crypt.o base64.o common.o OBJ_UP=rdup-up.o entry.o usage-up.o signal.o link.o getdelim.o abspath.o rm.o fs-up.o mkpath.o protocol.o msg.o dir.o common.o strippath.o names.o chown.o HDR=rdup.h rdup-tr.h rdup-up.h io.h common.h entry.h CMD=rdup rdup-tr rdup-up SH=rdup-simple MAN1_IN=rdup.1 rdup-tr.1 rdup-up.1 rdup-simple.1 MAN7_IN=rdup-backups.7 MAN1=$(addprefix doc/, $(MAN1_IN)) MAN7=$(addprefix doc/, $(MAN7_IN)) prefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir=@datarootdir@ localedir=@localedir@ bindir=@bindir@ libdir=@libdir@ sbindir=@sbindir@ mandir=@mandir@ sysconfdir=@sysconfdir@ datadir=@datadir@/rdup ARCHIVE_L=@ARCHIVE_L@ NETTLE_L=@NETTLE_L@ GCC=@CC@ GLIB_CFLAGS=@GLIB_CFLAGS@ GLIB_LIBS=@GLIB_LIBS@ LIBS=@LIBS@ DEBUG=@DEBUG@ CFLAGS=-Wall -W -Werror @CFLAGS@ @DEFS@ -DLOCALEROOTDIR=\"@localedir@\" -D_FILE_OFFSET_BITS=64 -D_LARGE_FILES -Os -Wpointer-arith -Wstrict-prototypes INSTALL=./install-sh -c INSTALL_DATA=$(INSTALL) -m 644 .PHONY: all clean install all uninstall strip %.o: %.c ${HDR} ${GCC} ${CFLAGS} ${GLIB_CFLAGS} -c $< ifeq (${ARCHIVE_L},no) all: rdup rdup-up @echo "WARNING: ** No archive library found; not building rdup-tr" else all: rdup rdup-up rdup-tr endif @chmod +x ${SH} @if [ "${NETTLE_L}" = "no" ]; then echo "WARNING: ** No nettle library found; rdup-tr has no encryption"; fi rdup-up: $(OBJ_UP) $(HDR) ${GCC} ${OBJ_UP} ${GLIB_LIBS} ${LDFLAGS} ${LIBS} -o rdup-up rdup-tr: $(OBJ_TR) $(HDR) ${GCC} ${OBJ_TR} ${GLIB_LIBS} ${LDFLAGS} ${LIBS} -o rdup-tr rdup: ${OBJ} ${HDR} ${GCC} ${OBJ} ${GLIB_LIBS} ${LDFLAGS} ${LIBS} -o rdup strip: rdup rdup-up ifneq (${ARCHIVE_L},no) strip: rdup-tr endif strip $^ po: rdup.pot ( cd po ; $(MAKE) -f GNUmakefile all ) rdup.pot: ${OBJ} ${OBJ_TR} ${OBJ_UP} xgettext --omit-header -k_ -d rdup -s -o rdup.pot *.c TAGS: *.[ch] ctags *.[ch] clean: rm -f *.o rm -f rdup.mo ${CMD} ( cd po ; $(MAKE) -f GNUmakefile clean ) realclean: clean rm -rf autom4te.cache rm -f config.log rm -f config.status rm -f config.h rm -f rdup.h rm -f rdup-tr.h rm -f rdup-up.h rm -f rdup*.tar.bz2 rm -f rdup*.tar.bz2.sha1 rm -f ${MAN1} $(MAKE) -C po realclean distclean: install: all mkdir -p ${DESTDIR}${mandir}/man1 # mkdir -p ${DESTDIR}${datadir} for i in ${CMD}; do ${INSTALL} $$i ${DESTDIR}${bindir}/$$i ; done for i in ${SH}; do ${INSTALL} $$i ${DESTDIR}${bindir}/$$i ; done for i in ${MAN1}; do [ -f $$i ] && ${INSTALL_DATA} $$i ${DESTDIR}${mandir}/man1/`basename $$i` ; done; exit 0 for i in ${MAN7}; do [ -f $$i ] && ${INSTALL_DATA} $$i ${DESTDIR}${mandir}/man7/`basename $$i` ; done; exit 0 $(MAKE) -C po install install-strip: all strip install uninstall: for i in ${CMD}; do rm -f ${DESTDIR}${bindir}/$$i ; done for i in ${SH}; do rm -f ${DESTDIR}${bindir}/$$i ; done for i in ${MAN1}; do rm -f ${DESTDIR}${mandir}/man1/`basename $$i` ; done for i in ${MAN7}; do rm -f ${DESTDIR}${mandir}/man7/`basename $$i` ; done $(MAKE) -C po uninstall check: all @[ -d testlogs ] || mkdir testlogs @chmod +x testsuite/rdup/rdup*helper runtest @chmod -x testlogs/rdup.log rdup-1.1.15/LICENSE000066400000000000000000001043741303430127500135650ustar00rootroot00000000000000 GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program 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 3 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, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . rdup-1.1.15/README000066400000000000000000000044751303430127500134410ustar00rootroot00000000000000# TO BUILD Run: autoreconf && ./configure && make Then a: make install as root, to get `rdup` installed. Optionally you can also do a: make check to run the test suite, note that you will need DejaGNU installed for this to work. If you find errors in this testrun, please look at testlogs/rdup.log and send that to the author. rdup depends on: * Gmake for compilation * Glib to build. Glib is the low level C library of the GTK project. Configure will check for this. * PCRE library * LibNettle - if you want rdup-tr to do path encryption and for sha hashing optional: * Libarchive - if you want to have rdup-tr rdup should compile on all unix platforms out there. It is tested on the following * Linux * Solaris * FreeBSD ./configure will try to do the right thing, if you don't have specific libraries certain functionality isn't built. # DIFFERENCE WITH RSYNC While rsync really works well, I wanted to have the ability to gzip and/or encrypt the backed up files. rsync can not do that. That is why I wrote rdup, which, with the help of rdup-tr and rdup-up will do that. Rdup was created to make custom backups, but due to its flexibility it can be used for much more. # DOCUMENTATION rdup is a utility inspired by rsync and the plan9 way of doing backups. rdup it self does not backup anything, it only print a list of absolute filenames to standard output. Auxiliary scripts are needed that act on this list and implement the backup strategy. This way rdup can be kept lean and mean. Currently the (stripped) rdup executable measures 26 KB (on i386) and I don't expect that to increase much (maybe it will even get smaller). The manual page explains rdup's options and usage, see rdup(1). For an introduction into making backups see rdup-backups(1). Helper tools that are included are rdup-tr (see rdup-tr(1)) and rdup-up (see rdup-up(1)). All manual pages include examples to get you started. A small script 'rdup-simple' is also included, this makes starting with rdup even more easy: rdup-simple ~ /backup. Will create a backup of your homedir in /backup. # COPYRIGHT All files in this archive are copyrighted by Miek Gieben, unless stated otherwise in the file itself. (c) Miek Gieben, 2005-2011. # LICENSE GPL, version 3, see the file LICENSE. # Coding style All code has been indented by `indent -linux` rdup-1.1.15/RELEASE-NOTES-1.1000066400000000000000000000035151303430127500147410ustar00rootroot00000000000000# RELEASE NOTES for RDUP 1.1.0 This is the first release of the new rdup branch, version 1.1.x. Why this new branch? I (and because of user requests) wanted to implement some extra features which needed (extensive) code modifications. I did not want to mess with the current stable release, hence a 1.1.x branch. However 1.1.x will obsolete 1.0.x soonish. > What is the difference with 1.0.x? (aka new features) 1. there is now only one default output format which always includes the files' contents; 2. the rdup output is now more comparable with the tar archive format, with the big difference of being able to *delete* files. 3. the new output includes: user- and groupnames and the modification timestamp of the file. They can now be correctly set on remote systems. (I.e the uid 'bert' stays 'bert' even if the remote side using a different uid *numbers* for 'bert'); 4. more efficient, files are only read once. In rdup 1.0.x both rdup and rdup-tr read files, in 1.1.x only rdup reads files. With this change the following new features were added: * `rdup` now has a `-a` switch: restore a-time when reading files; * `rdup-up` now sets the m-time on files it creates, this is the default; * `rdup-up` sets the user- and groupname more correct, see point 3. above. * `rdup-tr` can now be run on remote systems, because it receives the files' content on standard input. This work led to the following changes: * rdup has gotten the `-P` flag from rdup-up. This also makes the `-a` flag work even *if* you pipe the files' through external programs: they are only read once from disk; * `rdup-tr` only processes from stdin to stdout; * `rdup-up` only processes stdin; * much more tests are added to the testsuite (`make check`); * code cleanups. Some future work will of course remain, but I'm happy with how things turned out. rdup-1.1.15/abspath.c000066400000000000000000000032331303430127500143360ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup.h" /* * Remove /./ and /../ and // from a pathname * An absolute pathname argument is required. * Returns NULL on error, otherwise NULL terminated * sanitized pathname. * * Also see realpath(3) */ char *abspath(char *path) { char *p, *c; char *slash, *abspath2; char *abspath; int i; if (!path) return NULL; if (!g_path_is_absolute(path)) return NULL; /* abspath can be NULL or abspath[0] == '\0'. The NULL * is initial. the [0] == '\0' is when we got back to * the root */ abspath = NULL; abspath2 = g_strdup(path); i = strlen(abspath2); if (i > BUFSIZE) return NULL; /* add closing / (guard) */ if (abspath2[i - 1] != '/') { abspath2 = g_realloc(abspath2, i + 2); abspath2[i] = '/'; abspath2[i + 1] = '\0'; } /* jump from slash to slash */ for (p = abspath2; (c = strchr(p, '/')); p++) { *c = '\0'; if (*p == '\0' || (strcmp(p, ".") == 0)) { /* do nothing */ p = c; } else if (strcmp(p, "..") == 0) { /* go back a slash */ if (abspath == NULL || abspath[0] == '\0') { abspath = g_strdup("/"); } else { slash = strrchr(abspath, '/'); *slash = '\0'; *c = '/'; } } else { if (abspath == NULL || abspath[0] == '\0' || (strcmp(abspath, "/") == 0)) { g_free(abspath); abspath = g_strconcat("/", p, NULL); } else { gchar *tmp = g_strdup(abspath); g_free(abspath); abspath = g_strjoin("/", tmp, p, NULL); g_free(tmp); } *c = '/'; } p = c; } if (abspath == NULL || abspath[0] == '\0') abspath = g_strdup("/"); g_free(abspath2); return abspath; } rdup-1.1.15/base64.c000066400000000000000000000102171303430127500140000ustar00rootroot00000000000000/* * Copyright (C), 2000-2007 by the monit project group. * All Rights Reserved. * * This program 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 3 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, see . */ #include "rdup-tr.h" #include "base64.h" /* See Section 4 of RFC 3548, be URL safe, modified by Miek Gieben, 2009 */ /* Private prototypes */ static int is_base64(char c); static char encode(unsigned char u); static unsigned char decode(char c); /** * Implementation of base64 encoding/decoding. * @author Jan-Henrik Haukeland, * @version \$Id: base64.c,v 1.19 2007/07/25 12:54:31 hauk Exp $ * */ /** * Base64 encode and return size data in 'src'. The caller must free the * returned string. * @param size The size of the data in src * @param src The data to be base64 encode * @return encoded string otherwise NULL */ char *encode_base64(int size, unsigned char *src) { int i; char *out, *p; if (!src) return NULL; if (!size) size = strlen((char *)src); out = g_malloc0(size * 4 / 3 + 4); p = out; for (i = 0; i < size; i += 3) { unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0; b1 = src[i]; if (i + 1 < size) b2 = src[i + 1]; if (i + 2 < size) b3 = src[i + 2]; b4 = b1 >> 2; b5 = ((b1 & 0x3) << 4) | (b2 >> 4); b6 = ((b2 & 0xf) << 2) | (b3 >> 6); b7 = b3 & 0x3f; *p++ = encode(b4); *p++ = encode(b5); if (i + 1 < size) { *p++ = encode(b6); } else { *p++ = '='; } if (i + 2 < size) { *p++ = encode(b7); } else { *p++ = '='; } } return out; } /** * Decode the base64 encoded string 'src' into the memory pointed to by * 'dest'. The dest buffer is not NUL terminated. * @param dest Pointer to memory for holding the decoded string. * Must be large enough to recieve the decoded string. * @param src A base64 encoded string. * @return (the length of the decoded string) if decode * succeeded otherwise FALSE. */ int decode_base64(unsigned char *dest, const char *src) { if (src && *src) { unsigned char *p = dest; int k, l = strlen(src) + 1; unsigned char *buf = g_malloc0(l); /* Ignore non base64 chars as per the POSIX standard */ for (k = 0, l = 0; src[k]; k++) { if (is_base64(src[k])) { buf[l++] = src[k]; } } for (k = 0; k < l; k += 4) { char c1 = 'A', c2 = 'A', c3 = 'A', c4 = 'A'; unsigned char b1 = 0, b2 = 0, b3 = 0, b4 = 0; c1 = buf[k]; if (k + 1 < l) { c2 = buf[k + 1]; } if (k + 2 < l) { c3 = buf[k + 2]; } if (k + 3 < l) { c4 = buf[k + 3]; } b1 = decode(c1); b2 = decode(c2); b3 = decode(c3); b4 = decode(c4); *p++ = ((b1 << 2) | (b2 >> 4)); if (c3 != '=') { *p++ = (((b2 & 0xf) << 4) | (b3 >> 2)); } if (c4 != '=') { *p++ = (((b3 & 0x3) << 6) | b4); } } g_free(buf); return (p - dest); } return FALSE; } /** * Base64 encode one byte */ static char encode(unsigned char u) { if (u < 26) return 'A' + u; if (u < 52) return 'a' + (u - 26); if (u < 62) return '0' + (u - 52); if (u == 62) return '-'; /* was + */ /* return '/'; */ return '_'; } /** * Decode a base64 character */ static unsigned char decode(char c) { if (c >= 'A' && c <= 'Z') return (c - 'A'); if (c >= 'a' && c <= 'z') return (c - 'a' + 26); if (c >= '0' && c <= '9') return (c - '0' + 52); if (c == '-') return 62; /* was '+' */ return 63; } /** * Return TRUE if 'c' is a valid base64 character, otherwise FALSE */ static int is_base64(char c) { if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9') || (c == '-') || (c == '_') || (c == '=')) { return TRUE; } return FALSE; } rdup-1.1.15/base64.h000066400000000000000000000015701303430127500140070ustar00rootroot00000000000000/* * Copyright (C), 2000-2007 by the monit project group. * All Rights Reserved. * * This program 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 3 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, see . */ #ifndef BASE64_H #define BASE64_H int decode_base64(unsigned char *dest, const char *src); char *encode_base64(int size, unsigned char *src); #endif rdup-1.1.15/child.c000066400000000000000000000066621303430127500140100ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * child.c handle child stuff */ #include "rdup.h" extern int sig; /* signal.c */ void got_sig(int signal); /* close all pipes except n1 and n2 (-1 is not needed) */ void close_pipes(GSList * pipes, int n1, int n2) { GSList *p; int *q; int j; for (j = 0, p = g_slist_nth(pipes, 0); p; p = p->next, j++) { q = p->data; /* msg("Pipe set %d fds %d %d", j, q[0], q[1]); */ if (j == n1 || j == n2) continue; close(q[0]); close(q[1]); } } /* return 0 if all ok, -1 for trouble */ int wait_pids(GSList * pids, int flags) { GSList *p; int status; pid_t pid; for (p = g_slist_nth(pids, 0); p; p = p->next) { if (sig != 0) signal_abort(sig); #ifdef DEBUG msgd(__func__, __LINE__, "Waiting for pid %d", (int)*(pid_t *) (p->data)); #endif /* DEBUG */ pid = waitpid(*(pid_t *) (p->data), &status, flags); if (pid != *(pid_t *) (p->data)) { msg("Waitpid returned different pid %d than expected %d: `%s\'", pid, *(pid_t *) (p->data), strerror(errno)); continue; } #if 0 /* enable later */ if (!WIFEXITED(status)) { return -1; } #endif } return 0; } /* create pipes and childs, return pids */ GSList *create_children(GSList * child, GSList ** pipes, int file) { GSList *p; GSList *pids = NULL; GSList *cpipe = NULL; pid_t *cpid; char *args[4]; int *pips; int childs, j; if (!child) return NULL; /* create all pipes before forking * As a parent we read from the last pipe created * We attach file to the input of the first child * This eliminates to use of a tmp file */ childs = g_slist_length(child); for (j = 0; j < childs; j++) { pips = g_malloc(2 * sizeof(int)); if (pipe(pips) == -1) { msg(_("Failure creating pipes")); exit(EXIT_FAILURE); } cpipe = g_slist_append(cpipe, pips); } for (j = 0, p = g_slist_nth(child, 0); p; p = p->next, j++) { if (sig != 0) signal_abort(sig); /* fork, exec child */ args[0] = "sh"; args[1] = "-c"; args[2] = (char *)p->data; args[3] = NULL; pips = (g_slist_nth(cpipe, j))->data; cpid = g_malloc(sizeof(int)); if ((*cpid = fork()) == -1) { msg(_("Fork error")); return NULL; /* exit(EXIT_FAILURE); */ } if (*cpid != 0) { /* parent */ /* save the pids */ pids = g_slist_append(pids, cpid); } else { /* child */ if (j == 0) { /* dup f to stdin */ if (dup2(file, 0) == -1) exit(EXIT_FAILURE); close(pips[0]); /* pips[1] still alive */ if (dup2(pips[1], 1) == -1) exit(EXIT_FAILURE); close_pipes(cpipe, j, -1); } else { close(file); /* close read end */ close(pips[0]); /* dup write to stdout */ if (dup2(pips[1], 1) == -1) exit(EXIT_FAILURE); /* re-use pips for the previous pipe pair */ pips = (g_slist_nth(cpipe, j - 1))->data; /* dup read to stdin */ if (dup2(pips[0], 0) == -1) exit(EXIT_FAILURE); /* and close 1 */ close(pips[1]); close_pipes(cpipe, j, j - 1); } /* finally ... exec */ if (execvp(args[0], args) == -1) { msg(_("Failed to exec `%s\': %s"), args[0], strerror(errno)); exit(EXIT_FAILURE); } /* never reached */ exit(EXIT_SUCCESS); } } /* all childeren created, close all pipes except the last one */ close_pipes(cpipe, childs - 1, -1); /* close write end, we only need to read as parent */ pips = (g_slist_last(cpipe))->data; close(pips[1]); *pipes = cpipe; return pids; } rdup-1.1.15/chown.c000066400000000000000000000026611303430127500140360ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * Parse username:group helper files */ #include "rdup.h" /* signal.c */ void got_sig(int signal); /* write a chown helper file */ void chown_write(gchar * dir, gchar * base, uid_t u, gchar * user, gid_t g, gchar * group) { FILE *f; gchar *path; if (base == NULL) { /* a directory, i.e. /tmp/._rdup_. */ path = g_strdup_printf("%s/%s", dir, USRGRPINFO); } else { path = g_strdup_printf("%s/%s%s", dir, USRGRPINFO, base); } if (!(f = fopen(path, "w"))) { /* no file found or failure to open */ g_free(path); return; } g_free(path); fprintf(f, "%s:%d/%s:%d\n", user, u, group, g); fclose(f); } /* parse the chown help file */ struct chown_pack *chown_parse(gchar * dir, gchar * base) { FILE *f; gchar *path; if (base == NULL) { /* a directory */ path = g_strdup_printf("%s/%s", dir, USRGRPINFO); } else { path = g_strdup_printf("%s/%s%s", dir, USRGRPINFO, base); } if (!(f = fopen(path, "r"))) { /* no file found or failure to open */ g_free(path); return NULL; } long int u, g; gchar *user = g_malloc(17); gchar *group = g_malloc(17); struct chown_pack *cp = g_malloc(sizeof(struct chown_pack)); if (fscanf(f, "%16[^:]:%ld/%16[^:]:%ld\n", user, &u, group, &g) != 4) { /* failure to parse the file */ return NULL; } cp->u = (uid_t) u; cp->g = (gid_t) g; cp->user = user; cp->group = group; return cp; } rdup-1.1.15/common.c000066400000000000000000000017331303430127500142070ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * common functions for entries */ #include #include #include "entry.h" struct rdup *entry_dup(struct rdup *f) { struct rdup *g; g = g_malloc(sizeof(struct rdup)); g->plusmin = f->plusmin; if (f->f_name != NULL) g->f_name = g_strdup(f->f_name); else g->f_name = NULL; if (f->f_target != NULL) g->f_target = g_strdup(f->f_target); else g->f_target = NULL; g->f_name_size = f->f_name_size; g->f_lnk = f->f_lnk; g->f_uid = f->f_uid; g->f_user = f->f_user; g->f_gid = f->f_gid; g->f_group = f->f_group; g->f_mode = f->f_mode; g->f_ctime = f->f_ctime; g->f_mtime = f->f_mtime; g->f_atime = f->f_atime; g->f_size = f->f_size; g->f_dev = f->f_dev; g->f_rdev = f->f_rdev; g->f_ino = f->f_ino; return g; } void entry_free(struct rdup *f) { if (f->f_name != NULL) g_free(f->f_name); if (f->f_target != NULL) g_free(f->f_target); g_free(f); } rdup-1.1.15/common.h000066400000000000000000000002441303430127500142100ustar00rootroot00000000000000#ifndef _COMMON_H #define _COMMON_H #define BUFSIZE 8192 #define LIST_MINSIZE 6 #define LIST_SPACEPOS 5 /* signal.c */ void got_sig(int); #endif /* COMMON_H */ rdup-1.1.15/config.guess000077500000000000000000001270351303430127500150770ustar00rootroot00000000000000#! /bin/sh # Attempt to guess a canonical system name. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2007-03-06' # 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, 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. # Originally written by Per Bothner . # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # 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 build system type. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] Output the configuration name of the system \`$me' is run on. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.guess ($timestamp) Originally written by Per Bothner. Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" >&2 exit 1 ;; * ) break ;; esac done if test $# != 0; then echo "$me: too many arguments$help" >&2 exit 1 fi trap 'exit 1' 1 2 15 # CC_FOR_BUILD -- compiler used by this script. Note that the use of a # compiler to aid in system detection is discouraged as it requires # temporary files to be created and, as you can see below, it is a # headache to deal with in a portable fashion. # Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still # use `HOST_CC' if defined, but it is deprecated. # Portable tmp directory creation inspired by the Autoconf team. set_cc_for_build=' trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ; trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ; : ${TMPDIR=/tmp} ; { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } || { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } || { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } || { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ; dummy=$tmp/dummy ; tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ; case $CC_FOR_BUILD,$HOST_CC,$CC in ,,) echo "int x;" > $dummy.c ; for c in cc gcc c89 c99 ; do if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then CC_FOR_BUILD="$c"; break ; fi ; done ; if test x"$CC_FOR_BUILD" = x ; then CC_FOR_BUILD=no_compiler_found ; fi ;; ,,*) CC_FOR_BUILD=$CC ;; ,*,*) CC_FOR_BUILD=$HOST_CC ;; esac ; set_cc_for_build= ;' # This is needed to find uname on a Pyramid OSx when run in the BSD universe. # (ghazi@noc.rutgers.edu 1994-08-24) 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 # Note: order is significant - the case branches are not exclusive. case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in *:NetBSD:*:*) # NetBSD (nbsd) targets should (where applicable) match one or # more of the tupples: *-*-netbsdelf*, *-*-netbsdaout*, # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently # switched to ELF, *-*-netbsd* would select the old # object file format. This provides both forward # compatibility and a consistent mechanism for selecting the # object file format. # # Note: NetBSD doesn't particularly care about the vendor # portion of the name. We always set it to "unknown". sysctl="sysctl -n hw.machine_arch" UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \ /usr/sbin/$sysctl 2>/dev/null || echo unknown)` case "${UNAME_MACHINE_ARCH}" in armeb) machine=armeb-unknown ;; arm*) machine=arm-unknown ;; sh3el) machine=shl-unknown ;; sh3eb) machine=sh-unknown ;; sh5el) machine=sh5le-unknown ;; *) machine=${UNAME_MACHINE_ARCH}-unknown ;; esac # The Operating System including object format, if it has switched # to ELF recently, or will in the future. case "${UNAME_MACHINE_ARCH}" in arm*|i386|m68k|ns32k|sh3*|sparc|vax) eval $set_cc_for_build if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \ | grep __ELF__ >/dev/null then # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout). # Return netbsd for either. FIX? os=netbsd else os=netbsdelf fi ;; *) os=netbsd ;; esac # The OS release # Debian GNU/NetBSD machines have a different userland, and # thus, need a distinct triplet. However, they do not need # kernel version information, so it can be replaced with a # suitable tag, in the style of linux-gnu. case "${UNAME_VERSION}" in Debian*) release='-gnu' ;; *) release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'` ;; esac # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM: # contains redundant information, the shorter form: # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used. echo "${machine}-${os}${release}" exit ;; *:OpenBSD:*:*) UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'` echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE} exit ;; *:ekkoBSD:*:*) echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE} exit ;; *:SolidBSD:*:*) echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE} exit ;; macppc:MirBSD:*:*) echo powerpc-unknown-mirbsd${UNAME_RELEASE} exit ;; *:MirBSD:*:*) echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE} exit ;; alpha:OSF1:*:*) case $UNAME_RELEASE in *4.0) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'` ;; *5.*) UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'` ;; esac # According to Compaq, /usr/sbin/psrinfo has been available on # OSF/1 and Tru64 systems produced since 1995. I hope that # covers most systems running today. This code pipes the CPU # types through head -n 1, so we only detect the type of CPU 0. ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1` case "$ALPHA_CPU_TYPE" in "EV4 (21064)") UNAME_MACHINE="alpha" ;; "EV4.5 (21064)") UNAME_MACHINE="alpha" ;; "LCA4 (21066/21068)") UNAME_MACHINE="alpha" ;; "EV5 (21164)") UNAME_MACHINE="alphaev5" ;; "EV5.6 (21164A)") UNAME_MACHINE="alphaev56" ;; "EV5.6 (21164PC)") UNAME_MACHINE="alphapca56" ;; "EV5.7 (21164PC)") UNAME_MACHINE="alphapca57" ;; "EV6 (21264)") UNAME_MACHINE="alphaev6" ;; "EV6.7 (21264A)") UNAME_MACHINE="alphaev67" ;; "EV6.8CB (21264C)") UNAME_MACHINE="alphaev68" ;; "EV6.8AL (21264B)") UNAME_MACHINE="alphaev68" ;; "EV6.8CX (21264D)") UNAME_MACHINE="alphaev68" ;; "EV6.9A (21264/EV69A)") UNAME_MACHINE="alphaev69" ;; "EV7 (21364)") UNAME_MACHINE="alphaev7" ;; "EV7.9 (21364A)") UNAME_MACHINE="alphaev79" ;; esac # A Pn.n version is a patched version. # A Vn.n version is a released version. # A Tn.n version is a released field test version. # A Xn.n version is an unreleased experimental baselevel. # 1.2 uses "1.2" for uname -r. echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` exit ;; Alpha\ *:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # Should we change UNAME_MACHINE based on the output of uname instead # of the specific Alpha model? echo alpha-pc-interix exit ;; 21064:Windows_NT:50:3) echo alpha-dec-winnt3.5 exit ;; Amiga*:UNIX_System_V:4.0:*) echo m68k-unknown-sysv4 exit ;; *:[Aa]miga[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-amigaos exit ;; *:[Mm]orph[Oo][Ss]:*:*) echo ${UNAME_MACHINE}-unknown-morphos exit ;; *:OS/390:*:*) echo i370-ibm-openedition exit ;; *:z/VM:*:*) echo s390-ibm-zvmoe exit ;; *:OS400:*:*) echo powerpc-ibm-os400 exit ;; arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*) echo arm-acorn-riscix${UNAME_RELEASE} exit ;; arm:riscos:*:*|arm:RISCOS:*:*) echo arm-unknown-riscos exit ;; SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*) echo hppa1.1-hitachi-hiuxmpp exit ;; Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*) # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE. if test "`(/bin/universe) 2>/dev/null`" = att ; then echo pyramid-pyramid-sysv3 else echo pyramid-pyramid-bsd fi exit ;; NILE*:*:*:dcosx) echo pyramid-pyramid-svr4 exit ;; DRS?6000:unix:4.0:6*) echo sparc-icl-nx6 exit ;; DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*) case `/usr/bin/uname -p` in sparc) echo sparc-icl-nx7; exit ;; esac ;; sun4H:SunOS:5.*:*) echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*) echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; i86pc:SunOS:5.*:*) echo i386-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; 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 ;; 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 ;; sun3*:SunOS:*:*) echo m68k-sun-sunos${UNAME_RELEASE} exit ;; sun*:*:4.2BSD:*) UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null` test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3 case "`/bin/arch`" in sun3) echo m68k-sun-sunos${UNAME_RELEASE} ;; sun4) echo sparc-sun-sunos${UNAME_RELEASE} ;; esac exit ;; aushp:SunOS:*:*) echo sparc-auspex-sunos${UNAME_RELEASE} exit ;; # The situation for MiNT is a little confusing. The machine name # can be virtually everything (everything which is not # "atarist" or "atariste" at least should have a processor # > m68000). The system name ranges from "MiNT" over "FreeMiNT" # to the lowercase version "mint" (or "freemint"). Finally # the system name "TOS" denotes a system which is actually not # MiNT. But MiNT is downward compatible to TOS, so this should # be no problem. atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*) echo m68k-atari-mint${UNAME_RELEASE} exit ;; milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*) echo m68k-milan-mint${UNAME_RELEASE} exit ;; hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*) echo m68k-hades-mint${UNAME_RELEASE} exit ;; *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*) echo m68k-unknown-mint${UNAME_RELEASE} exit ;; m68k:machten:*:*) echo m68k-apple-machten${UNAME_RELEASE} exit ;; powerpc:machten:*:*) echo powerpc-apple-machten${UNAME_RELEASE} exit ;; RISC*:Mach:*:*) echo mips-dec-mach_bsd4.3 exit ;; RISC*:ULTRIX:*:*) echo mips-dec-ultrix${UNAME_RELEASE} exit ;; VAX*:ULTRIX*:*:*) echo vax-dec-ultrix${UNAME_RELEASE} exit ;; 2020:CLIX:*:* | 2430:CLIX:*:*) echo clipper-intergraph-clix${UNAME_RELEASE} exit ;; mips:*:*:UMIPS | mips:*:*:RISCos) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #ifdef __cplusplus #include /* for printf() prototype */ int main (int argc, char *argv[]) { #else int main (argc, argv) int argc; char *argv[]; { #endif #if defined (host_mips) && defined (MIPSEB) #if defined (SYSTYPE_SYSV) printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_SVR4) printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0); #endif #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD) printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0); #endif #endif exit (-1); } EOF $CC_FOR_BUILD -o $dummy $dummy.c && dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` && SYSTEM_NAME=`$dummy $dummyarg` && { echo "$SYSTEM_NAME"; exit; } echo mips-mips-riscos${UNAME_RELEASE} exit ;; Motorola:PowerMAX_OS:*:*) echo powerpc-motorola-powermax exit ;; Motorola:*:4.3:PL8-*) echo powerpc-harris-powermax exit ;; Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*) echo powerpc-harris-powermax exit ;; Night_Hawk:Power_UNIX:*:*) echo powerpc-harris-powerunix exit ;; m88k:CX/UX:7*:*) echo m88k-harris-cxux7 exit ;; m88k:*:4*:R4*) echo m88k-motorola-sysv4 exit ;; m88k:*:3*:R3*) echo m88k-motorola-sysv3 exit ;; AViiON:dgux:*:*) # DG/UX returns AViiON for all architectures UNAME_PROCESSOR=`/usr/bin/uname -p` if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ] then if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \ [ ${TARGET_BINARY_INTERFACE}x = x ] then echo m88k-dg-dgux${UNAME_RELEASE} else echo m88k-dg-dguxbcs${UNAME_RELEASE} fi else echo i586-dg-dgux${UNAME_RELEASE} fi exit ;; M88*:DolphinOS:*:*) # DolphinOS (SVR3) echo m88k-dolphin-sysv3 exit ;; M88*:*:R3*:*) # Delta 88k system running SVR3 echo m88k-motorola-sysv3 exit ;; XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3) echo m88k-tektronix-sysv3 exit ;; Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD) echo m68k-tektronix-bsd exit ;; *:IRIX*:*:*) echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'` exit ;; ????????: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 ;; # Note that: echo "'`uname -s`'" gives 'AIX ' i*86:AIX:*:*) echo i386-ibm-aix exit ;; ia64:AIX:*:*) if [ -x /usr/bin/oslevel ] ; then IBM_REV=`/usr/bin/oslevel` else IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${UNAME_MACHINE}-ibm-aix${IBM_REV} exit ;; *:AIX:2:3) if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include main() { if (!__power_pc()) exit(1); puts("powerpc-ibm-aix3.2.5"); exit(0); } EOF if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` then echo "$SYSTEM_NAME" else echo rs6000-ibm-aix3.2.5 fi 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 ;; *:AIX:*:[45]) IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'` if /usr/sbin/lsattr -El ${IBM_CPU_ID} | 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=${UNAME_VERSION}.${UNAME_RELEASE} fi echo ${IBM_ARCH}-ibm-aix${IBM_REV} exit ;; *:AIX:*:*) echo rs6000-ibm-aix exit ;; ibmrt:4.4BSD:*|romp-ibm:BSD:*) echo romp-ibm-bsd4.4 exit ;; ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to exit ;; # report: romp-ibm BSD 4.3 *:BOSX:*:*) echo rs6000-bull-bosx exit ;; DPX/2?00:B.O.S.:*:*) echo m68k-bull-sysv3 exit ;; 9000/[34]??:4.3bsd:1.*:*) echo m68k-hp-bsd exit ;; hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*) echo m68k-hp-bsd4.4 exit ;; 9000/[34678]??:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` case "${UNAME_MACHINE}" in 9000/31? ) HP_ARCH=m68000 ;; 9000/[34]?? ) HP_ARCH=m68k ;; 9000/[678][0-9][0-9]) if [ -x /usr/bin/getconf ]; then sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null` sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null` case "${sc_cpu_version}" in 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1 532) # CPU_PA_RISC2_0 case "${sc_kernel_bits}" in 32) HP_ARCH="hppa2.0n" ;; 64) HP_ARCH="hppa2.0w" ;; '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20 esac ;; esac fi if [ "${HP_ARCH}" = "" ]; then eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #define _HPUX_SOURCE #include #include int main () { #if defined(_SC_KERNEL_BITS) long bits = sysconf(_SC_KERNEL_BITS); #endif long cpu = sysconf (_SC_CPU_VERSION); switch (cpu) { case CPU_PA_RISC1_0: puts ("hppa1.0"); break; case CPU_PA_RISC1_1: puts ("hppa1.1"); break; case CPU_PA_RISC2_0: #if defined(_SC_KERNEL_BITS) switch (bits) { case 64: puts ("hppa2.0w"); break; case 32: puts ("hppa2.0n"); break; default: puts ("hppa2.0"); break; } break; #else /* !defined(_SC_KERNEL_BITS) */ puts ("hppa2.0"); break; #endif default: puts ("hppa1.0"); break; } exit (0); } EOF (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy` test -z "$HP_ARCH" && HP_ARCH=hppa fi ;; esac if [ ${HP_ARCH} = "hppa2.0w" ] then eval $set_cc_for_build # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler # generating 64-bit code. GNU and HP use different nomenclature: # # $ CC_FOR_BUILD=cc ./config.guess # => hppa2.0w-hp-hpux11.23 # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess # => hppa64-hp-hpux11.23 if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | grep __LP64__ >/dev/null then HP_ARCH="hppa2.0w" else HP_ARCH="hppa64" fi fi echo ${HP_ARCH}-hp-hpux${HPUX_REV} exit ;; ia64:HP-UX:*:*) HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'` echo ia64-hp-hpux${HPUX_REV} exit ;; 3050*:HI-UX:*:*) eval $set_cc_for_build 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_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } echo unknown-hitachi-hiuxwe2 exit ;; 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* ) echo hppa1.1-hp-bsd exit ;; 9000/8??:4.3bsd:*:*) echo hppa1.0-hp-bsd exit ;; *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*) echo hppa1.0-hp-mpeix exit ;; hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* ) echo hppa1.1-hp-osf exit ;; hp8??:OSF1:*:*) echo hppa1.0-hp-osf exit ;; i*86:OSF1:*:*) if [ -x /usr/sbin/sysversion ] ; then echo ${UNAME_MACHINE}-unknown-osf1mk else echo ${UNAME_MACHINE}-unknown-osf1 fi exit ;; parisc*:Lites*:*:*) echo hppa1.1-hp-lites exit ;; C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*) echo c1-convex-bsd exit ;; C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*) echo c34-convex-bsd exit ;; C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*) echo c38-convex-bsd exit ;; C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*) echo c4-convex-bsd exit ;; CRAY*Y-MP:*:*:*) echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*[A-Z]90:*:*:*) echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \ -e 's/\.[^.]*$/.X/' exit ;; CRAY*TS:*:*:*) echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*T3E:*:*:*) echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; CRAY*SV1:*:*:*) echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; *:UNICOS/mp:*:*) echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/' exit ;; F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*) FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'` FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'` echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; 5000:UNIX_System_V:4.*:*) FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'` FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'` echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}" exit ;; i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*) echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE} exit ;; sparc*:BSD/OS:*:*) echo sparc-unknown-bsdi${UNAME_RELEASE} exit ;; *:BSD/OS:*:*) echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE} exit ;; *:FreeBSD:*:*) case ${UNAME_MACHINE} in pc98) echo i386-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; amd64) echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; *) echo ${UNAME_MACHINE}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;; esac exit ;; i*:CYGWIN*:*) echo ${UNAME_MACHINE}-pc-cygwin exit ;; *:MINGW*:*) echo ${UNAME_MACHINE}-pc-mingw32 exit ;; i*:windows32*:*) # uname -m includes "-pc" on this system. echo ${UNAME_MACHINE}-mingw32 exit ;; i*:PW*:*) echo ${UNAME_MACHINE}-pc-pw32 exit ;; *:Interix*:[3456]*) case ${UNAME_MACHINE} in x86) echo i586-pc-interix${UNAME_RELEASE} exit ;; EM64T | authenticamd) echo x86_64-unknown-interix${UNAME_RELEASE} exit ;; esac ;; [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*) echo i${UNAME_MACHINE}-pc-mks exit ;; i*:Windows_NT*:* | Pentium*:Windows_NT*:*) # How do we know it's Interix rather than the generic POSIX subsystem? # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we # UNAME_MACHINE based on the output of uname instead of i386? echo i586-pc-interix exit ;; i*:UWIN*:*) echo ${UNAME_MACHINE}-pc-uwin exit ;; amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*) echo x86_64-unknown-cygwin exit ;; p*:CYGWIN*:*) echo powerpcle-unknown-cygwin exit ;; prep*:SunOS:5.*:*) echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'` exit ;; *:GNU:*:*) # the GNU system echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-gnu`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'` exit ;; *:GNU/*:*:*) # other systems with GNU libc and userland echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-gnu exit ;; i*86:Minix:*:*) echo ${UNAME_MACHINE}-pc-minix exit ;; arm*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; avr32*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; cris:Linux:*:*) echo cris-axis-linux-gnu exit ;; crisv32:Linux:*:*) echo crisv32-axis-linux-gnu exit ;; frv:Linux:*:*) echo frv-unknown-linux-gnu exit ;; ia64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m32r*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; m68*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; mips:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips #undef mipsel #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mipsel #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; mips64:Linux:*:*) eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #undef CPU #undef mips64 #undef mips64el #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL) CPU=mips64el #else #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB) CPU=mips64 #else CPU= #endif #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^CPU/{ s: ::g p }'`" test x"${CPU}" != x && { echo "${CPU}-unknown-linux-gnu"; exit; } ;; or32:Linux:*:*) echo or32-unknown-linux-gnu exit ;; ppc:Linux:*:*) echo powerpc-unknown-linux-gnu exit ;; ppc64:Linux:*:*) echo powerpc64-unknown-linux-gnu exit ;; alpha:Linux:*:*) case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in EV5) UNAME_MACHINE=alphaev5 ;; EV56) UNAME_MACHINE=alphaev56 ;; PCA56) UNAME_MACHINE=alphapca56 ;; PCA57) UNAME_MACHINE=alphapca56 ;; EV6) UNAME_MACHINE=alphaev6 ;; EV67) UNAME_MACHINE=alphaev67 ;; EV68*) UNAME_MACHINE=alphaev68 ;; esac objdump --private-headers /bin/sh | grep ld.so.1 >/dev/null if test "$?" = 0 ; then LIBC="libc1" ; else LIBC="" ; fi echo ${UNAME_MACHINE}-unknown-linux-gnu${LIBC} exit ;; parisc:Linux:*:* | hppa:Linux:*:*) # Look for CPU level case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in PA7*) echo hppa1.1-unknown-linux-gnu ;; PA8*) echo hppa2.0-unknown-linux-gnu ;; *) echo hppa-unknown-linux-gnu ;; esac exit ;; parisc64:Linux:*:* | hppa64:Linux:*:*) echo hppa64-unknown-linux-gnu exit ;; s390:Linux:*:* | s390x:Linux:*:*) echo ${UNAME_MACHINE}-ibm-linux exit ;; sh64*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sh*:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; sparc:Linux:*:* | sparc64:Linux:*:*) echo ${UNAME_MACHINE}-unknown-linux-gnu exit ;; vax:Linux:*:*) echo ${UNAME_MACHINE}-dec-linux-gnu exit ;; x86_64:Linux:*:*) echo x86_64-unknown-linux-gnu exit ;; xtensa:Linux:*:*) echo xtensa-unknown-linux-gnu exit ;; i*86:Linux:*:*) # The BFD linker knows what the default object file format is, so # first see if it will tell us. cd to the root directory to prevent # problems with other programs or directories called `ld' in the path. # Set LC_ALL=C to ensure ld outputs messages in English. ld_supported_targets=`cd /; LC_ALL=C ld --help 2>&1 \ | sed -ne '/supported targets:/!d s/[ ][ ]*/ /g s/.*supported targets: *// s/ .*// p'` case "$ld_supported_targets" in elf32-i386) TENTATIVE="${UNAME_MACHINE}-pc-linux-gnu" ;; a.out-i386-linux) echo "${UNAME_MACHINE}-pc-linux-gnuaout" exit ;; coff-i386) echo "${UNAME_MACHINE}-pc-linux-gnucoff" exit ;; "") # Either a pre-BFD a.out linker (linux-gnuoldld) or # one that does not give us useful --help. echo "${UNAME_MACHINE}-pc-linux-gnuoldld" exit ;; esac # Determine whether the default compiler is a.out or elf eval $set_cc_for_build sed 's/^ //' << EOF >$dummy.c #include #ifdef __ELF__ # ifdef __GLIBC__ # if __GLIBC__ >= 2 LIBC=gnu # else LIBC=gnulibc1 # endif # else LIBC=gnulibc1 # endif #else #if defined(__INTEL_COMPILER) || defined(__PGI) || defined(__SUNPRO_C) || defined(__SUNPRO_CC) LIBC=gnu #else LIBC=gnuaout #endif #endif #ifdef __dietlibc__ LIBC=dietlibc #endif EOF eval "`$CC_FOR_BUILD -E $dummy.c 2>/dev/null | sed -n ' /^LIBC/{ s: ::g p }'`" test x"${LIBC}" != x && { echo "${UNAME_MACHINE}-pc-linux-${LIBC}" exit } test x"${TENTATIVE}" != x && { echo "${TENTATIVE}"; exit; } ;; i*86:DYNIX/ptx:4*:*) # 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. echo i386-sequent-sysv4 exit ;; i*86:UNIX_SV:4.2MP:2.*) # Unixware is an offshoot of SVR4, but it has its own version # number series starting with 2... # I am not positive that other SVR4 systems won't match this, # I just have to hope. -- rms. # Use sysv4.2uw... so that sysv4* matches it. echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION} exit ;; i*86:OS/2:*:*) # If we were able to find `uname', then EMX Unix compatibility # is probably installed. echo ${UNAME_MACHINE}-pc-os2-emx exit ;; i*86:XTS-300:*:STOP) echo ${UNAME_MACHINE}-unknown-stop exit ;; i*86:atheos:*:*) echo ${UNAME_MACHINE}-unknown-atheos exit ;; i*86:syllable:*:*) echo ${UNAME_MACHINE}-pc-syllable exit ;; i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.0*:*) echo i386-unknown-lynxos${UNAME_RELEASE} exit ;; i*86:*DOS:*:*) echo ${UNAME_MACHINE}-pc-msdosdjgpp exit ;; i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*) UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'` if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL} else echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL} fi exit ;; i*86:*:5:[678]*) # UnixWare 7.x, OpenUNIX and OpenServer 6. case `/bin/uname -X | grep "^Machine"` in *486*) UNAME_MACHINE=i486 ;; *Pentium) UNAME_MACHINE=i586 ;; *Pent*|*Celeron) UNAME_MACHINE=i686 ;; esac echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION} exit ;; i*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|grep Release|sed -e 's/.*= //')` (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486 (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \ && UNAME_MACHINE=i586 (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \ && UNAME_MACHINE=i686 (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \ && UNAME_MACHINE=i686 echo ${UNAME_MACHINE}-pc-sco$UNAME_REL else echo ${UNAME_MACHINE}-pc-sysv32 fi exit ;; pc:*:*:*) # Left here for compatibility: # uname -m prints for DJGPP always 'pc', but it prints nothing about # the processor, so we play safe by assuming i386. echo i386-pc-msdosdjgpp exit ;; Intel:Mach:3*:*) echo i386-pc-mach3 exit ;; paragon:*:*:*) echo i860-intel-osf1 exit ;; 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 ;; mini*:CTIX:SYS*5:*) # "miniframe" echo m68010-convergent-sysv exit ;; mc68k:UNIX:SYSTEM5:3.51m) echo m68k-convergent-sysv exit ;; M680?0:D-NIX:5.3:*) echo m68k-diab-dnix exit ;; M68*:*:R3V[5678]*:*) test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;; 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0) OS_REL='' test -r /etc/.relid \ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid` /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4.3${OS_REL}; exit; } /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;; 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*) /bin/uname -p 2>/dev/null | grep 86 >/dev/null \ && { echo i486-ncr-sysv4; exit; } ;; m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*) echo m68k-unknown-lynxos${UNAME_RELEASE} exit ;; mc68030:UNIX_System_V:4.*:*) echo m68k-atari-sysv4 exit ;; TSUNAMI:LynxOS:2.*:*) echo sparc-unknown-lynxos${UNAME_RELEASE} exit ;; rs6000:LynxOS:2.*:*) echo rs6000-unknown-lynxos${UNAME_RELEASE} exit ;; PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.0*:*) echo powerpc-unknown-lynxos${UNAME_RELEASE} exit ;; SM[BE]S:UNIX_SV:*:*) echo mips-dde-sysv${UNAME_RELEASE} exit ;; RM*:ReliantUNIX-*:*:*) echo mips-sni-sysv4 exit ;; RM*:SINIX-*:*:*) echo mips-sni-sysv4 exit ;; *: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 ;; PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort # says echo i586-unisys-sysv4 exit ;; *:UNIX_System_V:4*:FTX*) # From Gerald Hewes . # How about differentiating between stratus architectures? -djm echo hppa1.1-stratus-sysv4 exit ;; *:*:*:FTX*) # From seanf@swdc.stratus.com. echo i860-stratus-sysv4 exit ;; i*86:VOS:*:*) # From Paul.Green@stratus.com. echo ${UNAME_MACHINE}-stratus-vos exit ;; *:VOS:*:*) # From Paul.Green@stratus.com. echo hppa1.1-stratus-vos exit ;; mc68*:A/UX:*:*) echo m68k-apple-aux${UNAME_RELEASE} exit ;; news*:NEWS-OS:6*:*) echo mips-sony-newsos6 exit ;; R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*) if [ -d /usr/nec ]; then echo mips-nec-sysv${UNAME_RELEASE} else echo mips-unknown-sysv${UNAME_RELEASE} fi exit ;; BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only. echo powerpc-be-beos exit ;; BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only. echo powerpc-apple-beos exit ;; BePC:BeOS:*:*) # BeOS running on Intel PC compatible. echo i586-pc-beos exit ;; SX-4:SUPER-UX:*:*) echo sx4-nec-superux${UNAME_RELEASE} exit ;; SX-5:SUPER-UX:*:*) echo sx5-nec-superux${UNAME_RELEASE} exit ;; SX-6:SUPER-UX:*:*) echo sx6-nec-superux${UNAME_RELEASE} exit ;; SX-7:SUPER-UX:*:*) echo sx7-nec-superux${UNAME_RELEASE} exit ;; SX-8:SUPER-UX:*:*) echo sx8-nec-superux${UNAME_RELEASE} exit ;; SX-8R:SUPER-UX:*:*) echo sx8r-nec-superux${UNAME_RELEASE} exit ;; Power*:Rhapsody:*:*) echo powerpc-apple-rhapsody${UNAME_RELEASE} exit ;; *:Rhapsody:*:*) echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE} exit ;; *:Darwin:*:*) UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown case $UNAME_PROCESSOR in unknown) UNAME_PROCESSOR=powerpc ;; esac echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE} exit ;; *:procnto*:*:* | *:QNX:[0123456789]*:*) UNAME_PROCESSOR=`uname -p` if test "$UNAME_PROCESSOR" = "x86"; then UNAME_PROCESSOR=i386 UNAME_MACHINE=pc fi echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE} exit ;; *:QNX:*:4*) echo i386-pc-qnx exit ;; NSE-?:NONSTOP_KERNEL:*:*) echo nse-tandem-nsk${UNAME_RELEASE} exit ;; NSR-?:NONSTOP_KERNEL:*:*) echo nsr-tandem-nsk${UNAME_RELEASE} exit ;; *:NonStop-UX:*:*) echo mips-compaq-nonstopux exit ;; BS2000:POSIX*:*:*) echo bs2000-siemens-sysv exit ;; DS/*:UNIX_System_V:*:*) echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE} exit ;; *:Plan9:*:*) # "uname -m" is not consistent, so use $cputype instead. 386 # is converted to i386 for consistency with other x86 # operating systems. if test "$cputype" = "386"; then UNAME_MACHINE=i386 else UNAME_MACHINE="$cputype" fi echo ${UNAME_MACHINE}-unknown-plan9 exit ;; *:TOPS-10:*:*) echo pdp10-unknown-tops10 exit ;; *:TENEX:*:*) echo pdp10-unknown-tenex exit ;; KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*) echo pdp10-dec-tops20 exit ;; XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*) echo pdp10-xkl-tops20 exit ;; *:TOPS-20:*:*) echo pdp10-unknown-tops20 exit ;; *:ITS:*:*) echo pdp10-unknown-its exit ;; SEI:*:*:SEIUX) echo mips-sei-seiux${UNAME_RELEASE} exit ;; *:DragonFly:*:*) echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` exit ;; *:*VMS:*:*) UNAME_MACHINE=`(uname -p) 2>/dev/null` case "${UNAME_MACHINE}" in A*) echo alpha-dec-vms ; exit ;; I*) echo ia64-dec-vms ; exit ;; V*) echo vax-dec-vms ; exit ;; esac ;; *:XENIX:*:SysV) echo i386-pc-xenix exit ;; i*86:skyos:*:*) echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//' exit ;; i*86:rdos:*:*) echo ${UNAME_MACHINE}-pc-rdos exit ;; esac #echo '(No uname command or uname output not recognized.)' 1>&2 #echo "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" 1>&2 eval $set_cc_for_build 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\n"); 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`; if (version < 4) printf ("%s-next-nextstep%d\n", __ARCHITECTURE__, version); else printf ("%s-next-openstep%d\n", __ARCHITECTURE__, version); 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-pc-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) # include # if defined (BSD) # if BSD == 43 printf ("vax-dec-bsd4.3\n"); exit (0); # else # if BSD == 199006 printf ("vax-dec-bsd4.3reno\n"); exit (0); # else printf ("vax-dec-bsd\n"); exit (0); # endif # endif # else printf ("vax-dec-bsd\n"); exit (0); # endif # 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_FOR_BUILD -o $dummy $dummy.c 2>/dev/null && SYSTEM_NAME=`$dummy` && { echo "$SYSTEM_NAME"; exit; } # Apollos put the system type in the environment. test -d /usr/apollo && { echo ${ISP}-apollo-${SYSTYPE}; exit; } # 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 ;; c2*) if getsysinfo -f scalar_acc then echo c32-convex-bsd else echo c2-convex-bsd fi exit ;; c34*) echo c34-convex-bsd exit ;; c38*) echo c38-convex-bsd exit ;; c4*) echo c4-convex-bsd exit ;; esac fi cat >&2 < in order to provide the needed information to handle your system. config.guess timestamp = $timestamp uname -m = `(uname -m) 2>/dev/null || echo unknown` uname -r = `(uname -r) 2>/dev/null || echo unknown` uname -s = `(uname -s) 2>/dev/null || echo unknown` uname -v = `(uname -v) 2>/dev/null || echo unknown` /usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null` /bin/uname -X = `(/bin/uname -X) 2>/dev/null` hostinfo = `(hostinfo) 2>/dev/null` /bin/universe = `(/bin/universe) 2>/dev/null` /usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null` /bin/arch = `(/bin/arch) 2>/dev/null` /usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null` /usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null` UNAME_MACHINE = ${UNAME_MACHINE} UNAME_RELEASE = ${UNAME_RELEASE} UNAME_SYSTEM = ${UNAME_SYSTEM} UNAME_VERSION = ${UNAME_VERSION} EOF exit 1 # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rdup-1.1.15/config.sub000077500000000000000000000776311303430127500145500ustar00rootroot00000000000000#! /bin/sh # Configuration validation subroutine script. # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, # 2000, 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, # Inc. timestamp='2007-01-18' # 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., 51 Franklin Street - Fifth Floor, Boston, MA # 02110-1301, 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. # Please send patches to . Submit a context # diff and a properly formatted ChangeLog entry. # # 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 # or in some cases, the newer four-part form: # CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM # It is wrong to echo any other type of specification. me=`echo "$0" | sed -e 's,.*/,,'` usage="\ Usage: $0 [OPTION] CPU-MFR-OPSYS $0 [OPTION] ALIAS Canonicalize a configuration name. Operation modes: -h, --help print this help, then exit -t, --time-stamp print date of last modification, then exit -v, --version print version number, then exit Report bugs and patches to ." version="\ GNU config.sub ($timestamp) Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE." help=" Try \`$me --help' for more information." # Parse command line while test $# -gt 0 ; do case $1 in --time-stamp | --time* | -t ) echo "$timestamp" ; exit ;; --version | -v ) echo "$version" ; exit ;; --help | --h* | -h ) echo "$usage"; exit ;; -- ) # Stop option processing shift; break ;; - ) # Use stdin as input. break ;; -* ) echo "$me: invalid option $1$help" exit 1 ;; *local*) # First pass through any local machine types. echo $1 exit ;; * ) break ;; esac done case $# in 0) echo "$me: missing argument$help" >&2 exit 1;; 1) ;; *) echo "$me: too many arguments$help" >&2 exit 1;; esac # Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any). # Here we must recognize all the valid KERNEL-OS combinations. maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'` case $maybe_os in nto-qnx* | linux-gnu* | linux-dietlibc | linux-newlib* | linux-uclibc* | \ uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | knetbsd*-gnu* | netbsd*-gnu* | \ storm-chaos* | os2-emx* | rtmk-nova*) os=-$maybe_os basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'` ;; *) basic_machine=`echo $1 | sed 's/-[^-]*$//'` if [ $basic_machine != $1 ] then os=`echo $1 | sed 's/.*-/-/'` else os=; fi ;; esac ### 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 | \ -apple | -axis | -knuth | -cray) os= basic_machine=$1 ;; -sim | -cisco | -oki | -wec | -winbond) os= basic_machine=$1 ;; -scout) ;; -wrs) os=-vxworks basic_machine=$1 ;; -chorusos*) os=-chorusos basic_machine=$1 ;; -chorusrdb) os=-chorusrdb basic_machine=$1 ;; -hiux*) os=-hiuxwe2 ;; -sco6) os=-sco5v6 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5) os=-sco3.2v5 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco4) os=-sco3.2v4 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2.[4-9]*) os=`echo $os | sed -e 's/sco3.2./sco3.2v/'` basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco3.2v[4-9]*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco5v6*) # Don't forget version if it is 3.2v4 or newer. basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -sco*) os=-sco3.2v2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -udk*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -isc) os=-isc2.2 basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -clix*) basic_machine=clipper-intergraph ;; -isc*) basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'` ;; -lynx*) os=-lynxos ;; -ptx*) basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'` ;; -windowsnt*) os=`echo $os | sed -e 's/windowsnt/winnt/'` ;; -psos*) os=-psos ;; -mint | -mint[0-9]*) basic_machine=m68k-atari os=-mint ;; 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. 1750a | 580 \ | a29k \ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \ | am33_2.0 \ | arc | arm | arm[bl]e | arme[lb] | armv[2345] | armv[345][lb] | avr | avr32 \ | bfin \ | c4x | clipper \ | d10v | d30v | dlx | dsp16xx \ | fido | fr30 | frv \ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \ | i370 | i860 | i960 | ia64 \ | ip2k | iq2000 \ | m32c | m32r | m32rle | m68000 | m68k | m88k \ | maxq | mb | microblaze | mcore | mep \ | mips | mipsbe | mipseb | mipsel | mipsle \ | mips16 \ | mips64 | mips64el \ | mips64vr | mips64vrel \ | mips64orion | mips64orionel \ | mips64vr4100 | mips64vr4100el \ | mips64vr4300 | mips64vr4300el \ | mips64vr5000 | mips64vr5000el \ | mips64vr5900 | mips64vr5900el \ | mipsisa32 | mipsisa32el \ | mipsisa32r2 | mipsisa32r2el \ | mipsisa64 | mipsisa64el \ | mipsisa64r2 | mipsisa64r2el \ | mipsisa64sb1 | mipsisa64sb1el \ | mipsisa64sr71k | mipsisa64sr71kel \ | mipstx39 | mipstx39el \ | mn10200 | mn10300 \ | mt \ | msp430 \ | nios | nios2 \ | ns16k | ns32k \ | or32 \ | pdp10 | pdp11 | pj | pjl \ | powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \ | pyramid \ | score \ | sh | sh[1234] | sh[24]a | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \ | sh64 | sh64le \ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \ | spu | strongarm \ | tahoe | thumb | tic4x | tic80 | tron \ | v850 | v850e \ | we32k \ | x86 | xc16x | xscale | xscalee[bl] | xstormy16 | xtensa \ | z8k) basic_machine=$basic_machine-unknown ;; m6811 | m68hc11 | m6812 | m68hc12) # Motorola 68HC11/12. basic_machine=$basic_machine-unknown os=-none ;; m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k) ;; ms1) basic_machine=mt-unknown ;; # We use `pc' rather than `unknown' # because (1) that's what they normally are, and # (2) the word "unknown" tends to confuse beginning users. i*86 | x86_64) basic_machine=$basic_machine-pc ;; # 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. 580-* \ | a29k-* \ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* \ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \ | avr-* | avr32-* \ | bfin-* | bs2000-* \ | c[123]* | c30-* | [cjt]90-* | c4x-* | c54x-* | c55x-* | c6x-* \ | clipper-* | craynv-* | cydra-* \ | d10v-* | d30v-* | dlx-* \ | elxsi-* \ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \ | h8300-* | h8500-* \ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \ | i*86-* | i860-* | i960-* | ia64-* \ | ip2k-* | iq2000-* \ | m32c-* | m32r-* | m32rle-* \ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \ | m88110-* | m88k-* | maxq-* | mcore-* \ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \ | mips16-* \ | mips64-* | mips64el-* \ | mips64vr-* | mips64vrel-* \ | mips64orion-* | mips64orionel-* \ | mips64vr4100-* | mips64vr4100el-* \ | mips64vr4300-* | mips64vr4300el-* \ | mips64vr5000-* | mips64vr5000el-* \ | mips64vr5900-* | mips64vr5900el-* \ | mipsisa32-* | mipsisa32el-* \ | mipsisa32r2-* | mipsisa32r2el-* \ | mipsisa64-* | mipsisa64el-* \ | mipsisa64r2-* | mipsisa64r2el-* \ | mipsisa64sb1-* | mipsisa64sb1el-* \ | mipsisa64sr71k-* | mipsisa64sr71kel-* \ | mipstx39-* | mipstx39el-* \ | mmix-* \ | mt-* \ | msp430-* \ | nios-* | nios2-* \ | none-* | np1-* | ns16k-* | ns32k-* \ | orion-* \ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \ | pyramid-* \ | romp-* | rs6000-* \ | sh-* | sh[1234]-* | sh[24]a-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \ | sparclite-* \ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | strongarm-* | sv1-* | sx?-* \ | tahoe-* | thumb-* \ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \ | tron-* \ | v850-* | v850e-* | vax-* \ | we32k-* \ | x86-* | x86_64-* | xc16x-* | xps100-* | xscale-* | xscalee[bl]-* \ | xstormy16-* | xtensa-* \ | ymp-* \ | z8k-*) ;; # Recognize the various machine names and aliases which stand # for a CPU type and a company and sometimes even an OS. 386bsd) basic_machine=i386-unknown os=-bsd ;; 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc) basic_machine=m68000-att ;; 3b*) basic_machine=we32k-att ;; a29khif) basic_machine=a29k-amd os=-udi ;; abacus) basic_machine=abacus-unknown ;; adobe68k) basic_machine=m68010-adobe os=-scout ;; alliant | fx80) basic_machine=fx80-alliant ;; altos | altos3068) basic_machine=m68k-altos ;; am29k) basic_machine=a29k-none os=-bsd ;; amd64) basic_machine=x86_64-pc ;; amd64-*) basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; amdahl) basic_machine=580-amdahl os=-sysv ;; amiga | amiga-*) basic_machine=m68k-unknown ;; amigaos | amigados) basic_machine=m68k-unknown os=-amigaos ;; amigaunix | amix) basic_machine=m68k-unknown os=-sysv4 ;; apollo68) basic_machine=m68k-apollo os=-sysv ;; apollo68bsd) basic_machine=m68k-apollo os=-bsd ;; aux) basic_machine=m68k-apple os=-aux ;; balance) basic_machine=ns32k-sequent os=-dynix ;; c90) basic_machine=c90-cray os=-unicos ;; 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 | j90) basic_machine=j90-cray os=-unicos ;; craynv) basic_machine=craynv-cray os=-unicosmp ;; cr16c) basic_machine=cr16c-unknown os=-elf ;; crds | unos) basic_machine=m68k-crds ;; crisv32 | crisv32-* | etraxfs*) basic_machine=crisv32-axis ;; cris | cris-* | etrax*) basic_machine=cris-axis ;; crx) basic_machine=crx-unknown os=-elf ;; da30 | da30-*) basic_machine=m68k-da30 ;; decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn) basic_machine=mips-dec ;; decsystem10* | dec10*) basic_machine=pdp10-dec os=-tops10 ;; decsystem20* | dec20*) basic_machine=pdp10-dec os=-tops20 ;; delta | 3300 | motorola-3300 | motorola-delta \ | 3300-motorola | delta-motorola) basic_machine=m68k-motorola ;; delta88) basic_machine=m88k-motorola os=-sysv3 ;; djgpp) basic_machine=i586-pc os=-msdosdjgpp ;; 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 ;; es1800 | OSE68k | ose68k | ose | OSE) basic_machine=m68k-ericsson os=-ose ;; fx2800) basic_machine=i860-alliant ;; genix) basic_machine=ns32k-ns ;; gmicro) basic_machine=tron-gmicro os=-sysv ;; go32) basic_machine=i386-pc os=-go32 ;; h3050r* | hiux*) basic_machine=hppa1.1-hitachi os=-hiuxwe2 ;; h8300hms) basic_machine=h8300-hitachi os=-hms ;; h8300xray) basic_machine=h8300-hitachi os=-xray ;; h8500hms) basic_machine=h8500-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 ;; hp3k9[0-9][0-9] | hp9[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k2[0-9][0-9] | hp9k31[0-9]) basic_machine=m68000-hp ;; hp9k3[2-9][0-9]) basic_machine=m68k-hp ;; hp9k6[0-9][0-9] | hp6[0-9][0-9]) basic_machine=hppa1.0-hp ;; hp9k7[0-79][0-9] | hp7[0-79][0-9]) basic_machine=hppa1.1-hp ;; hp9k78[0-9] | hp78[0-9]) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893) # FIXME: really hppa2.0-hp basic_machine=hppa1.1-hp ;; hp9k8[0-9][13679] | hp8[0-9][13679]) basic_machine=hppa1.1-hp ;; hp9k8[0-9][0-9] | hp8[0-9][0-9]) basic_machine=hppa1.0-hp ;; hppa-next) os=-nextstep3 ;; hppaosf) basic_machine=hppa1.1-hp os=-osf ;; hppro) basic_machine=hppa1.1-hp os=-proelf ;; i370-ibm* | ibm*) basic_machine=i370-ibm ;; # I'm not sure what "Sysv32" means. Should this be sysv3.2? i*86v32) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv32 ;; i*86v4*) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv4 ;; i*86v) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-sysv ;; i*86sol2) basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'` os=-solaris2 ;; i386mach) basic_machine=i386-mach os=-mach ;; i386-vsta | vsta) basic_machine=i386-unknown os=-vsta ;; 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 ;; mingw32) basic_machine=i386-pc os=-mingw32 ;; miniframe) basic_machine=m68000-convergent ;; *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*) basic_machine=m68k-atari os=-mint ;; mips3*-*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'` ;; mips3*) basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown ;; monitor) basic_machine=m68k-rom68k os=-coff ;; morphos) basic_machine=powerpc-unknown os=-morphos ;; msdos) basic_machine=i386-pc os=-msdos ;; ms1-*) basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'` ;; mvs) basic_machine=i370-ibm os=-mvs ;; ncr3000) basic_machine=i486-ncr os=-sysv4 ;; netbsd386) basic_machine=i386-unknown os=-netbsd ;; netwinder) basic_machine=armv4l-rebel os=-linux ;; 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 ;; necv70) basic_machine=v70-nec os=-sysv ;; 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 ;; mon960) basic_machine=i960-intel os=-mon960 ;; nonstopux) basic_machine=mips-compaq os=-nonstopux ;; np1) basic_machine=np1-gould ;; nsr-tandem) basic_machine=nsr-tandem ;; op50n-* | op60c-*) basic_machine=hppa1.1-oki os=-proelf ;; openrisc | openrisc-*) basic_machine=or32-unknown ;; os400) basic_machine=powerpc-ibm os=-os400 ;; OSE68000 | ose68000) basic_machine=m68000-ericsson os=-ose ;; os68k) basic_machine=m68k-none os=-os68k ;; 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 ;; pc98) basic_machine=i386-pc ;; pc98-*) basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium | p5 | k5 | k6 | nexgen | viac3) basic_machine=i586-pc ;; pentiumpro | p6 | 6x86 | athlon | athlon_*) basic_machine=i686-pc ;; pentiumii | pentium2 | pentiumiii | pentium3) basic_machine=i686-pc ;; pentium4) basic_machine=i786-pc ;; pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*) basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumpro-* | p6-* | 6x86-* | athlon-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*) basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pentium4-*) basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'` ;; pn) basic_machine=pn-gould ;; power) basic_machine=power-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/^[^-]*-//'` ;; ppc64) basic_machine=powerpc64-unknown ;; ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ppc64le | powerpc64little | ppc64-le | powerpc64-little) basic_machine=powerpc64le-unknown ;; ppc64le-* | powerpc64little-*) basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'` ;; ps2) basic_machine=i386-ibm ;; pw32) basic_machine=i586-unknown os=-pw32 ;; rdos) basic_machine=i386-pc os=-rdos ;; rom68k) basic_machine=m68k-rom68k os=-coff ;; rm[46]00) basic_machine=mips-siemens ;; rtpc | rtpc-*) basic_machine=romp-ibm ;; s390 | s390-*) basic_machine=s390-ibm ;; s390x | s390x-*) basic_machine=s390x-ibm ;; sa29200) basic_machine=a29k-amd os=-udi ;; sb1) basic_machine=mipsisa64sb1-unknown ;; sb1el) basic_machine=mipsisa64sb1el-unknown ;; sde) basic_machine=mipsisa32-sde os=-elf ;; sei) basic_machine=mips-sei os=-seiux ;; sequent) basic_machine=i386-sequent ;; sh) basic_machine=sh-hitachi os=-hms ;; sh5el) basic_machine=sh5le-unknown ;; sh64) basic_machine=sh64-unknown ;; sparclite-wrs | simso-wrs) basic_machine=sparclite-wrs os=-vxworks ;; sps7) basic_machine=m68k-bull os=-sysv2 ;; spur) basic_machine=spur-unknown ;; st2000) basic_machine=m68k-tandem ;; stratus) basic_machine=i860-stratus os=-sysv4 ;; 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 ;; sv1) basic_machine=sv1-cray os=-unicos ;; symmetry) basic_machine=i386-sequent os=-dynix ;; t3e) basic_machine=alphaev5-cray os=-unicos ;; t90) basic_machine=t90-cray os=-unicos ;; tic54x | c54x*) basic_machine=tic54x-unknown os=-coff ;; tic55x | c55x*) basic_machine=tic55x-unknown os=-coff ;; tic6x | c6x*) basic_machine=tic6x-unknown os=-coff ;; tx39) basic_machine=mipstx39-unknown ;; tx39el) basic_machine=mipstx39el-unknown ;; toad1) basic_machine=pdp10-xkl os=-tops20 ;; tower | tower-32) basic_machine=m68k-ncr ;; tpf) basic_machine=s390x-ibm os=-tpf ;; udi29k) basic_machine=a29k-amd os=-udi ;; ultra3) basic_machine=a29k-nyu os=-sym1 ;; v810 | necv810) basic_machine=v810-nec os=-none ;; vaxv) basic_machine=vax-dec os=-sysv ;; vms) basic_machine=vax-dec os=-vms ;; vpp*|vx|vx-*) basic_machine=f301-fujitsu ;; vxworks960) basic_machine=i960-wrs os=-vxworks ;; vxworks68) basic_machine=m68k-wrs os=-vxworks ;; vxworks29k) basic_machine=a29k-wrs os=-vxworks ;; w65*) basic_machine=w65-wdc os=-none ;; w89k-*) basic_machine=hppa1.1-winbond os=-proelf ;; xbox) basic_machine=i686-pc os=-mingw32 ;; xps | xps100) basic_machine=xps100-honeywell ;; ymp) basic_machine=ymp-cray os=-unicos ;; z8k-*-coff) basic_machine=z8k-unknown os=-sim ;; 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. w89k) basic_machine=hppa1.1-winbond ;; op50n) basic_machine=hppa1.1-oki ;; op60c) basic_machine=hppa1.1-oki ;; romp) basic_machine=romp-ibm ;; mmix) basic_machine=mmix-knuth ;; rs6000) basic_machine=rs6000-ibm ;; vax) basic_machine=vax-dec ;; pdp10) # there are many clones, so DEC is not a safe bet basic_machine=pdp10-unknown ;; pdp11) basic_machine=pdp11-dec ;; we32k) basic_machine=we32k-att ;; sh[1234] | sh[24]a | sh[34]eb | sh[1234]le | sh[23]ele) basic_machine=sh-unknown ;; sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v) basic_machine=sparc-sun ;; cydra) basic_machine=cydra-cydrome ;; orion) basic_machine=orion-highlevel ;; orion105) basic_machine=clipper-highlevel ;; mac | mpw | mac-mpw) basic_machine=m68k-apple ;; pmac | pmac-mpw) basic_machine=powerpc-apple ;; *-unknown) # Make sure to match an already-canonicalized machine name. ;; *) 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 # First match some system type aliases # that might get confused with valid system types. # -solaris* is a basic system type, with this one exception. -solaris1 | -solaris1.*) os=`echo $os | sed -e 's|solaris1|sunos4|'` ;; -solaris) os=-solaris2 ;; -svr4*) os=-sysv4 ;; -unixware*) os=-sysv4.2uw ;; -gnu/linux*) os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'` ;; # 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[34]*\ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -solaris* | -sym* \ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \ | -aos* \ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \ | -openbsd* | -solidbsd* \ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \ | -chorusos* | -chorusrdb* \ | -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \ | -mingw32* | -linux-gnu* | -linux-newlib* | -linux-uclibc* \ | -uxpv* | -beos* | -mpeix* | -udk* \ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \ | -skyos* | -haiku* | -rdos* | -toppers* | -drops*) # Remember, each alternative MUST END IN *, to match a version number. ;; -qnx*) case $basic_machine in x86-* | i*86-*) ;; *) os=-nto$os ;; esac ;; -nto-qnx*) ;; -nto*) os=`echo $os | sed -e 's|nto|nto-qnx|'` ;; -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*) ;; -mac*) os=`echo $os | sed -e 's|mac|macos|'` ;; -linux-dietlibc) os=-linux-dietlibc ;; -linux*) os=`echo $os | sed -e 's|linux|linux-gnu|'` ;; -sunos5*) os=`echo $os | sed -e 's|sunos5|solaris2|'` ;; -sunos6*) os=`echo $os | sed -e 's|sunos6|solaris3|'` ;; -opened*) os=-openedition ;; -os400*) os=-os400 ;; -wince*) os=-wince ;; -osfrose*) os=-osfrose ;; -osf*) os=-osf ;; -utek*) os=-bsd ;; -dynix*) os=-bsd ;; -acis*) os=-aos ;; -atheos*) os=-atheos ;; -syllable*) os=-syllable ;; -386bsd) os=-bsd ;; -ctix* | -uts*) os=-sysv ;; -nova*) os=-rtmk-nova ;; -ns2 ) os=-nextstep2 ;; -nsk*) os=-nsk ;; # Preserve the version number of sinix5. -sinix5.*) os=`echo $os | sed -e 's|sinix|sysv|'` ;; -sinix*) os=-sysv4 ;; -tpf*) os=-tpf ;; -triton*) os=-sysv3 ;; -oss*) os=-sysv3 ;; -svr4) os=-sysv4 ;; -svr3) os=-sysv3 ;; -sysvr4) os=-sysv4 ;; # This must come after -sysvr4. -sysv*) ;; -ose*) os=-ose ;; -es1800*) os=-ose ;; -xenix) os=-xenix ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) os=-mint ;; -aros*) os=-aros ;; -kaos*) os=-kaos ;; -zvmoe) os=-zvmoe ;; -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 score-*) os=-elf ;; spu-*) os=-elf ;; *-acorn) os=-riscix1.2 ;; arm*-rebel) os=-linux ;; arm*-semi) os=-aout ;; c4x-* | tic4x-*) os=-coff ;; # This must come before the *-dec entry. pdp10-*) os=-tops20 ;; 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 ;; m68*-cisco) os=-aout ;; mep-*) os=-elf ;; mips*-cisco) os=-elf ;; mips*-*) os=-elf ;; or32-*) os=-coff ;; *-tti) # must be before sparc entry or we get the wrong os. os=-sysv3 ;; sparc-* | *-sun) os=-sunos4.1.1 ;; *-be) os=-beos ;; *-haiku) os=-haiku ;; *-ibm) os=-aix ;; *-knuth) os=-mmixware ;; *-wec) os=-proelf ;; *-winbond) os=-proelf ;; *-oki) os=-proelf ;; *-hp) os=-hpux ;; *-hitachi) os=-hiux ;; i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent) os=-sysv ;; *-cbm) os=-amigaos ;; *-dg) os=-dgux ;; *-dolphin) os=-sysv3 ;; m68k-ccur) os=-rtu ;; m88k-omron*) os=-luna ;; *-next ) os=-nextstep ;; *-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 ;; f30[01]-fujitsu | f700-fujitsu) os=-uxpv ;; *-rom68k) os=-coff ;; *-*bug) os=-coff ;; *-apple) os=-macos ;; *-atari*) os=-mint ;; *) 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 ;; -aix*) vendor=ibm ;; -beos*) vendor=be ;; -hpux*) vendor=hp ;; -mpeix*) vendor=hp ;; -hiux*) vendor=hitachi ;; -unos*) vendor=crds ;; -dgux*) vendor=dg ;; -luna*) vendor=omron ;; -genix*) vendor=ns ;; -mvs* | -opened*) vendor=ibm ;; -os400*) vendor=ibm ;; -ptx*) vendor=sequent ;; -tpf*) vendor=ibm ;; -vxsim* | -vxworks* | -windiss*) vendor=wrs ;; -aux*) vendor=apple ;; -hms*) vendor=hitachi ;; -mpw* | -macos*) vendor=apple ;; -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*) vendor=atari ;; -vos*) vendor=stratus ;; esac basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"` ;; esac echo $basic_machine$os exit # Local variables: # eval: (add-hook 'write-file-hooks 'time-stamp) # time-stamp-start: "timestamp='" # time-stamp-format: "%:y-%02m-%02d" # time-stamp-end: "'" # End: rdup-1.1.15/configure.ac000066400000000000000000000070211303430127500150350ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ(2.57) AC_INIT(rdup, 1.1.14, miek@miek.nl, rdup) AC_CONFIG_SRCDIR([rdup.c]) AC_PREFIX_DEFAULT(/usr/local) sinclude(glib-2.0.m4) AC_AIX AC_PROG_CC AC_PROG_MAKE_SET AM_PATH_GLIB_2_0(2.0.0,,AC_MSG_ERROR([** No glib2-dev library found.])) # dirfd stuff AC_CHECK_FUNCS([dirfd]) AC_CHECK_MEMBERS([DIR.d_fd],,, [[#include ]]) AC_CHECK_MEMBERS([DIR.dd_fd],,, [[#include ]]) AC_CHECK_HEADERS([getopt.h dirent.h sys/vfs.h sys/statvfs.h sys/sysmacros.h]) AC_CHECK_HEADERS(sys/param.h sys/mount.h,,, [ [ #if HAVE_SYS_PARAM_H # include #endif ] ]) AC_ARG_ENABLE([debug], AS_HELP_STRING([--enable-debug], [Turn on debugging])) if test "x$enable_debug" = "xyes"; then CFLAGS="${CFLAGS} -g -DDEBUG" DEBUG=yes AC_SUBST(DEBUG) fi # post 1.0, this can be turned on # --disable-nls if you do not need it #AM_GNU_GETTEXT([external]) #AM_GNU_GETTEXT_VERSION AC_CHECK_LIB(archive, archive_entry_copy_symlink, ,ARCHIVE_L="no") if test "$ARCHIVE_L" = "no"; then AC_MSG_WARN([** No archive library found; not building rdup-tr.]) else : AC_SUBST(HAVE_LIBARCHIVE) AC_SUBST(ARCHIVE_L) fi AC_ARG_WITH(libpcre_includes, [ --with-libpcre-includes=DIR libpcre include directory], [with_libpcre_includes="$withval"],[with_libpcre_includes=no]) AC_ARG_WITH(libpcre_libraries, [ --with-libpcre-libraries=DIR libpcre library directory], [with_libpcre_libraries="$withval"],[with_libpcre_libraries=no]) if test "$with_libpcre_includes" != "no"; then CFLAGS="${CFLAGS} -I${with_libpcre_includes}" else CFLAGS="${CFLAGS} `pcre-config --cflags`" fi if test "$with_libpcre_libraries" != "no"; then LIBS="${LIBS} -L${with_libpcre_libraries}" else LIBS="${LIBS} `pcre-config --libs`" fi # PCRE configuration (required) # Verify that we have the headers PCRE_H="" AC_CHECK_HEADERS(pcre.h,, PCRE_H="no") if test "$PCRE_H" = "no"; then AC_MSG_ERROR([** No pcre library found.]) fi # Verify that we have the library PCRE_L="" AC_CHECK_LIB(pcre, pcre_compile, ,PCRE_L="no") if test "$PCRE_L" = "no"; then AC_MSG_ERROR([** No pcre library found.]) fi AC_ARG_WITH(libnettle_includes, [ --with-libnettle-includes=DIR libnettle include directory], [with_libnettle_includes="$withval"],[with_libnettle_includes=no]) AC_ARG_WITH(libnettle_libraries, [ --with-libnettle-libraries=DIR libnettle library directory], [with_libnettle_libraries="$withval"],[with_libnettle_libraries=no]) if test "$with_libnettle_includes" != "no"; then CFLAGS="${CFLAGS} -I${with_libnettle_includes}" fi if test "$with_libnettle_libraries" != "no"; then LIBS="${LIBS} -L${with_libnettle_libraries}" fi NETTLE_H="" AC_CHECK_HEADERS(nettle/aes.h,, NETTLE_H="no") if test "$NETTLE_H" = "no"; then AC_MSG_WARN([** No nettle library found.]) fi # This fails on my Fedora 11 machine - just assume we # can do aes... NETTLE_L="" AC_CHECK_LIB(nettle, nettle_aes_encrypt, ,NETTLE_L="no") if test "$NETTLE_L" = "no"; then AC_MSG_WARN([** No nettle library found.]) fi AC_SUBST(NETTLE_L) # sysconfdir if test ${sysconfdir} = '${prefix}/etc'; then sysconfdir='/etc' fi AC_CONFIG_FILES([GNUmakefile po/GNUmakefile rdup.h rdup-tr.h rdup-up.h doc/rdup.1 doc/rdup-tr.1 doc/rdup-up.1 ]) AC_CONFIG_HEADER([config.h]) AC_OUTPUT rdup-1.1.15/contrib/000077500000000000000000000000001303430127500142075ustar00rootroot00000000000000rdup-1.1.15/contrib/README000066400000000000000000000003471303430127500150730ustar00rootroot00000000000000These are third party scripts. They are provided AS-IS, the original author and license are included in each source file. prune.rb -- deletes old backups convert.pl -- convert internal rdup filelist from version 1.0 to 1.1 format rdup-1.1.15/contrib/convert.pl000066400000000000000000000003721303430127500162260ustar00rootroot00000000000000#!/usr/bin/perl -wn # convert a pre 1.1.x internal rdup filelist to rdup 1.1.x format # Author: Miek Gieben (miek@miek.nl) # License: GPLv3 split; if ($_[0] eq "41471") { $l[3] = "l" } # symlink if ($_[3] eq "*") { $l[3] = "-" } print "@_\n"; rdup-1.1.15/contrib/prune.rb000066400000000000000000000016651303430127500156750ustar00rootroot00000000000000#!/usr/bin/env ruby # Deletes/Prunes old backups # Use at your own risk # # Author: Matthias-Christian Ott (ott@mirix.org) # License: GPLv3 require 'optparse' require 'date' require 'fileutils' options = { :limit => 30 } OptionParser.new do |opts| opts.on '-l', '--limit limit', "set archive limit (default: #{options[:limit]})" do |v| options[:limit] = v.to_i end end.parse! if ARGV.size < 1 warn "no backup directory given" exit 1 elsif ARGV.size > 1 warn "more than one backup directory given" exit 1 end today = DateTime.strptime Time.now.strftime('%Y%m/%d'), '%Y%m/%d' limit = today - options[:limit] Dir.chdir ARGV[0] Dir.glob '*/*' do |entry| begin date = DateTime.strptime entry, '%Y%m/%d' rescue next end if date < limit FileUtils.rm_r entry end topdir = date.strftime '%Y%m' entries = Dir.entries(topdir) - ['.', '..'] p entries if entries.empty? FileUtils.rmdir topdir end end rdup-1.1.15/crawler.c000066400000000000000000000173601303430127500143610ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * * Directory crawler */ #include "rdup.h" extern gboolean opt_onefilesystem; extern gboolean opt_nobackup; extern gboolean opt_chown; extern time_t opt_timestamp; extern gint opt_verbose; extern GSList *pregex_list; /* common.c */ struct rdup *entry_dup(struct rdup *); void entry_free(struct rdup *); /** * prepend path leading up to backup directory to the tree */ gboolean dir_prepend(GTree * t, char *path, GHashTable * u, GHashTable * g) { char *c; char *p; char *path2; size_t len; struct stat s; struct rdup e; path2 = g_strdup(path); len = strlen(path); /* add closing / */ if (path2[len - 1] != '/') { path2 = g_realloc(path2, len + 2); path2[len] = '/'; path2[len + 1] = '\0'; } for (p = path2 + 1; (c = strchr(p, '/')); p++) { *c = '\0'; if (lstat(path2, &s) != 0) { msg(_("Could not stat path `%s\': %s"), path2, strerror(errno)); g_free(path2); return FALSE; } e.f_name = path2; e.f_target = NULL; e.f_name_size = strlen(path2); e.f_uid = s.st_uid; e.f_user = lookup_user(u, e.f_uid); e.f_gid = s.st_gid; e.f_group = lookup_group(g, e.f_gid); e.f_ctime = s.st_ctime; e.f_mtime = s.st_mtime; e.f_atime = s.st_atime; e.f_mode = s.st_mode; e.f_size = s.st_size; e.f_dev = s.st_dev; e.f_rdev = s.st_rdev; e.f_ino = s.st_ino; e.f_lnk = 0; /* symlinks; also set the target */ if (S_ISLNK(s.st_mode)) { e.f_target = slink(&e); e.f_size = e.f_name_size; e.f_name_size += 4 + strlen(e.f_target); /* When we encounter a symlink on this level, it is very hard to make this * backup work, because the target may fall out of the backup. If this * is the case the entire backup fails. Gnu tar only show the symlink * and then stops. We do now the same, heance the return FALSE */ g_tree_insert(t, (gpointer) entry_dup(&e), VALUE); g_free(e.f_target); g_free(path2); return FALSE; } g_tree_insert(t, (gpointer) entry_dup(&e), VALUE); *c = '/'; p = c++; } g_free(path2); return TRUE; } void dir_crawl(GTree * t, GHashTable * linkhash, GHashTable * userhash, GHashTable * grouphash, char *path) { DIR *dir; struct dirent *dent; struct rdup *directory; struct chown_pack *cp; char *curpath; gchar *lnk; struct stat s; struct rdup pop; struct remove_path rp; dev_t current_dev; size_t curpath_len; /* dir stack */ gint32 d = 0; gint32 dstack_cnt = 1; struct rdup **dirstack = g_malloc(dstack_cnt * D_STACKSIZE * sizeof(struct rdup *)); if (!(dir = opendir(path))) { /* non-dirs are also allowed, check for this, if it isn't give the error */ if (access(path, R_OK) == 0) { g_free(dirstack); return; } msg(_("Cannot enter directory `%s\': %s"), path, strerror(errno)); g_free(dirstack); return; } /* get device */ #ifdef HAVE_DIRFD if (fstat(dirfd(dir), &s) != 0) { #else if (fstat(rdup_dirfd(dir), &s) != 0) { #endif msg(_ ("Cannot determine holding device of the directory `%s\': %s"), path, strerror(errno)); closedir(dir); g_free(dirstack); return; } current_dev = s.st_dev; while ((dent = readdir(dir))) { if (!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, "..")) continue; if (opt_chown) { if (!strncmp(dent->d_name, USRGRPINFO, LEN_USRGRPINFO)) { continue; } } if (strcmp(path, "/") == 0) { curpath = g_strdup_printf("/%s", dent->d_name); curpath_len = strlen(curpath); } else { curpath = g_strdup_printf("%s/%s", path, dent->d_name); curpath_len = strlen(curpath); } if (lstat(curpath, &s) != 0) { msg(_("Could not stat path `%s\': %s"), curpath, strerror(errno)); g_free(curpath); continue; } if (strchr(curpath, '\n')) { msg(_("Newline (\\n) found in path `%s\', skipping"), curpath); g_free(curpath); continue; } if (S_ISREG(s.st_mode) || S_ISLNK(s.st_mode) || S_ISBLK(s.st_mode) || S_ISCHR(s.st_mode) || S_ISFIFO(s.st_mode) || S_ISSOCK(s.st_mode)) { pop.f_name = curpath; pop.f_target = NULL; pop.f_name_size = curpath_len; pop.f_uid = s.st_uid; pop.f_user = lookup_user(userhash, pop.f_uid); pop.f_gid = s.st_gid; pop.f_group = lookup_group(grouphash, pop.f_gid); pop.f_ctime = s.st_ctime; pop.f_mtime = s.st_mtime; pop.f_atime = s.st_atime; pop.f_mode = s.st_mode; pop.f_size = s.st_size; pop.f_dev = s.st_dev; pop.f_rdev = s.st_rdev; pop.f_ino = s.st_ino; pop.f_lnk = 0; if (gfunc_regexp(pregex_list, curpath, curpath_len)) { g_free(curpath); continue; } /* hardlinks */ if (s.st_nlink > 1) { if ((lnk = hlink(linkhash, &pop))) { pop.f_target = lnk; pop.f_lnk = 1; } } if (S_ISLNK(s.st_mode)) pop.f_target = slink(&pop); if (S_ISLNK(s.st_mode) || pop.f_lnk) { /* fix the name and the sizes */ pop.f_size = pop.f_name_size; pop.f_name_size += 4 + strlen(pop.f_target); } /* check for USRGRPINFO file */ if (opt_chown && (cp = chown_parse(path, dent->d_name)) != NULL) { pop.f_uid = cp->u; pop.f_gid = cp->g; pop.f_user = cp->user; pop.f_group = cp->group; } if (opt_nobackup && !strcmp(dent->d_name, NOBACKUP)) { /* return after seeing .nobackup */ if (opt_verbose > 0) { msg(_("%s found in '%s\'"), NOBACKUP, path); } /* remove all files found in this path */ rp.tree = t; rp.len = strlen(path); rp.path = path; g_tree_foreach(t, gfunc_remove_path, (gpointer) & rp); /* add .nobackup back in */ g_tree_insert(t, (gpointer) entry_dup(&pop), VALUE); g_free(dirstack); closedir(dir); return; } g_tree_insert(t, (gpointer) entry_dup(&pop), VALUE); if (pop.f_target != NULL) g_free(pop.f_target); g_free(curpath); continue; } else if (S_ISDIR(s.st_mode)) { /* one filesystem */ if (opt_onefilesystem && s.st_dev != current_dev) { msg(_ ("Not walking into different filesystem `%s\'"), curpath); g_free(curpath); continue; } /* Exclude list */ if (gfunc_regexp(pregex_list, curpath, curpath_len)) { g_free(curpath); continue; } dirstack[d] = g_malloc(sizeof(struct rdup)); dirstack[d]->f_name = g_strdup(curpath); dirstack[d]->f_target = NULL; dirstack[d]->f_name_size = curpath_len; dirstack[d]->f_uid = s.st_uid; dirstack[d]->f_user = lookup_user(userhash, s.st_uid); dirstack[d]->f_gid = s.st_gid; dirstack[d]->f_group = lookup_group(grouphash, s.st_gid); dirstack[d]->f_ctime = s.st_ctime; dirstack[d]->f_mtime = s.st_mtime; dirstack[d]->f_atime = s.st_atime; dirstack[d]->f_mode = s.st_mode; dirstack[d]->f_size = s.st_size; dirstack[d]->f_dev = s.st_dev; dirstack[d]->f_rdev = s.st_rdev; dirstack[d]->f_ino = s.st_ino; dirstack[d]->f_lnk = 0; /* check for USRGRPINFO file */ if (opt_chown && (cp = chown_parse(curpath, NULL)) != NULL) { dirstack[d]->f_uid = cp->u; dirstack[d]->f_gid = cp->g; dirstack[d]->f_user = cp->user; dirstack[d]->f_group = cp->group; } if (d++ % D_STACKSIZE == 0) { dirstack = g_realloc(dirstack, ++dstack_cnt * D_STACKSIZE * sizeof(struct rdup *)); } g_free(curpath); continue; } else { if (opt_verbose > 0) { msg(_("Neither file nor directory `%s\'"), curpath); } g_free(curpath); } } closedir(dir); while (d > 0) { directory = dirstack[--d]; g_tree_insert(t, (gpointer) entry_dup(directory), VALUE); /* recurse */ /* potentially expensive operation. Better would be to when we hit * .nobackup to go up the tree and delete some nodes.... or not */ dir_crawl(t, linkhash, userhash, grouphash, directory->f_name); entry_free(directory); } g_free(dirstack); return; } rdup-1.1.15/crypt.c000066400000000000000000000143421303430127500140600ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * crypt.c * encrypt/decrypt paths * struct r_entry */ #include "rdup-tr.h" #include "base64.h" #ifdef HAVE_LIBNETTLE #include extern guint opt_verbose; /** * init the cryto * with key *key * and length length * lenght MUST be 16, 24 or 32 * anything short will be zero padded to * create a correct key * return aes context */ struct aes_ctx *crypt_init(gchar * key, gboolean crypt) { guint length = strlen(key); struct aes_ctx *ctx = g_malloc(sizeof(struct aes_ctx)); if (crypt) aes_set_encrypt_key(ctx, length, (uint8_t *) key); else aes_set_decrypt_key(ctx, length, (uint8_t *) key); return ctx; } static gboolean is_plain(gchar * s) { char *p; for (p = s; *p; p++) if (!isascii(*p)) return FALSE; return TRUE; } /* * don't do anything with the strings .. and . */ gchar *dot_dotdot(gchar * q, gchar * p, gboolean abs) { gchar *r = NULL; if (strcmp(q, "..") == 0) { if (p) r = g_strdup_printf("%s/%s", p, ".."); else abs ? (r = g_strdup("/..")) : (r = g_strdup("..")); } if (strcmp(q, ".") == 0) { if (p) r = g_strdup_printf("%s/%s", p, "."); else abs ? (r = g_strdup("/.")) : (r = g_strdup(".")); } return r; } /* encrypt and base64 encode path element * return the result */ gchar *crypt_path_ele(struct aes_ctx * ctx, gchar * elem, GHashTable * tr) { guint aes_size, len; guchar *source; guchar *dest; gchar *b64, *hashed; len = strlen(elem); hashed = g_hash_table_lookup(tr, elem); if (hashed) return hashed; aes_size = ((len / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* pad the string to be crypted */ source = g_malloc0(aes_size); dest = g_malloc0(aes_size); g_memmove(source, elem, len); aes_encrypt(ctx, aes_size, dest, source); b64 = encode_base64(aes_size, dest); g_free(source); g_free(dest); if (!b64) { /* hash insert? */ return elem; /* as if nothing happened */ } else if (strlen(b64) > 255) { /* path ele too long. XXX 255 -> symbolic name please */ msg(_("Encrypted base64 path length exceeds %d characters"), 255); return elem; } else { g_hash_table_insert(tr, elem, b64); return b64; } } /* decrypt and base64 decode path element * return the result */ gchar *decrypt_path_ele(struct aes_ctx * ctx, char *b64, GHashTable * tr) { guint aes_size, len; guchar *source; guchar *dest; gchar *crypt, *hashed; guint crypt_size; len = strlen(b64); hashed = g_hash_table_lookup(tr, b64); if (hashed) return hashed; /* be safe and alloc 2 times what we need */ crypt = g_malloc(len * 2); crypt_size = decode_base64((guchar *) crypt, b64); if (!crypt_size) return b64; aes_size = ((crypt_size / AES_BLOCK_SIZE) + 1) * AES_BLOCK_SIZE; /* pad the string to be crypted */ source = g_malloc0(aes_size); dest = g_malloc0(aes_size); g_memmove(source, crypt, crypt_size); aes_decrypt(ctx, aes_size, dest, source); g_free(source); g_free(crypt); /* we could have gotten valid string to begin with * if the result is now garbled instead of nice plain * text assume this was the case. */ if (!is_plain((char *)dest)) { if (opt_verbose > 2) msg(_("Returning original string `%s\'"), b64); g_free(dest); dest = (guchar *) g_strdup(b64); } g_hash_table_insert(tr, b64, dest); return (gchar *) dest; } /** * encrypt an entire path */ gchar *crypt_path(struct aes_ctx * ctx, gchar * p, GHashTable * tr) { gchar *q, *c, *t, *crypt, *xpath, *temp, d; gboolean abs; /* links might have relative targets */ abs = g_path_is_absolute(p); xpath = NULL; for (q = (p + abs); (c = strchr(q, '/')); q++) { d = *c; *c = '\0'; /* don't decrypt '..' and '.' */ if ((t = dot_dotdot(q, xpath, abs))) { xpath = t; q = c; *c = d; continue; } crypt = crypt_path_ele(ctx, q, tr); if (xpath) { temp = g_strdup_printf("%s/%s", xpath, crypt); g_free(xpath); xpath = temp; } else { if (abs) { g_free(xpath); xpath = g_strdup_printf("/%s", crypt); } else { g_free(xpath); xpath = g_strdup(crypt); } } q = c; *c = d; } crypt = crypt_path_ele(ctx, q, tr); if (xpath) { temp = g_strdup_printf("%s/%s", xpath, crypt); g_free(xpath); xpath = temp; } else { if (abs) { g_free(xpath); xpath = g_strdup_printf("/%s", crypt); } else { g_free(xpath); xpath = g_strdup(crypt); } } return xpath; } /** * decrypt an entire path */ gchar *decrypt_path(struct aes_ctx * ctx, gchar * x, GHashTable * tr) { gchar *path, *q, *c, *t, *plain, *temp, d; gboolean abs; /* links */ abs = g_path_is_absolute(x); path = NULL; for (q = (x + abs); (c = strchr(q, '/')); q++) { d = *c; *c = '\0'; /* don't decrypt '..' and '.' */ if ((t = dot_dotdot(q, path, abs))) { path = t; q = c; *c = d; continue; } plain = decrypt_path_ele(ctx, q, tr); if (path) { temp = g_strdup_printf("%s/%s", path, plain); g_free(path); path = temp; } else { if (abs) { g_free(path); path = g_strdup_printf("/%s", plain); } else { g_free(path); path = g_strdup(plain); } } q = c; *c = d; } plain = decrypt_path_ele(ctx, q, tr); if (path) { temp = g_strdup_printf("%s/%s", path, plain); g_free(path); path = temp; } else { if (abs) { g_free(path); path = g_strdup_printf("/%s", plain); } else { g_free(path); path = g_strdup(plain); } } return path; } /** * Read the key from a file * Key must be 16, 24 or 32 octets * Check for this - if larger than 32 cut it off */ gchar *crypt_key(gchar * file) { FILE *f; char *buf; size_t s; buf = g_malloc0(BUFSIZE); s = BUFSIZE; if (!(f = fopen(file, "r"))) { msg(_("Failed to open `%s\': %s"), file, strerror(errno)); g_free(buf); return NULL; } if (rdup_getdelim(&buf, &s, '\n', f) == -1) { msg(_("Failed to read AES key from `%s\': %s"), file, strerror(errno)); g_free(buf); return NULL; } if (buf[strlen(buf) - 1] == '\n') { buf[strlen(buf) - 1] = '\0'; /* kill \n */ } s = strlen(buf); if (s > 32) { msg(_("Maximum AES key size is 32 bytes, truncating!")); buf[32] = '\0'; return buf; } if (s != 16 && s != 24 && s != 32) { msg(_("AES key must be 16, 24 or 32 bytes")); g_free(buf); return NULL; } return buf; } #endif /* HAVE_LIBNETTLE */ rdup-1.1.15/dir.c000066400000000000000000000025231303430127500134730ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * make a dir writable and later remove that * right again */ #include "rdup-up.h" struct stat *dir_write(gchar * p) { /* chmod +w . && rm $file && chmod -w # and hope for the best */ if (!p) return NULL; struct stat *s = g_malloc(sizeof(struct stat)); #ifdef DEBUG msgd(__func__, __LINE__, _("Making directory writable `%s\'"), p); #endif /* DEBUG */ if (stat(p, s) == -1) return NULL; /* make it writable, assume we are the OWNER */ if (chmod(p, s->st_mode | S_IWUSR) == -1) { msgd(__func__, __LINE__, _("Failed to make directory writeable `%s\': %s"), p, strerror(errno)); } return s; } void dir_restore(gchar * p, struct stat *s) { if (!s || !p) return; /* restore perms - assumes *s has not be f*cked up */ if (chmod(p, s->st_mode & 07777) == -1) { msgd(__func__, __LINE__, _("Failed to restore permissions `%s\': %s"), p, strerror(errno)); } } /** * return parent dir string * p MUST not end in a / */ gchar *dir_parent(gchar * p) { gchar *p2; gchar *n; gchar *copy; if (!p) return NULL; if (p[0] == '/' && p[1] == '\0') return p; copy = g_strdup(p); n = strrchr(copy, '/'); if (n) { *(n + 1) = '\0'; p2 = g_strdup(copy); g_free(copy); *n = '/'; return p2; } return NULL; } rdup-1.1.15/doc/000077500000000000000000000000001303430127500133145ustar00rootroot00000000000000rdup-1.1.15/doc/rdup-backups.7000066400000000000000000000136431303430127500160130ustar00rootroot00000000000000'\" t .TH RDUP-BACKUPS 7 "15 Dec 2008" "1.1.x" "rdup" .SH NAME rdup-backups \- introduction into making backups with rdup .SH INTRODUCTION \fBrdup\fR is a simple program that prints out a list of files and directories that are changed changed on a filesystem. It is more sophisticated than for instance \fIfind\fR, because \fBrdup\fR will find files that are removed or directories that are renamed. A long time ago \fBrdup\fR included a bunch of shell and Perl scripts that implemented a backup policy. These could be used in a pipeline to perform a backup. .PP Currently \fBrdup\fR consists out of three basic utilities: .TP .B rdup With \fBrdup\fR you create the file list on which later programs in the pipeline can work. The default output format also includes the files' content. \fBrdup\fR can be seen as a tar replacement in this respect, but \fBrdup\fR also allows for all kinds of transformations of the content (encryption, compression, reversal), see the -P switch in rdup(1) for more information. .TP .B rdup-tr With \fBrdup-tr\fR you can transform the files rdup delivers to you. You can create tar, cpio or pax files. You can encrypt pathnames. \fBrdup-tr\fR is filter that reads from standard input and writes to standard output. See rdup-tr(1) for more information. With \fBrdup\fR and \fBrdup-tr\fR you can create an encrypted archive which is put in a directory structure that is also encrypted. .TP .B rdup-up With \fBrdup-up\fR you can update an existing directory structure with the updates as described by rdup. \fBrdup-up\fR reads \fBrdup\fR input and will create the files, symbolic links, hard links and directories (and sockets, pipes and devices) in the file system. See rdup-up(1) for more information. .PP So the general backup pipeline for \fBrdup\fR will look something like this: create filelist | transform | update filesystem ( rdup | rdup-tr | rdup-up ) .TP .B Note 1: The same sequence is used for restoring. In both cases you want to move files from location A to B. The only difference is that the transformation is reversed when you restore. .TP .B Note 2: The use of \fBrdup-tr\fR is optional. .SH BACKUPS AND RESTORES For \fBrdup\fR there is \fIno\fR difference between backups and restores. If you think about this for a minute you understand why. Making a backup means copying a list of files somewhere else. Restoring files is copying a list of files back to the place they came from. Same difference. So \fBrdup\fR can be used for both, if you did any transformation with \fBrdup\fR during the backup you just need to reverse those operations during the restore. .SH BACKUPS It is always best to backup to \fIanother\fR medium, be it a different local harddisk or a NFS/CIFS mounted filesystem. You can also use \fIssh\fR to store file on a remote server, ala rsync (although not as network efficient). If you backup to a local disk you can just as well use \fBrsync\fR or plain old tar, but if you store your files at somebody else's disk you will need encryption. This is where you go beyond \fBrsync\fR and \fBrdup\fR comes in. Rsync cannot do per-file encryption, sure you can encrypt the network traffic with ssh, but at the remote side your files are kept in plain view. If you implement remote backups, the easy route is to allow root access on the backup medium. If the backup runs without root access the created files will not have their original ownership. For NFS this can be achieved by using \fBno_root_squash\fR, for \fBssh\fR you could enable \fIPermitRootLogin\fR. Note that this may be a security risk. .SH SNAPSHOT BACKUPS We need a little help here in the form of the \fBrdup-simple\fR script. Keep in mind that the following scripts can also be run remotely with the help of \fBssh\fR. The following script implements the algorithm of \fBrdup-simple\fR. .RS .nf #!/bin/bash # some tmp files are saved in ~/.rdup. This directory must exist DIR=/home # what to backup BACKUP=/vol/backup TODAY=$(date +%Y%m/%d) LIST=~/.rdup/list-$HOSTNAME STAMP=~/.rdup/timestamp-$HOSTNAME # for remote backup, this has to run on the remote host! BUGBUG RET=$? case $RET in 2|*) echo Error >&2 exit 1 ;; 1) # full dump, remove file-list and time-stamp file rm $LIST $STAMP ;; 0) # inc dump # do nothing here ;; esac # this is the place where you want to modify the command line # right now, nothing is translated we just use 'cat' rdup -N $STAMP -Pcat $LIST $DIR | rdup-up $BACKUP/$HOSTNAME/$TODAY # or do a remote backup #rdup -N $STAMP -Pcat $LIST $DIR | ssh root@remotehost \\ # rdup-up $BACKUP/$HOSTNAME/$TODAY .fi .RE .SH LOCAL BACKUPS With \fBrdup-simple\fR you can easily create backups. Backing up my home directory to a backup directory: .RS rdup-simple ~ /vol/backup/$HOSTNAME .RE This will create a backup in /vol/backup/$HOSTNAME/200705/15. So each day will have its own directory. Multiple sources are allowed, so: .RS rdup-simple ~ /etc/ /var/lib /vol/backup/$HOSTNAME .RE Will backup your home directory, /etc and /var/lib to the backup location. Also if you need to compress your backup, simple add a '-z' switch: .RS rdup-simple -z ~ /etc/ /var/lib /vol/backup/$HOSTNAME .RE .SH REMOTE BACKUPS For a remote backup to work, both the sending machine and the receiving machine must have \fBrdup\fR installed. The currently implemented protocol is \fIssh\fR. Dumping my homedir to the remote server: .RS rdup-simple ~ ssh://miekg@remote/vol/backup/$HOSTNAME .RE The syntax is almost identical, only the destination starts with the magic string 'ssh://'. Compression and encryption are just as easily enabled as with a local backup, just add '-z' and/or a '-k keyfile' argument: .RS rdup-simple -z -k 'secret-file' ~ ssh://miekg@remote/vol/backup/$HOSTNAME .RE Remember though, that because of these advanced features (compression, encryption, etc, ...) the network transfer can never be as efficient as \fBrsync\fR. .SH ALSO SEE rdup(1), rdup-tr(1), rdup-up(1) and http://www.miek.nl/projects/rdup/ rdup-1.1.15/doc/rdup-simple.1000066400000000000000000000076341303430127500156510ustar00rootroot00000000000000'\" t .TH RDUP 1 "24 Dec 2005" "1.1.14" "rdup" .SH NAME rdup-simple \- create a hardlinked backup .SH SYNOPSIS .B rdup-simple [\fI\+DAYS\fR] -[\fI\-P CMD\fR]... [\fIOPTION\fR]... \fIFILELIST\fR [\fIDIR/FILE]...\fR DESTINATION .SH DESCRIPTION rdup-simple is a frontend for 'rdup-snap' and 'rdup'. It will backup all directories and files given on the command line. It will create a hard linked backup directory, where the backup is created. With the optional +DAYS argument you can specify how far backup rdup-simple looks back for previous backups. This should be a number in the range 1..99. It defaults to 8 days. rdup-simple will create the directory '~/.rdup' and will store its administrative files there. This program does not need to be run with root permissions. The last argument of rdup-simple is used as the destination; the following destinations are supported: ssh:///user@host/directory Use 'ssh' as a protocol and 'user' as the remote user name. Store the backup in 'directory' on the remote server 'host'. ssh://host/directory Use 'ssh' as a protocol and the current username as the remote user name. Store the backup in 'directory' on the remote server 'host'. file:///directory Use '/directory' to store the backup, 'file://' is optional. Note: there are 3 slashes here. /directory Use '/directory' to store the backup. directory Use 'directory' in the current directory for the backup. Making a backup Making a backup is as simple as: rdup-simple ~ /adm /vol/backup/$HOSTNAME ~ and /adm are the directories to be backed up. Multiple directories or files are allowed on the command line. The backup will be stored in '/vol/backup/$HOSTNAME'. For the backup a YYYYMM directory is created. In this directory specific day-dumps are placed. So the first dump in October 2006, will created in 200610/01 and the second in 200610/02, etc. You can use incremental dumps for ever, there is no need to do a full dump every once in a while. Note that rdup-simple calls rdup-snap-link. This small utility will actually hardlink copy the previous backup. The return value of rdup-snap-link will determine if a full or incremental dump will be performed. Remote backups Note: for remote backups to work, the receiving machine must have rdup installed. Also note: there is no colon between the hostname and the directory. Remote backup will create a pipeline of the form: rdup -c DIR|FILE | ssh user@remotehost rdup-shapshot -c -b backupdir There is no provisioning for ssh so unless you have configured ssh to work without a passphrase you will be asked to supply one. Also note that the PATH on the remote host should be set in such a way that all the rdup-util scripts can be found. .SH OPTIONS .TP .B \-P\fIcommand\fR Filter all output through \fIcommand\fR, which is called via `sh -c command'. Multiple \-P's can be used. .SH AUTHOR Written by Miek Gieben. .SH REPORTING BUGS Report bugs to . .SH SEE ALSO http:/www.miek.nl/projects/rdup is the main site of rdup. Also see rdup-tr(1), rdup-up(1) and rdup-backups(7). .SH COPYRIGHT Copyright (C) 2005-2011 Miek Gieben. This is free software. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .PP Licensed under the GPL version 3. See the file LICENSE in the source distribution of rdup. rdup-simple [ +DAYS ] [ OPTIONS ] DIR|FILE [ DIR|FILE ] DESTINATION Description Options -k keyfile Encrypt the files while backing up with keyfile. This option inserts rdup-crypt keyfile in the pipeline. -a Enable extended attributes. Write the uid/gid to the extended user attributes r_uid and r_gid. -f Force a full dump. -x See -x in rdup(8). -z Compress the files while backing up. This option inserts rdup-gzip in the pipeline. -v Echo the files processed to standard error. -h Show a short help message. -V Show the version. See Also rdup(8), rdup-snap-link(8) and rdup-snapshot(8). See rdup-backups(8) for examples and an introduction into making backups with rdup. rdup-1.1.15/doc/rdup-tr.1.in000066400000000000000000000074411303430127500154060ustar00rootroot00000000000000'\" t .TH RDUP-TR 1 "27 Nov 2008" "@PACKAGE_VERSION@" "@PACKAGE_NAME@" .SH NAME @PACKAGE_NAME@-tr \- transform rdup output .SH SYNOPSIS .B @PACKAGE_NAME@-tr [\fIOPTION\fR]... .SH DESCRIPTION Transform rdup output into \fIsomething else\fR. Where \fIsomething else\fR can be a tar, cpio, pax archive or another rdup stream. The rdup archive must be given on \fBrdup-tr\fR's standard input. You can select multiple types of output (\-O flag), but you must be aware that you may loose some information in formats other than \fBrdup\fR's own, see the table below. You may also supply \fBrdup-tr\fR with only a list of pathnames, this can be selected with the \-L flag. The following table shows what happens with the output depending on the input. .BR .TP .B 0 OK .TP .B D delete information is lost .TP .B H hardlink information is lost .BR .TS L|L|CC. output tar,cpio,pax rdup input ------------- ------------- ------ rdup D 0 filelist DH H .TE .SH OPTIONS .TP .B \-L Select list input format. Normally \fBrdup-tr\fR accepts rdup output, with this option you can give it a list of path names. Note: with list input \fBrdup-tr\fR will `stat()` each file, so this can not be used in remote back ups. .TP .B \-O Output format. This can be 'tar', 'cpio', 'pax' or 'rdup'. It defaults to 'rdup'. .TP .B \-X \fIkey\fR Read the encryption key from the file key and encrypt all paths with Blowfish and this key and iv. After the encryption the binary data is converted into ASCII using an URL safe (Section 4 of RFC 3548) version of base64 encode. The encryption key must be on the first line and the key size must be 16 and 8 bytes for the iv, so 24 in total. .TP .B \-Y \fIkey\fR Read the decryption key from the file key and decrypt all paths with Blowfish and this key. Before the encryption the paths are converted to binary by using an URL safe version of base64 decode. .TP .B \-c Force output to the tty. Normally \fBrdup-tr\fR wants to see it's output redirected. .TP .B \-v Be more verbose. Print the processed file names to standard error. .TP .B \-V Print rdup-tr's version. .TP .B \-h A short help. .SH EXAMPLES The following is possible .RS rdup -P gzip -P "mcrypt -f KEY -c" /dev/null /home | \\ rdup-tr -O tar -X<(echo secret) | gzip > \\ my-home-zipped-crypted-pathcrypted-tar.gz .RE That is: all files under /home are gzipped and encrypted on a \fIper\fR file basis (first line). Further more, all pathnames are Blowfish encrypted (second line) with the key 'secret'. This is put in a tar file, which is then compressed, resulting in the final output (final line). Creating a compressed and encrypted tar archive out of a full rdup dump might be done as follows .RS rdup -P gzip -P "mcrypt -f KEY -c" /dev/null /home | \\ rdup-tr -O tar > my-home-zipped-and-crypted.tar .RE Or even pack and unpack it on the fly .RS rdup -P gzip -P "mcrypt -fKEY -c" /dev/null /home | rdup-tr -Otar | \\ ssh user@remotehost tar xvCf /tmp - .RE Or encryption with openssl .RS rdup -P "openssl enc -e -des-cbc -k secret" /dev/null /home .RE Or, compressing with gzip, encrypting with openssl and then compressing the entire archive yet again .RS rdup -P gzip -P "openssl enc -e -des-cbc -k secret" /dev/null /home | \\ gzip > my_compressed_encrypted_rdup_archive.gz .RE .SH EXIT CODE \fBrdup-tr\fR return a zero exit code on success, otherwise 1 is returned. .SH AUTHOR Written by Miek Gieben. .SH REPORTING BUGS Report bugs to . .SH SEE ALSO http:/www.miek.nl/projects/rdup/ is the main site of rdup. Also see rdup(1), rdup-up(1) and rdup-backups(7). .SH COPYRIGHT Copyright (C) 2005-2010 Miek Gieben. This is free software. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .PP Licensed under the GPL version 3. See the file LICENSE in the source distribution of rdup. rdup-1.1.15/doc/rdup-up.1.in000066400000000000000000000064231303430127500154040ustar00rootroot00000000000000'\" t .TH RDUP-UP 1 "13 Dec 2008" "@PACKAGE_VERSION@" "@PACKAGE_NAME@" .SH NAME @PACKAGE_NAME@-up \- update a directory tree with a rdup archive .SH SYNOPSIS .B @PACKAGE_NAME@-up [\fIOPTION\fR]... \fIDIRECTORY\fR .SH DESCRIPTION With \fBrdup-up\fR you can update an (possibly) existing directory structure with a rdup archive. The rdup archive has to be given to \fBrdup-up\fR's standard input. .SS Username and uids \fBrdup\fR outputs both the user name and uid, the receiving system (which may be a totally different system) checks if the user name and uid match. If the user name and uid don't match the (numeric) uid is used on the file. The same holds true for the group name and gid. .SS File ownership As \fBrdup\fR supports backups via SSH the following situation can occur: locally \fBrdup\fR is run a root, but \fBrdup-up\fR is run as a non-root user (the one logged in via SSH). In this case the original owner- and group name can not be set. If this happens \fBrdup-up\fR will create a \fI._rdup_.\fR file which contains the user/group information, also see the \fI\-u\fR flag for \fBrdup-tr\fR (and \fBrdup\fR). .SH OPTIONS .TP .B \-n Do a dry-run and do not create anything on disk. .TP .B \-t Create DIRECTORY (ala mkdir -p) if it does not exist. .TP .B \-s N Strip N path components from a pathname. If the resulting pathname is empty after this operation it is skipped. Be careful however with the following structure: /foo /foo/bar /foo/bar/bla.txt /foo/blork/bla.txt With \fBrdup-up -s\fI2\fR this will leave: /bla.txt /bla.txt And the last 'bla.txt' will \fIover write\fR the previous one, this will happen without warnings. .TP .B \-r PATH This option is related to the \-s option, but works different. The string PATH is removed from (the beginning of) each pathname. With \fI-r /home/backup\fR the pathname \fI/home/backup/bin/mycmd\fR becomes \fI/bin/mycmd\fR. The same could be done with \fB-s 2\fR, but then you need to count the slashes. Note \-s is always performed before \-r. .TP .B \-v Be more verbose and echo the processed files to \fIstandard output\fR. .TP .B \-T Show a table of contents of the rdup stream received (ala tar \-tf \-). With \-T the directory argument is optional. \-T unsets any verbose (\-v) options. .TP .B \-u Do not create a \fI._rdup_.\fR file which contains user/group information when failing to \fBchown\fR the actual file or directory. Useful when restoring a backup when you do not want to see \fI._rdup._\fR-files being created. .TP .B \-q Silence 'chown' failures even when running as root. This can be helpful when the file system does not implement 'chown' or disallows it ('sshfs' for instance). .TP .B \-h A short help message. .TP .B \-V Show the version. .SH EXIT CODE \fBrdup-up\fR return a zero exit code on success, otherwise 1 is returned. .SH AUTHOR Written by Miek Gieben. .SH REPORTING BUGS Report bugs to . .SH SEE ALSO http:/www.miek.nl/projects/rdup/ is the main site of rdup. Also see rdup(1), rdup-tr(1) and rdup-backups(7). .SH COPYRIGHT Copyright (C) 2005-2010 Miek Gieben. This is free software. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .PP Licensed under the GPL version 3. See the file LICENSE in the source distribution of rdup. rdup-1.1.15/doc/rdup.1.in000066400000000000000000000352101303430127500147560ustar00rootroot00000000000000'\" t .TH RDUP 1 "24 Dec 2005" "@PACKAGE_VERSION@" "@PACKAGE_NAME@" .SH NAME @PACKAGE_NAME@ \- generate a file list suitable for making backups .SH SYNOPSIS .B @PACKAGE_NAME@ [\fI\-N timestamp\fR] -[\fI\-P CMD\fR]... [\fIOPTION\fR]... \fIFILELIST\fR [\fIDIR/FILE]...\fR .SH DESCRIPTION \fBrdup\fR is a utility inspired by rsync and the Plan9 way of doing backups. \fBrdup\fR itself does not backup anything. It only prints a list of files that are changed, or all files in case of a null dump. It also handles files that are removed, allowing for correct incremental backups. All paths printed are absolute. \fBrdup\fR uses the change time (ctime) to decide whether a file is altered. .PP It works as follows, for a full dump .TP .B 1. Crawl all directories, and print all the names found to standard output. Also check for \fI._rdup_.\fR files to restore the original ownership (see the \fI\-u\fR flag). .TP .B 2. Write a filelist with all the names found when crawling. Use this list to calculate the correct incremental dump. .PP And for incremental dumps .TP .B 1. Read in the filelist that was written when doing a full dump. .TP .B 2. Touch the time stamp file. .TP .B 3. Crawl all the directories again. .TP .B 4. Diff 1. and 2. to get two lists; one of removed items and one of added/modified items. .TP .B 5. Write the removed items to standard output .TP .B 6. Write the modified/new items to standard output. .TP .B 7. Write a new filelist. .PP The .IR FILELIST is a internal list \fBrdup\fR writes to, to keep track of which files are in a backup. If you don't want this (i.e. make a full backup), use \fI/dev/null\fR here. The file \fI/dev/null\fR is handled specially by \fBrdup\fR: if detected no new file list is written. .PP The .IR DIRS/FILES can be specified multiple times. These are the directories and files you want to backup. If omitted it defaults to the current directory "." . .PP If the \fI\-N timestamp\fR option is not given, all paths found are printed. Only when a \fI\-N timestamp\fR file is given, times can be compared and an incremental output can be generated. .PP \fBrdup\fR prints a filelist to standard output. Subsequent programs in a pipe line can be used to actually implement to backup scheme. After a run a new FILELIST is written. No warning is given when FILELIST is an existing file, it just gets overwritten by \fBrdup\fR. New runs will print out only those files that have actually changed or are removed since the last run, thereby making incremental backups possible. .PP Files are checked for changes by comparing the c\-time (change time), if this time is NEWER than the c\-time of timestamp file the pathname is printed to standard output. When files are removed they are also printed to standard output, but they are prefixed with a '-'. See .B FORMAT below. The default format \fBrdup\fR uses is: "%p%T %b %t %u %U %g %G %l %s\\n%n%C" Note, that \fBrdup\fR also supports hashing of files, this makes it possible to check the local hash with the hash of the backed up file. .PP All errors are written to standard error. If the directory or file does not exist, they are skipped and a warning is emitted. .PP The general idea is to be very UNIX like and create a bunch of simple programs which each do a their specific thing very well. With \fBrdup\fR and a small shell script (50 lines) one can implement encrypted and compressed backups. As \fBrdup\fR doesn't backup anything, the backup policy; what you backup, how you backup, how often and how you restore; is all left to the scripts and your imagination. To kick start your imagination see \fIrdup-tr(1)\fR, \fIrdup-up(1)\fR and maybe \fIrdup-backups\fR. .SH OPTIONS .TP .B \-P\fI command\fR Filter all output through \fIcommand\fR, multiple \-P's can be used. Due to the nature of pipes in Unix, this pipeline is recreated for every file processed. Also see 'Child Processes' below. .TP .B \-F format Specify a printf-style format to use. See \fBFORMAT\fR below. .TP .B \-N timestamp use the c_time of file \fBtimestamp\fR as the timestamp to decide what to include in the incremental backup list. If \fBtimestamp\fR does not exist a full dump is performed. .TP .B \-M timestamp As \-N, but look at the m_time of timestamp. .TP .B \-R Reverse the output of \fBrdup\fR. Tools accepting this ouput must create leading directory as they see them. This option allows a script -- running as a normal user -- to put files in a directory which could have 0600 as its permission. .TP .B \-E file The file named 'file' contains a list of Perl-compatible regular expressions (PCRE), one per line, that \fBrdup\fR will use to \fIexclude\fR names. A '#' at the start of the line can be used to signal a comment. Empty lines are ignored. If a directory is excluded, \fBrdup\fR won't descend in that directory, so all files in that directory are also excluded. The directories leading up to the directory to be backed up can not be excluded. If you use a command line like: .RS rdup /dev/null /home/miekg/bin .RE .RS The directories '/home', '/home/miekg', '/home/miekg/bin' are always printed. If you want to exclude the file '/home/miekg/blaat' you need to add the following regular expression: '/home/miekg/blaat'. If you want to exclude all .mozilla/cache directories of all users you can use '/home/.*/.mozilla/cache/.*'. This doesn't exclude the directory itself and I'm assuming that the users' home directories are found under '/home'. Also note that \fBrdup\fR does not print directories with a trailing slash. .RE .TP .B \-a Restore the original access times on files and directories. .TP .B \-n Don't honor \fI.nobackup\fR files. Normally if such a file is found the directory and all files containing it, are not printed to standard output. Now they are. .TP .B \-u Output files with a \fI._rdup_.\fR prefix just as normal files. When this option is not given these files are skipped by \fIrdup\fR. .TP .B \-r Only print removed files; entries that start with a `\-'. This option unsets \-m. .TP .B \-m Only print modified/new files; entries that start with a `+'. This option unsets \-r. .TP .B \-v Be more verbose. When used each path will also be printed to standard error. .TP .B \-s size Don't output files larger than \fBsize\fR bytes. This can be used to limit the amount of data to be transferred when doing a remote backup. This option \fIonly\fR applies to files. .TP .B \-x Stay on the local filesystem. .TP .B \-V Print rdup's version. .TP .B \-h Give an overview of the options. .SS Child Processes (-P flag) When creating output you might also want to 'pipe' the contents of \fIeach\fR file through a number of commands, say a compression and encryption utility. Note that this is different than compressing the \fIentire\fR archive as GNU tar allows by using the \-z option. So this is where \fBrdup\fR comes in. It allows you to create a normal archive in which \fIeach\fR file is encrypted (or compressed. reversed or whatever). \fBrdup\fR does this by forking child processes which transform the content. If one of the forked children returns an exit code other than zero (0), it is assumed the whole conversion process failed. In that case \fBrdup\fR terminates. As said \fBrdup\fR works by forking off a number of child processes (those commands named with the \-P option(s)), interconnecting these with pipes. The current file is connected to the first child. The output created by these child processes is captured by the parent (\fBrdup\fR). The contents is then written to standard output in an archive format. As a picture says more than a thousand words here is an ASCII image of the process: .RS +--- ... (stdout) ... ----> archive / rdup <--- ... ... <----+ | loop #files | | file ---> cmd1 | cmd2 | ...| cmdN .RE .SH BACKUPS With: .RS rm -f timestamp && rdup -N timestamp LIST DIR .RE A full-dump filelist is printed to standard output. And with: .RS rdup -N timestamp LIST DIR .RE An incremental dump filelist is printed. The file \fItimestamp\fR is used to save the exact time of rdup's run. The file \fILIST\fR is used to calculate the correct incremental dump list, this is needed for files that are removed, or have a different type. .SH NON-ROOT BACKUPS If backups are made by a non-root user or on a filesystem that does not implement/allow \fIchown\fR (think sshfs mounted by an ordinary user), \fIrdup\fR creates a seperate file which stores the correct user and group information. If the file's name is \fIfoobar\fR a new file called \fI._rdup_.foobar\fR is created in the same directory. This file contains one line, for instance: .RS root:0/root:0 .RE That tells that the \fIactual\fR ownership should be root:root. For directories a \fI._rdup_.\fR file is created inside the current directory. .SH FORMAT The default format \fBrdup\fR uses is: "%p%T %b %t %u %U %g %G %l %s\\n%n%C" .PP The following escape sequences are understood by \fBrdup\fR: .BR 'p': '+' if file is new/modified, '-' if removed .BR 'b': permission bits from lstat(2), octal in four digits .BR 'm': the file mode bits, st_mode from lstat(2), decimal digits .BR 'u': uid .BR 'U': username .BR 'g': gid .BR 'G': groupname .BR 'l': path name length .BR 's': original file size, but see .B CAVEATS .BR 'n': path name .BR 'N': path name, but in case of a soft- or hardlink \fIonly\fR the link name .BR 't': time of modification (seconds from epoch) .BR 'H': the SHA1 hash of the file, all zeros ("0") for all other types .BR 'T': file type .RS \fB-\fR normal file, \fBl\fR symlink, \fBh\fR hardlink, \fBd\fR directory, \fBc\fR character device, \fBb\fR block device, \fBp\fR named pipe and \fBs\fR socket .RE 'C': the content of the file (none for all other types) .PP To delimit the output of \fBrdup\fR with NULLs you can use '\\0' in the format string. Any file content is written in a block/chunk based manner. The last block is signaled with a null block. A block start entry is ASCII and is formatted as follows: VVBLOCKBBBBB\\n . Where 'VV' is the version, currently at '01', then the literal string 'BLOCK' and then the amount of bytes (BBBBB), typical '08192'. And then a newline. This look like this: .RS 01BLOCK08192 01BLOCK00015 01BLOCK00000 .RE A byte count of zero signals a stop block. .SH FILELIST \fBrdup\fR writes the (internal) FILELIST in the following format: .RS MODE DEV INODE LINK UID GID PATH_SIZE FILE_SIZE PATH .RE .PP Where MODE is the st_mode from stat(2), DEV is the dev id as returned by the stat call and INODE is the inode number - \fBrdup\fR needs this info to decide if a directory is renamed. LINK is equal to 'h' for hardlinks, 'l' for symlinks and otherwise it is '*'. UID and GID are the numeric user and group id of the file. PATH_SIZE is the length of PATH. FILE_SIZE the file size. And finally PATH is the path of the file. A typical example is: .RS 16893 2050 32085 * 1000 1000 30 4096 /home/miekg/git/rdup/.git/logs .RE .SH OUTPUT FORMAT The output generated by \fBrdup\fR is formatted like: .RS +|-TYPE BITS MTIME UID USER GID GROUP PATH_SIZE FILE_SIZE\\n PATH FILE_CONTENTS .RE .PP This makes it possible possible for a remote shell script to receive the actual file contetns and make a backup. .PP For directories: the FILE_SIZE is zero and no content is printed. Thus: .RS +d 0755 1260243445 1000 miekg 1000 miekg 11 0\\n \fB/home/miekg\fR .RE For regular files the following is a sample output: .RS +- 0644 1260243445 1000 miekg 1000 miekg 32 6\\n \fB/home/miekg/svn/rdup/trunk/aaa/a\fR01BLOCK00006\\n \fIhello\fR\\n 01BLOCK00000\\n .RE Where \fBaaa/a\fR is a regular file containing the word 'hello\\n' .SS CAVEATS Soft- and hardlinks are handled differently when using %n, if you don't like this behavior use %N. The PATH name is generated from the link's name and its target. A symlink like .RS /home/bin/blaat -> /home/bin/bliep .RE is printed as '/home/bin/blaat -> /home/bin/bliep'. The PATH_SIZE is modified accordingly, where '\fB -> \fR' (4 characters) is also counted. The FILE_SIZE is not needed for soft- or hardlinks, so it is set the length of the link's name -- the part left of the ' ->', in this case the length of '/home/bin/blaat'. If rdup encounters a hardlink it is handled in the same way, but the output type is set to 'h' instead of 'l'. A hardlink is only detected if rdup finds a file with the same inode and device number as a previous one, i.e. such hardlinks must be contained in your backup. Again note: with '%N' only the link's name is printed. The FILE_SIZE is \fIstill\fR set to the length of the link's name. .SS Device Files For devices the size field (%s) is changed to hold the major,minor number of the device. So if a major number is 8 and the minor number is 0 (under Linux this is /dev/sda), its size will be \fB8,0\fR. The numbers are only separated with a comma `,'. .SS Symlinks You will probably think \fBrdup\fR will descend into the directory the symbolic link points to. This is not what actually happens, \fBrdup\fR will print any directories leading up to the symlink and will \fInot\fR descend into the directory. GNU tar works the same. .SH EXIT CODE \fBrdup\fR return a zero exit code on success, otherwise 1 is returned. \fRrdup\fR will abort if a file can not be concatenated, if a regular expression can not be compiled or if a signal is received. .SH EXAMPLES The next set of examples will all make a full dump -- because of the use of /dev/null. See \fIrdup-tr(1)\fR for more advanced examples. .SS rdup (mirroring) Backup: .RS rdup /dev/null ~/bin | rdup-up -t /shared/backup .RE Restore: .RS rdup /dev/null /shared/backup | rdup-up -t /tmp/restore .RE or .RS cp -rap /shared/backup /tmp/restore .RE .SS rdup (archiving) Backup: .RS rdup /dev/null ~/bin > my-archive.rdup .RE Restore: .RS rdup-up -t /tmp/restore < my-archive.rdup .RE .SS cpio Backup: .RS rdup -R -F '%N\\n' /dev/null ~/bin | cpio -o -Hcrc > my-archive.cpio .RE Restore: .RS cpio -i -d -Hcrc < my-archive.cpio .RE .SS tar Backup: .RS rdup -F '%N\\n' /dev/null ~/bin | tar c -f my-archive.tar -T - --no-recursion .RE Restore: .RS tar x -f my-archive.tar .RE .SH AUTHOR Written by Miek Gieben. .SH REPORTING BUGS Report bugs to . .SH SEE ALSO http:/www.miek.nl/projects/rdup is the main site of rdup. Also see rdup-tr(1), rdup-up(1) and rdup-backups(7). .SH COPYRIGHT Copyright (C) 2005-2011 Miek Gieben. This is free software. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. .PP Licensed under the GPL version 3. See the file LICENSE in the source distribution of rdup. rdup-1.1.15/entry.c000066400000000000000000000242631303430127500140630ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * parse_entry.c * parse an standard rdup entry and return a * struct rdup */ #include "rdup-tr.h" #include "protocol.h" #include "io.h" /* signal.c */ void got_sig(int); void signal_abort(int); extern int sig; extern gint opt_input; extern gint opt_output; extern gchar *opt_crypt_key; extern gchar *opt_decrypt_key; /* * or parse a new style rdup -c output entry * +- 0775 1000 1000 18 2947\n * /home/miekg/bin/tt * * * where contents is block based * 1BLOCK8192 * 8192 bytes of data * 1BLOCK15 * 15 bytes of data * 1BLOCK0 * the-end */ struct rdup *parse_entry(char *buf, size_t l) { struct rdup *e; struct stat s; gint i; char *n, *pos; e = g_malloc(sizeof(struct rdup)); e->f_ctime = 0; /* not used in rdup-* */ switch (opt_input) { case I_LIST: if (lstat(buf, &s) == -1) { msg(_("Could not stat path `%s\': %s"), buf, strerror(errno)); g_free(e); return NULL; } e->plusmin = PLUS; e->f_name = g_strdup(buf); e->f_name_size = strlen(buf); e->f_target = NULL; e->f_mode = s.st_mode; e->f_uid = s.st_uid; e->f_gid = s.st_gid; e->f_size = s.st_size; e->f_dev = s.st_dev; e->f_ino = s.st_ino; e->f_rdev = s.st_rdev; e->f_lnk = 0; e->f_ctime = s.st_ctime; e->f_mtime = s.st_mtime; e->f_atime = s.st_atime; /* you will loose hardlink information here * as 'stat' cannot check this */ if (S_ISLNK(e->f_mode)) e->f_target = slink(e); break; case I_RDUP: if (strlen(buf) < LIST_MINSIZE) { msg(_("Corrupt entry `%s\' in input at line: %zd"), buf, l); g_free(e); return NULL; } /* defaults */ e->f_dev = 0; e->f_rdev = 0; e->f_ino = 0; e->f_lnk = 0; e->f_target = NULL; e->f_name = NULL; /* 1st char should + or - */ if (buf[0] != '-' && buf[0] != '+') { msg(_ ("First character should \'-\' or \'+\', `%s\' at line: %zd"), buf, l); g_free(e); return NULL; } if (buf[0] == '+') e->plusmin = PLUS; if (buf[0] == '-') e->plusmin = MINUS; if (opt_output != O_RDUP && e->plusmin == MINUS) { msg(_ ("Removing files is not supported for any output except rdup")); g_free(e); return NULL; } /* type */ switch (buf[1]) { case '-': e->f_mode = S_IFREG; break; case 'd': e->f_mode = S_IFDIR; break; case 'l': e->f_mode = S_IFLNK; break; case 'h': e->f_mode = S_IFREG; e->f_lnk = 1; break; case 'c': e->f_mode = S_IFCHR; break; case 'b': e->f_mode = S_IFBLK; break; case 'p': e->f_mode = S_IFIFO; break; case 's': e->f_mode = S_IFSOCK; break; default: msg(_("Type must be one of d, l, h, -, c, b, p or s")); g_free(e); return NULL; } /* perm */ i = (buf[3] - 48) * 512 + (buf[4] - 48) * 64 + /* oct -> dec */ (buf[5] - 48) * 8 + (buf[6] - 48); if (i < 0 || i > 07777) { msg(_("Invalid permissions at line: %zd"), l); g_free(e); return NULL; } e->f_mode |= i; /* m_time */ n = strchr(buf + 8, ' '); if (!n) { msg(_("Malformed input for m_time at line: %zd"), l); g_free(e); return NULL; } e->f_mtime = (time_t) atol(buf + 8); pos = n + 1; /* uid */ n = strchr(pos, ' '); if (!n) { msg(_("Malformed input for uid at line: %zd"), l); g_free(e); return NULL; } else { *n = '\0'; } e->f_uid = atoi(pos); pos = n + 1; /* username */ n = strchr(pos, ' '); if (!n) { msg(_("Malformed input for user at line: %zd"), l); g_free(e); return NULL; } else { *n = '\0'; } e->f_user = g_strdup(pos); pos = n + 1; /* gid */ n = strchr(pos, ' '); if (!n) { msg(_("Malformed input for gid at line: %zd"), l); g_free(e); return NULL; } else { *n = '\0'; } e->f_gid = atoi(pos); pos = n + 1; /* groupname */ n = strchr(pos, ' '); if (!n) { msg(_("Malformed input for group at line: %zd"), l); g_free(e); return NULL; } else { *n = '\0'; } e->f_group = g_strdup(pos); pos = n + 1; /* pathname length */ n = strchr(pos, ' '); if (!n) { msg(_("Malformed input for path length at line: %zd"), l); g_free(e); return NULL; } e->f_name_size = atoi(pos); /* checks */ pos = n + 1; /* dev file? */ if (S_ISCHR(e->f_mode) || S_ISBLK(e->f_mode)) { int major, minor; n = strchr(pos, ','); if (!n) { msg("No major,minor found for device at line: %zd", l); g_free(e); return NULL; } *n = '\0'; major = atoi(pos); minor = atoi(n + 1); e->f_size = 0; e->f_rdev = makedev(major, minor); } else e->f_size = atoi(pos); break; } return e; } /* ALmost the same of entry_print_data in gfunc.c, but * not quite as we don't don't use FILE* structs here * for instance. TODO: integrate the two functions? * entry_print_data() */ gint rdup_write_header(struct rdup * e) { char *out; char t; if (S_ISDIR(e->f_mode)) { t = 'd'; } else if (S_ISCHR(e->f_mode)) { t = 'c'; } else if (S_ISBLK(e->f_mode)) { t = 'b'; } else if (S_ISFIFO(e->f_mode)) { t = 'p'; } else if (S_ISSOCK(e->f_mode)) { t = 's'; } else if (S_ISLNK(e->f_mode)) { t = 'l'; } else { if (e->f_lnk == 1) t = 'h'; else t = '-'; } if (t == 'b' || t == 'c') { /* device */ out = g_strdup_printf("%c%c %.4o %ld %ld %s %ld %s %ld %d,%d\n%s", e->plusmin == PLUS ? '+' : '-', t, (int)e->f_mode & 07777, (unsigned long)e->f_mtime, (unsigned long)e->f_uid, e->f_user, (unsigned long)e->f_gid, e->f_group, (unsigned long)e->f_name_size, (unsigned int)major(e->f_rdev), (unsigned int)minor(e->f_rdev), e->f_name); } else if (t == 'l' || t == 'h') { /* link */ gchar *n; n = g_strdup_printf("%s -> %s", e->f_name, e->f_target); e->f_name_size = strlen(n); out = g_strdup_printf("%c%c %.4o %ld %ld %s %ld %s %ld %zd\n%s", e->plusmin == PLUS ? '+' : '-', t, (int)e->f_mode & 07777, (unsigned long)e->f_mtime, (unsigned long)e->f_uid, e->f_user, (unsigned long)e->f_gid, e->f_group, (unsigned long)e->f_name_size, (size_t) e->f_size, n); g_free(n); } else { out = g_strdup_printf("%c%c %.4o %ld %ld %s %ld %s %ld %zd\n%s", e->plusmin == PLUS ? '+' : '-', t, (int)e->f_mode & 07777, (unsigned long)e->f_mtime, (unsigned long)e->f_uid, e->f_user, (unsigned long)e->f_gid, e->f_group, (unsigned long)e->f_name_size, (size_t) e->f_size, e->f_name); } if (sig != 0) signal_abort(sig); if (write(1, out, strlen(out)) == -1) { msg(_("Failed to write to stdout: %s"), strerror(errno)); return -1; } g_free(out); return 0; } gint rdup_write_data( __attribute__ ((unused)) struct rdup * e, char *buf, size_t len) { if (block_out_header(NULL, len, 1) == -1 || block_out(NULL, len, buf, 1) == -1) return -1; return 0; } /* fill a stat structure from an rdup entry */ struct stat *stat_from_rdup(struct rdup *e) { struct stat *s; s = g_malloc(sizeof(struct stat)); s->st_mode = e->f_mode; s->st_uid = e->f_uid; s->st_gid = e->f_gid; s->st_size = e->f_size; s->st_dev = e->f_dev; s->st_ino = e->f_ino; s->st_rdev = e->f_rdev; s->st_ctime = e->f_ctime; s->st_mtime = e->f_mtime; s->st_atime = e->f_atime; /* struct stat { dev_t st_dev; ino_t st_ino; mode_t st_mode; nlink_t st_nlink; uid_t st_uid; gid_t st_gid; dev_t st_rdev; off_t st_size; blksize_t st_blksize; blkcnt_t st_blocks; time_t st_atime; time_t st_mtime; time_t st_ctime; } */ return s; } /* convert time_t to string: 2009-10-30 08:37 */ static void strtime(time_t time, gchar * str) { struct tm *t; t = localtime(&time); strftime(str, BUFSIZE, "%Y-%m-%d %H:%M", t); } /* stolen from coreutils */ static void rdup_strmode(mode_t mode, gchar * str) { str[0] = mode & S_IRUSR ? 'r' : '-'; str[1] = mode & S_IWUSR ? 'w' : '-'; str[2] = (mode & S_ISUID ? (mode & S_IXUSR ? 's' : 'S') : (mode & S_IXUSR ? 'x' : '-')); str[3] = mode & S_IRGRP ? 'r' : '-'; str[4] = mode & S_IWGRP ? 'w' : '-'; str[5] = (mode & S_ISGID ? (mode & S_IXGRP ? 's' : 'S') : (mode & S_IXGRP ? 'x' : '-')); str[6] = mode & S_IROTH ? 'r' : '-'; str[7] = mode & S_IWOTH ? 'w' : '-'; str[8] = (mode & S_ISVTX ? (mode & S_IXOTH ? 't' : 'T') : (mode & S_IXOTH ? 'x' : '-')); str[9] = ' '; str[10] = '\0'; } /* * write a table of contents (ala gnu tar) entry to stdout * -/+drwxr-xr-x miekg/miekg 0 2009-10-30 08:37 home/miekg/bin2/ */ gint rdup_write_table(struct rdup *e, FILE * f) { gchar *tmp = g_malloc(BUFSIZE); e->plusmin == PLUS ? fputc('+', f) : fputc('-', f); /* type */ if (S_ISDIR(e->f_mode)) { fputc('d', f); } else if (S_ISCHR(e->f_mode)) { fputc('c', f); } else if (S_ISBLK(e->f_mode)) { fputc('b', f); } else if (S_ISFIFO(e->f_mode)) { fputc('p', f); } else if (S_ISSOCK(e->f_mode)) { fputc('s', f); } else if (S_ISLNK(e->f_mode)) { fputc('l', f); } else { if (e->f_lnk == 1) fputc('h', f); else fputc('-', f); } /* perm symbolic */ rdup_strmode(e->f_mode, tmp); fputs(tmp, f); if (sig != 0) signal_abort(sig); /* user/group */ if (e->f_user) fprintf(f, " %s/", e->f_user); else fprintf(f, " %ld/", (unsigned long)e->f_uid); if (e->f_group) fprintf(f, "%s ", e->f_group); else fprintf(f, "%ld ", (unsigned long)e->f_gid); if (sig != 0) signal_abort(sig); /* size 6 pos right justified */ if ((S_ISLNK(e->f_mode) || e->f_lnk == 1)) { /* correctly recover original filesize for the link */ fprintf(f, "% 9ld ", (unsigned long)(e->f_name_size - e->f_size - 4)); } else if (S_ISCHR(e->f_mode) || S_ISBLK(e->f_mode)) { fprintf(f, "% 6d,%d ", (unsigned int)major(e->f_rdev), (unsigned int)minor(e->f_rdev)); } else { fprintf(f, "% 9ld ", (unsigned long)e->f_size); } if (sig != 0) signal_abort(sig); /* mtime in 2009-10-30 08:37 */ strtime(e->f_mtime, tmp); fputs(tmp, f); fputc(' ', f); /* path */ fputs(e->f_name, f); if (S_ISLNK(e->f_mode) || e->f_lnk == 1) { fputs(" -> ", f); fputs(e->f_target, f); } if (sig != 0) signal_abort(sig); fputc('\n', f); g_free(tmp); return 0; } rdup-1.1.15/entry.h000066400000000000000000000020311303430127500140550ustar00rootroot00000000000000#ifndef _ENTRY_H #define _ENTRY_H #include #include #define PLUS 1 #define MINUS 0 /* almost the whole stat structure... */ struct rdup { guint plusmin:1; /* '-' remove, '+' add. Added because of rdup-tr */ guint f_lnk:1; /* 0, 1 if hardlink */ gchar *f_name; /* filename or link src iff link */ gchar *f_target; /* in case of a link this holds the target name */ size_t f_name_size; /* size of filename */ uid_t f_uid; /* uid */ gchar *f_user; /* username */ gid_t f_gid; /* gid */ gchar *f_group; /* groupname */ mode_t f_mode; /* mode bits */ time_t f_ctime; /* change time of the inode */ time_t f_mtime; /* modification time of the inode */ time_t f_atime; /* modification time of the inode */ off_t f_size; /* file size */ dev_t f_dev; /* ID of device containing file */ dev_t f_rdev; /* device ID (if special file), we use this for major, minor */ ino_t f_ino; /* inode number */ }; #endif /* _ENTRY_H */ rdup-1.1.15/fs-up.c000066400000000000000000000241401303430127500137460ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * rdup-up -- update an directory tree with and rdup archive * * File related functions * */ #include "rdup-up.h" #include "protocol.h" extern int sig; extern gboolean opt_dry; extern gboolean opt_table; extern gboolean opt_quiet; extern gboolean opt_chown; extern guint opt_strip; extern gint opt_verbose; extern GSList *hlink_list; /* signal.c */ void got_sig(int signal); /* common.c */ struct rdup *entry_dup(struct rdup *); void entry_free(struct rdup *); static gboolean mk_time(struct rdup *e) { struct utimbuf ut; /* we don't carry the a_time, how cares anyway with noatime? */ ut.actime = ut.modtime = e->f_mtime; if (utime(e->f_name, &ut) == -1) msgd(__func__, __LINE__, _("Failed to set mtime '%s\': %s"), e->f_name, strerror(errno)); return TRUE; } static gboolean mk_chown(struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { uid_t u; gid_t g; u = lookup_uid(uidhash, e->f_user, e->f_uid); g = lookup_gid(gidhash, e->f_group, e->f_gid); if (lchown(e->f_name, u, g) == -1) { if (opt_chown) { /* chown failed, use and create ._rdup_. - file, it that fails too * we're out of luck - so we don't care about the return value */ if (S_ISDIR(e->f_mode)) { chown_write(e->f_name, NULL, e->f_uid, e->f_user, e->f_gid, e->f_group); } else { chown_write(dirname(e->f_name), basename(e->f_name), e->f_uid, e->f_user, e->f_gid, e->f_group); } } else { if (!opt_quiet) { msgd(__func__, __LINE__, _("Failed to chown `%s\': %s"), e->f_name, strerror(errno)); } } } return TRUE; } static gboolean mk_mode(struct rdup *e) { chmod(e->f_name, e->f_mode); return TRUE; } static gboolean mk_meta(struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { mk_mode(e); mk_chown(e, uidhash, gidhash); mk_time(e); return TRUE; } static gboolean mk_dev(struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { gchar *parent; struct stat *st; if (opt_dry) return TRUE; if (!rm(e->f_name)) return FALSE; if (mknod(e->f_name, e->f_mode, e->f_rdev) == -1) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (mknod(e->f_name, e->f_mode, e->f_rdev) == -1) { msgd(__func__, __LINE__, _("Failed to make device `%s\': %s"), e->f_name, strerror(errno)); dir_restore(parent, st); g_free(parent); return FALSE; } dir_restore(parent, st); g_free(parent); } else { msgd(__func__, __LINE__, _("Failed to make device `%s\': %s"), e->f_name, strerror(errno)); return FALSE; } } mk_meta(e, uidhash, gidhash); return TRUE; } static gboolean mk_sock(struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { gchar *parent; struct stat *st; if (opt_dry) return TRUE; if (!rm(e->f_name)) return FALSE; if (mkfifo(e->f_name, e->f_mode) == -1) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (mkfifo(e->f_name, e->f_mode) == -1) { msgd(__func__, __LINE__, _("Failed to make socket `%s\': %s"), e->f_name, strerror(errno)); dir_restore(parent, st); g_free(parent); return FALSE; } dir_restore(parent, st); g_free(parent); } else { msgd(__func__, __LINE__, _("Failed to make socket `%s\': %s"), e->f_name, strerror(errno)); return FALSE; } } mk_meta(e, uidhash, gidhash); return TRUE; } static gboolean mk_link(struct rdup *e, char *p, GHashTable * uidhash, GHashTable * gidhash) { struct stat *st; gchar *t; gchar *parent; if (opt_dry) return TRUE; if (!rm(e->f_name)) return FALSE; /* symlink */ if (S_ISLNK(e->f_mode)) { if (symlink(e->f_target, e->f_name) == -1) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (symlink(e->f_target, e->f_name) == -1) { msgd(__func__, __LINE__, _ ("Failed to make symlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); dir_restore(parent, st); g_free(parent); return FALSE; } dir_restore(parent, st); g_free(parent); } else { msgd(__func__, __LINE__, _ ("Failed to make symlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); return FALSE; } } mk_chown(e, uidhash, gidhash); return TRUE; } /* hardlink */ /* target must also fall in backup dir */ t = g_strdup_printf("%s%s", p, e->f_target); e->f_target = t; hlink_list = g_slist_append(hlink_list, entry_dup(e)); return TRUE; } static gboolean mk_reg(FILE * in, struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { FILE *out = NULL; char *buf; gchar *parent; size_t bytes; gboolean ok = TRUE; gboolean old_dry = opt_dry; struct stat *st; /* with opt_dry we can't just return TRUE; as we may * need to suck in the file's content - which is thrown * away in that case */ if (!e->f_name) { /* fake an opt_dry */ opt_dry = TRUE; } if (!opt_dry) { if (!rm(e->f_name)) { opt_dry = old_dry; return FALSE; } } if (!opt_dry && !(out = fopen(e->f_name, "w"))) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (!(out = fopen(e->f_name, "w"))) { msgd(__func__, __LINE__, _("Failed to open file `%s\': %s"), e->f_name, strerror(errno)); g_free(parent); ok = FALSE; } dir_restore(parent, st); g_free(parent); } else { msgd(__func__, __LINE__, _("Failed to open file `%s\': %s"), e->f_name, strerror(errno)); ok = FALSE; } } /* we need to read the input to not upset * the flow into rdup-up, but we are not * creating anything when opt_dry is active */ buf = g_malloc(BUFSIZE + 1); while ((bytes = block_in_header(in)) > 0) { if (block_in(in, bytes, buf) == -1) { if (out) fclose(out); opt_dry = old_dry; g_free(buf); return FALSE; } if (ok && !opt_dry) { if (fwrite(buf, sizeof(char), bytes, out) != bytes) { msgd(__func__, __LINE__, _("Write failure `%s\': %s"), e->f_name, strerror(errno)); if (out) fclose(out); opt_dry = old_dry; g_free(buf); return FALSE; } } } g_free(buf); if (ok && out) fclose(out); if (ok && !opt_dry) mk_meta(e, uidhash, gidhash); #ifdef DEBUG msgd(__func__, __LINE__, "Wrote file `%s\'", e->f_name); #endif /* DEBUG */ opt_dry = old_dry; return TRUE; } static gboolean mk_dir(struct rdup *e, GHashTable * uidhash, GHashTable * gidhash) { struct stat *s; struct stat st; gchar *parent; if (opt_dry) return TRUE; if (lstat(e->f_name, &st) == 0) { if (S_ISDIR(st.st_mode)) { #if 0 msgd(__func__, __LINE__, _("Updating current dir `%s\'"), e->f_name); #endif /* DEBUG */ /* some dir is here - update the perms and ownership */ mk_meta(e, uidhash, gidhash); return TRUE; } } /* nothing there */ if (mkdir(e->f_name, e->f_mode) == -1) { if (errno == EACCES) { /* make parent dir writable, and try again */ parent = dir_parent(e->f_name); #ifdef DEBUG msgd(__func__, __LINE__, _("EACCES for `%s\'"), parent); #endif /* DEBUG */ s = dir_write(parent); if (!s) msgd(__func__, __LINE__, _("Failed to make parent writable")); if (mkdir(e->f_name, e->f_mode) == -1) { msgd(__func__, __LINE__, _("Failed to create directory `%s\': %s"), e->f_name, strerror(errno)); dir_restore(parent, s); g_free(parent); return FALSE; } dir_restore(parent, s); g_free(parent); } else { msgd(__func__, __LINE__, _("Failed to create directory `%s\': %s"), e->f_name, strerror(errno)); return FALSE; } } mk_meta(e, uidhash, gidhash); return TRUE; } /* make (or delete) an object in the filesystem */ gboolean mk_obj(FILE * in, char *p, struct rdup * e, GHashTable * uidhash, GHashTable * gidhash) { if (opt_verbose >= 1 && e->f_name) { if (S_ISLNK(e->f_mode) || e->f_lnk) fprintf(stderr, "%s -> %s\n", e->f_name, e->f_target); else fprintf(stderr, "%s\n", e->f_name); } if (opt_table) rdup_write_table(e, stdout); /* split here - or above - return when path is zero length * for links check that the f_size is zero */ switch (e->plusmin) { case MINUS: if (opt_dry || !e->f_name) return TRUE; return rm(e->f_name); case PLUS: /* opt_dry handled within the subfunctions */ /* only files, no hardlinks! */ if (S_ISREG(e->f_mode) && !e->f_lnk) return mk_reg(in, e, uidhash, gidhash); /* no name, we can exit here - for files this is handled * in mk_reg, because we may need to suck in data */ if (e->f_name == NULL) return TRUE; if (S_ISDIR(e->f_mode)) return mk_dir(e, uidhash, gidhash); /* First sym and hardlinks and then regular files */ if (S_ISLNK(e->f_mode) || e->f_lnk) return mk_link(e, p, uidhash, gidhash); if (S_ISBLK(e->f_mode) || S_ISCHR(e->f_mode)) return mk_dev(e, uidhash, gidhash); // There's no way to restore a named socket if (S_ISSOCK(e->f_mode)) return TRUE; if (S_ISFIFO(e->f_mode)) return mk_sock(e, uidhash, gidhash); } /* only reached during the heat death of the universe */ return TRUE; } /* Create the remaining hardlinks in the target directory */ gboolean mk_hlink(GSList * h) { struct rdup *e; GSList *p; struct stat *st; gchar *parent; if (opt_dry) return TRUE; for (p = g_slist_nth(h, 0); p; p = p->next) { e = (struct rdup *)p->data; if (link(e->f_target, e->f_name) == -1) { if (errno == EACCES) { parent = dir_parent(e->f_name); st = dir_write(parent); if (link(e->f_target, e->f_name) == -1) { msgd(__func__, __LINE__, _ ("Failed to create hardlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); dir_restore(parent, st); g_free(parent); return FALSE; } dir_restore(parent, st); g_free(parent); return TRUE; } else { msgd(__func__, __LINE__, _ ("Failed to create hardlink `%s -> %s\': %s"), e->f_name, e->f_target, strerror(errno)); return FALSE; } } entry_free(e); } return TRUE; } rdup-1.1.15/getdelim.c000066400000000000000000000022241303430127500145050ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup.h" #define GETDELIM_BUFFER 128 extern int sig; /* copied from xine-devel, same license applies * slightly modified to fit my needs */ ssize_t rdup_getdelim(char **lineptr, size_t * n, int delimiter, FILE * stream) { char *p; int c; size_t len = 0; if (!lineptr || !n || (!*lineptr && *n)) return -1; /* **lineptr is allocated */ p = *lineptr; /* read characters from stream */ while ((c = fgetc(stream)) != EOF) { if (sig != 0) { fclose(stream); signal_abort(sig); } if (len >= *n) { msg(_("Line longer than %d characters"), *n); return 0; #if 0 char *np = g_realloc(*lineptr, *n * 2); if (!np) return -1; p = np + (p - *lineptr); *lineptr = np; *n *= 2; #endif } *p++ = (char)c; len++; if (delimiter == c) break; } /* end of file without any bytes read */ if ((c == EOF) && (len == 0)) return -1; /* trailing "\0" */ if (len >= *n) { char *np = g_realloc(*lineptr, *n + 1); if (!np) return -1; p = np + (p - *lineptr); *lineptr = np; *n += 1; } *p = '\0'; return len; } rdup-1.1.15/gfunc.c000066400000000000000000000326301303430127500140210ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * * g_tree_foreach helper functions */ #include "rdup.h" #include "protocol.h" #include #ifdef HAVE_LIBNETTLE #include #else #define SHA1_DIGEST_SIZE 20 #endif /* HAVE_LIBNETTLE */ extern gboolean opt_removed; extern gboolean opt_modified; extern gboolean opt_skip; extern gint opt_verbose; extern char *opt_format; extern time_t opt_timestamp; extern size_t opt_size; extern int sig; extern GList *list; extern GSList *child; /* sha1.c */ int sha1_stream(FILE * stream, void *digest); /* * calculates a files sha1 sum */ static gboolean sha1(FILE * fp, __attribute__ ((unused)) char *filename) { #ifdef HAVE_LIBNETTLE unsigned char digest[SHA1_DIGEST_SIZE]; gint i; FILE *file; if ((file = fopen(filename, "r")) == NULL) { msg(_("Could not open '%s\': %s"), filename, strerror(errno)); return FALSE; } if (sha1_stream(file, digest) != 0) { msg(_("Failed to calculate sha1 digest: `%s\'"), filename); fclose(file); return FALSE; } fclose(file); for (i = 0; i < SHA1_DIGEST_SIZE; i++) { fprintf(fp, "%02x", digest[i]); } #else fprintf(fp, "%s", NO_SHA); #endif /* HAVE_LIBNETTLE */ return TRUE; } /* * cat the files' contents */ static gboolean cat(FILE * fp, char *filename) { char buf[BUFSIZE + 1]; FILE *file; ssize_t i; gboolean nullblock = FALSE; GSList *pipes, *pids; int *parent; if ((file = fopen(filename, "r")) == NULL) { msg(_("Could not open '%s\': %s"), filename, strerror(errno)); return FALSE; } clearerr(file); if (child == NULL) { while (!feof(file) && (!ferror(file))) { if (sig != 0) { fclose(file); signal_abort(sig); } i = fread(buf, sizeof(char), BUFSIZE, file); if (block_out_header(fp, i, -1) == -1 || block_out(fp, i, buf, -1)) { msg(_("Write failure `%s\': %s"), filename, strerror(errno)); fclose(file); return FALSE; } /* there is no diff between 0 bytes block and a ending block */ if (i == 0) nullblock = TRUE; } if (ferror(file)) { msg(_("Read failure `%s\'"), filename); fclose(file); return FALSE; } fclose(file); } else { pids = create_children(child, &pipes, fileno(file)); if (!pids) { fclose(file); return FALSE; } parent = (g_slist_last(pipes))->data; i = read(parent[0], buf, BUFSIZE); if (i == -1) { msg(_("Failure to read from pipe: %s"), strerror(errno)); fclose(file); close(parent[0]); return FALSE; } while (i > 0) { if (sig != 0) signal_abort(sig); if (block_out_header(fp, i, -1) == -1 || block_out(fp, i, buf, -1)) { msg(_("Write failure `%s\': %s"), filename, strerror(errno)); fclose(file); close(parent[0]); return FALSE; } /* there is no diff between 0 bytes block and a ending block */ if (i == 0) nullblock = TRUE; i = read(parent[0], buf, BUFSIZE); } if (i < 0) { msg(_("Read failure `%s\': %s"), filename, strerror(errno)); fclose(file); close(parent[0]); return FALSE; } close(parent[0]); fclose(file); if (sig != 0) signal_abort(sig); /* wait for our children */ if (wait_pids(pids, 0) == -1) { msg(_("Weird child exit `%s\': %s"), filename, strerror(errno)); /* weird child exit */ return FALSE; } } if (!nullblock) { if (block_out_header(fp, 0, -1) == -1) { msg(_("Write failure `%s\': %s"), filename, strerror(errno)); fclose(file); return FALSE; } } return TRUE; } /* * cat the contents, only when adding and only for files */ static void entry_cat_data(FILE * fp, struct rdup *e) { if (S_ISREG(e->f_mode) && e->f_lnk == 0) { if (!cat(fp, e->f_name)) exit(EXIT_FAILURE); return; } } /** * print an escape sequence correctly */ static void entry_print_escape(char n, FILE * out) { switch (n) { case 'a': fputc('\a', out); break; case 'b': fputc('\b', out); break; case 'e': fputc('\e', out); break; case 'f': fputc('\f', out); break; case 'r': fputc('\r', out); break; case 't': fputc('\t', out); break; case 'v': fputc('\v', out); break; case '0': fputc('\0', out); break; case 'n': fputc('\n', out); break; default: fputc(n, out); break; } } /** * print arbitrary data field */ static void entry_print_data(FILE * out, char n, struct rdup *e) { switch (n) { case 'n': fputs(e->f_name, out); if (S_ISLNK(e->f_mode) || e->f_lnk == 1) { fputs(" -> ", out); fputs(e->f_target, out); } break; case 'N': fputs(e->f_name, out); break; case 'l': #if 0 if (S_ISLNK(e->f_mode) || e->f_lnk == 1) { fprintf(stderr, "[%s] [%s]\n", e->f_name, e->f_target); fprintf(stderr, "%d %d\n", (int)e->f_name_size, strlen(e->f_target)); fprintf(out, "%ld", (unsigned long)e->f_name_size + 4 + (unsigned long)strlen(e->f_target)); } else #endif fprintf(out, "%ld", (unsigned long)e->f_name_size); break; case 'u': fprintf(out, "%ld", (unsigned long)e->f_uid); break; case 'U': if (!e->f_user) fprintf(out, "-"); else fprintf(out, "%s", e->f_user); break; case 'g': fprintf(out, "%ld", (unsigned long)e->f_gid); break; case 'G': if (!e->f_group) fprintf(out, "-"); else fprintf(out, "%s", e->f_group); break; case 'm': fprintf(out, "%d", (int)e->f_mode); break; case 'b': fprintf(out, "%.4o", (int)e->f_mode & 07777); break; case 't': fprintf(out, "%ld", (unsigned long)e->f_mtime); break; case 's': /* don't report size for directories. */ if (S_ISDIR(e->f_mode)) { fputc('0', out); break; } /* hijack size for major,minor number when special */ if (S_ISBLK(e->f_mode) || S_ISCHR(e->f_mode)) { fprintf(out, "%d,%d", (unsigned int)major(e->f_rdev), (unsigned int)minor(e->f_rdev)); break; } /* links */ if (S_ISLNK(e->f_mode) || e->f_lnk == 1) { fprintf(out, "%jd", e->f_size); break; } fprintf(out, "%jd", e->f_size); break; case 'H': /* sha1 hash */ if (S_ISREG(e->f_mode)) { sha1(out, e->f_name); break; } fprintf(out, NO_SHA); break; case 'T': /* file type */ if (S_ISDIR(e->f_mode)) { fputc('d', out); } else if (S_ISCHR(e->f_mode)) { fputc('c', out); } else if (S_ISBLK(e->f_mode)) { fputc('b', out); } else if (S_ISFIFO(e->f_mode)) { fputc('p', out); } else if (S_ISSOCK(e->f_mode)) { fputc('s', out); } else if (S_ISLNK(e->f_mode)) { fputc('l', out); } else { if (e->f_lnk == 1) { fputc('h', out); } else fputc('-', out); } break; default: fputc(' ', out); break; } } /** * print function */ void entry_print(FILE * out, guint pm, struct rdup *e, char *fmt) { char *pos; if ((pm == PLUS) && (opt_modified == FALSE)) return; if ((pm == MINUS) && (opt_removed == FALSE)) return; if (opt_verbose >= 1) { fputs("** ", stderr); fputc(pm == PLUS ? '+' : '-', stderr); fprintf(stderr, " %s", e->f_name); if (S_ISLNK(e->f_mode) || e->f_lnk == 1) fprintf(stderr, " -> %s\n", e->f_target); else fputs("\n", stderr); } /* next check if we can read the file, if not - skip it and don't emit * anything */ if (S_ISREG(e->f_mode) && pm == PLUS && e->f_lnk == 0) { if (access(e->f_name, R_OK) == -1) { msg("Unable to open file `%s\': %s", e->f_name, strerror(errno)); return; } } for (pos = fmt; *pos != '\0'; ++pos) { switch (*pos) { /* c-style escapes are valid */ case '\\': ++pos; entry_print_escape(*pos, out); break; /* emit data */ case '%': ++pos; switch (*pos) { case '%': fputc('%', out); break; case 'p': fputc(pm == PLUS ? '+' : '-', out); break; case 'C': if (pm == PLUS) { entry_cat_data(out, e); } break; default: entry_print_data(out, *pos, e); break; } break; /* don't know? echo it. */ default: fputc(*pos, out); break; } } } /** * Write our internal filelist */ gboolean gfunc_write(gpointer data, gpointer value, gpointer fp) { struct rdup *e = (struct rdup *)data; char linktype = '-'; size_t file_size, name_size; gchar *n; if (sig != 0) signal_abort(sig); if (value == NO_PRINT) return FALSE; if (e->f_lnk == 1) linktype = 'h'; if (S_ISLNK(e->f_mode)) linktype = 'l'; file_size = e->f_size; name_size = e->f_name_size; if (S_ISLNK(e->f_mode) || e->f_lnk == 1) n = g_strdup_printf("%s -> %s", e->f_name, e->f_target); else n = strdup(e->f_name); if (S_ISDIR(e->f_mode)) /* the same as in the normal output */ file_size = 0; fprintf((FILE *) fp, "%5ld %ld %lld %c %ld %ld %ld %lld %s", (long int)e->f_mode, (long int)e->f_dev, (long long)e->f_ino, linktype, (long int)e->f_uid, (long int)e->f_gid, (long int)name_size, (long long)file_size, n); fputc('\n', (FILE *) fp); g_free(n); return FALSE; } /** * write out the list of to be backupped items */ gboolean gfunc_backup(gpointer data, gpointer value, __attribute__ ((unused)) gpointer usr) { if (sig != 0) signal_abort(sig); /* .nobackup seen, don't print it */ if (value == NO_PRINT) return FALSE; if (S_ISDIR(((struct rdup *)data)->f_mode)) { entry_print(stdout, PLUS, (struct rdup *)data, opt_format); return FALSE; } else { if (opt_size != 0 && S_ISREG(((struct rdup *)data)->f_mode) && ((struct rdup *)data)->f_size > (ssize_t) opt_size) { return FALSE; } switch (opt_timestamp) { case NULL_DUMP: entry_print(stdout, PLUS, (struct rdup *)data, opt_format); return FALSE; default: /* INC_DUMP */ if (((struct rdup *)data)->f_ctime >= opt_timestamp) { entry_print(stdout, PLUS, (struct rdup *)data, opt_format); #if DEBUG msgd(__func__, __LINE__, "%s %ld >= %ld diff %ld\n", ((struct rdup *)data)->f_name, (long int)((struct rdup *)data)->f_ctime, (long int)opt_timestamp, (long int)opt_timestamp - (long int)((struct rdup *)data)->f_ctime); #endif /* DEBUG */ } return FALSE; } } return FALSE; } /** * write out the list of removed items */ gboolean gfunc_remove(gpointer data, gpointer value, __attribute__ ((unused)) gpointer usr) { if (sig != 0) signal_abort(sig); /* should not have these here!! */ if (value == NO_PRINT) { msg(_("Internal error: NO_PRINT in remove tree!")); return FALSE; } entry_print(stdout, MINUS, (struct rdup *)data, opt_format); return FALSE; } /** * Print out the list of new item */ gboolean gfunc_new(gpointer data, __attribute__ ((unused)) gpointer value, __attribute__ ((unused)) gpointer usr) { if (sig != 0) signal_abort(sig); /* it is perfectly possibly to have these here */ if (value == NO_PRINT) return FALSE; if (opt_size != 0 && S_ISREG(((struct rdup *)data)->f_mode) && ((struct rdup *)data)->f_size > (ssize_t) opt_size) { return FALSE; } entry_print(stdout, PLUS, (struct rdup *)data, opt_format); return FALSE; } /** * decide whether 2 struct entries are equal or not * 0 = equal */ gint gfunc_equal(gconstpointer a, gconstpointer b) { gint e; struct rdup *ae, *be; ae = (struct rdup *)a; be = (struct rdup *)b; if (sig != 0) signal_abort(sig); e = strcmp(((struct rdup *)a)->f_name, ((struct rdup *)b)->f_name); if (e == 0) { /* * newer Linux version automount disks, so sometimes /dev/sda becomes * /dev/sdb. This leads to an full dump which isn't needed. */ /* if (ae->f_dev != be->f_dev) return -1; */ if (ae->f_ino != be->f_ino) return -2; /* if we are looking at a directory and only the mode has changed * don't let rdup remove the entire directory */ if (S_ISDIR(ae->f_mode) && S_ISDIR(be->f_mode) && ((ae->f_mode & 07777) != (be->f_mode & 07777))) return 0; if (ae->f_mode != be->f_mode) return -3; } return e; } /** * used in the crawler, remove specific paths on finding a .nobackup */ gboolean gfunc_remove_path(gpointer data, gpointer __attribute__ ((unused)) value, gpointer r) { if (sig != 0) signal_abort(sig); if (strncmp(((struct rdup *)data)->f_name, ((struct remove_path *)r)->path, ((struct remove_path *)r)->len) == 0) { /* don't remove the directory itself */ if (S_ISDIR(((struct rdup *)data)->f_mode)) return FALSE; g_tree_insert(((struct remove_path *)r)->tree, data, NO_PRINT); } return FALSE; } /** * traverse function * implement the tree subtraction * everything in A, but NOT in b * (data := element out of A) * (b := packed in diff, diff->b) * This function is essentially the most expensive function * in rdup... */ gboolean gfunc_subtract(gpointer data, gpointer value, gpointer diff) { gpointer v; if (sig != 0) signal_abort(sig); v = g_tree_lookup((GTree *) ((struct subtract *)diff)->b, data); if (!v) g_tree_insert(((struct subtract *)diff)->d, data, value); return FALSE; } /** * Walk the linked list and return TRUE when a regexp * matches, otherwise return FALSE */ gboolean gfunc_regexp(GSList * l, char *n, size_t len) { GSList *k; pcre *P; int ovector[REG_VECTOR]; for (k = g_slist_nth(l, 0); k; k = k->next) { if (sig != 0) signal_abort(sig); P = (pcre *) k->data; /* pcre_exec errors are all < 0, so >= 0 is some kind * of success */ if (pcre_exec(P, NULL, n, len, 0, 0, ovector, REG_VECTOR) >= 0) return TRUE; } return FALSE; } /** * put an element of the tree in a double linked list */ gboolean gfunc_tree2list(gpointer data, gpointer value, __attribute__ ((unused)) gpointer l) { if (sig != 0) signal_abort(sig); if (value == NO_PRINT) return FALSE; list = g_list_prepend(list, data); return FALSE; } rdup-1.1.15/glib-2.0.m4000066400000000000000000000177621303430127500142400ustar00rootroot00000000000000# Configure paths for GLIB # Owen Taylor 1997-2001 dnl AM_PATH_GLIB_2_0([MINIMUM-VERSION, [ACTION-IF-FOUND [, ACTION-IF-NOT-FOUND [, MODULES]]]]) dnl Test for GLIB, and define GLIB_CFLAGS and GLIB_LIBS, if gmodule, gobject or dnl gthread is specified in MODULES, pass to pkg-config dnl AC_DEFUN([AM_PATH_GLIB_2_0], [dnl dnl Get the cflags and libraries from pkg-config dnl AC_ARG_ENABLE(glibtest, [ --disable-glibtest do not try to compile and run a test GLIB program], , enable_glibtest=yes) pkg_config_args=glib-2.0 for module in . $4 do case "$module" in gmodule) pkg_config_args="$pkg_config_args gmodule-2.0" ;; gobject) pkg_config_args="$pkg_config_args gobject-2.0" ;; gthread) pkg_config_args="$pkg_config_args gthread-2.0" ;; esac done AC_PATH_PROG(PKG_CONFIG, pkg-config, no) no_glib="" if test x$PKG_CONFIG != xno ; then if $PKG_CONFIG --atleast-pkgconfig-version 0.7 ; then : else echo *** pkg-config too old; version 0.7 or better required. no_glib=yes PKG_CONFIG=no fi else no_glib=yes fi min_glib_version=ifelse([$1], ,2.0.0,$1) AC_MSG_CHECKING(for GLIB - version >= $min_glib_version) if test x$PKG_CONFIG != xno ; then ## don't try to run the test against uninstalled libtool libs if $PKG_CONFIG --uninstalled $pkg_config_args; then echo "Will use uninstalled version of GLib found in PKG_CONFIG_PATH" enable_glibtest=no fi if $PKG_CONFIG --atleast-version $min_glib_version $pkg_config_args; then : else no_glib=yes fi fi if test x"$no_glib" = x ; then GLIB_GENMARSHAL=`$PKG_CONFIG --variable=glib_genmarshal glib-2.0` GOBJECT_QUERY=`$PKG_CONFIG --variable=gobject_query glib-2.0` GLIB_MKENUMS=`$PKG_CONFIG --variable=glib_mkenums glib-2.0` GLIB_CFLAGS=`$PKG_CONFIG --cflags $pkg_config_args` GLIB_LIBS=`$PKG_CONFIG --libs $pkg_config_args` glib_config_major_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\1/'` glib_config_minor_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\2/'` glib_config_micro_version=`$PKG_CONFIG --modversion glib-2.0 | \ sed 's/\([[0-9]]*\).\([[0-9]]*\).\([[0-9]]*\)/\3/'` if test "x$enable_glibtest" = "xyes" ; then ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$GLIB_LIBS $LIBS" dnl dnl Now check if the installed GLIB is sufficiently new. (Also sanity dnl checks the results of pkg-config to some extent) dnl rm -f conf.glibtest AC_TRY_RUN([ #include #include #include int main () { int major, minor, micro; char *tmp_version; system ("touch conf.glibtest"); /* HP/UX 9 (%@#!) writes to sscanf strings */ tmp_version = g_strdup("$min_glib_version"); if (sscanf(tmp_version, "%d.%d.%d", &major, &minor, µ) != 3) { printf("%s, bad version string\n", "$min_glib_version"); exit(1); } if ((glib_major_version != $glib_config_major_version) || (glib_minor_version != $glib_config_minor_version) || (glib_micro_version != $glib_config_micro_version)) { printf("\n*** 'pkg-config --modversion glib-2.0' returned %d.%d.%d, but GLIB (%d.%d.%d)\n", $glib_config_major_version, $glib_config_minor_version, $glib_config_micro_version, glib_major_version, glib_minor_version, glib_micro_version); printf ("*** was found! If pkg-config was correct, then it is best\n"); printf ("*** to remove the old version of GLib. You may also be able to fix the error\n"); printf("*** by modifying your LD_LIBRARY_PATH enviroment variable, or by editing\n"); printf("*** /etc/ld.so.conf. Make sure you have run ldconfig if that is\n"); printf("*** required on your system.\n"); printf("*** If pkg-config was wrong, set the environment variable PKG_CONFIG_PATH\n"); printf("*** to point to the correct configuration files\n"); } else if ((glib_major_version != GLIB_MAJOR_VERSION) || (glib_minor_version != GLIB_MINOR_VERSION) || (glib_micro_version != GLIB_MICRO_VERSION)) { printf("*** GLIB header files (version %d.%d.%d) do not match\n", GLIB_MAJOR_VERSION, GLIB_MINOR_VERSION, GLIB_MICRO_VERSION); printf("*** library (version %d.%d.%d)\n", glib_major_version, glib_minor_version, glib_micro_version); } else { if ((glib_major_version > major) || ((glib_major_version == major) && (glib_minor_version > minor)) || ((glib_major_version == major) && (glib_minor_version == minor) && (glib_micro_version >= micro))) { return 0; } else { printf("\n*** An old version of GLIB (%d.%d.%d) was found.\n", glib_major_version, glib_minor_version, glib_micro_version); printf("*** You need a version of GLIB newer than %d.%d.%d. The latest version of\n", major, minor, micro); printf("*** GLIB is always available from ftp://ftp.gtk.org.\n"); printf("***\n"); printf("*** If you have already installed a sufficiently new version, this error\n"); printf("*** probably means that the wrong copy of the pkg-config shell script is\n"); printf("*** being found. The easiest way to fix this is to remove the old version\n"); printf("*** of GLIB, but you can also set the PKG_CONFIG environment to point to the\n"); printf("*** correct copy of pkg-config. (In this case, you will have to\n"); printf("*** modify your LD_LIBRARY_PATH enviroment variable, or edit /etc/ld.so.conf\n"); printf("*** so that the correct libraries are found at run-time))\n"); } } return 1; } ],, no_glib=yes,[echo $ac_n "cross compiling; assumed OK... $ac_c"]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi if test "x$no_glib" = x ; then AC_MSG_RESULT(yes (version $glib_config_major_version.$glib_config_minor_version.$glib_config_micro_version)) ifelse([$2], , :, [$2]) else AC_MSG_RESULT(no) if test "$PKG_CONFIG" = "no" ; then echo "*** A new enough version of pkg-config was not found." echo "*** See http://www.freedesktop.org/software/pkgconfig/" else if test -f conf.glibtest ; then : else echo "*** Could not run GLIB test program, checking why..." ac_save_CFLAGS="$CFLAGS" ac_save_LIBS="$LIBS" CFLAGS="$CFLAGS $GLIB_CFLAGS" LIBS="$LIBS $GLIB_LIBS" AC_TRY_LINK([ #include #include ], [ return ((glib_major_version) || (glib_minor_version) || (glib_micro_version)); ], [ echo "*** The test program compiled, but did not run. This usually means" echo "*** that the run-time linker is not finding GLIB or finding the wrong" echo "*** version of GLIB. If it is not finding GLIB, you'll need to set your" echo "*** LD_LIBRARY_PATH environment variable, or edit /etc/ld.so.conf to point" echo "*** to the installed location Also, make sure you have run ldconfig if that" echo "*** is required on your system" echo "***" echo "*** If you have an old version installed, it is best to remove it, although" echo "*** you may also be able to get things to work by modifying LD_LIBRARY_PATH" ], [ echo "*** The test program failed to compile or link. See the file config.log for the" echo "*** exact error that occured. This usually means GLIB is incorrectly installed."]) CFLAGS="$ac_save_CFLAGS" LIBS="$ac_save_LIBS" fi fi GLIB_CFLAGS="" GLIB_LIBS="" GLIB_GENMARSHAL="" GOBJECT_QUERY="" GLIB_MKENUMS="" ifelse([$3], , :, [$3]) fi AC_SUBST(GLIB_CFLAGS) AC_SUBST(GLIB_LIBS) AC_SUBST(GLIB_GENMARSHAL) AC_SUBST(GOBJECT_QUERY) AC_SUBST(GLIB_MKENUMS) rm -f conf.glibtest ]) rdup-1.1.15/install-sh000077500000000000000000000127361303430127500145640ustar00rootroot00000000000000#!/bin/sh # # install - install a program, script, or datafile # This comes from X11R5 (mit/util/scripts/install.sh). # # Copyright 1991 by the Massachusetts Institute of Technology # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation, and that the name of M.I.T. not be used in advertising or # publicity pertaining to distribution of the software without specific, # written prior permission. M.I.T. makes no representations about the # suitability of this software for any purpose. It is provided "as is" # without express or implied warranty. # # 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. It can only install one file at a time, a restriction # shared with many OS's install programs. # 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}" transformbasename="" 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=: chmodcmd="" 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 rdup-1.1.15/io.h000066400000000000000000000004631303430127500133320ustar00rootroot00000000000000#ifndef _IO_H #define _IO_H #define O_NONE 0 #define O_TAR 1 #define O_CPIO 2 #define O_PAX 3 #define O_RDUP 4 #define I_NONE 0 #define I_LIST 1 /* the input is a list of files names */ #define I_RDUP 2 /* the input is the standard rdup output */ #endif /* _IO_H */ rdup-1.1.15/link.c000066400000000000000000000016321303430127500136520ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * * dev_t,ino_t -> path look up table * needed for hardlink implementation */ #include "rdup.h" /** * Find if there is a hardlink for this file * If found, return it, otherwise add it to * the hashtable. */ gchar *hlink(GHashTable * t, struct rdup *e) { gchar *key; gchar *name; /* use , to make it unique */ key = g_strdup_printf("%d,%d", (gint) e->f_dev, (gint) e->f_ino); if (!(name = g_hash_table_lookup(t, (gpointer) key))) { g_hash_table_insert(t, key, g_strdup(e->f_name)); } return g_strdup(name); /* entry_free will free this */ } gchar *slink(struct rdup * e) { char buf[BUFSIZE + 1]; ssize_t i; if ((i = readlink(e->f_name, buf, BUFSIZE)) == -1) { msg(_("Error reading link `%s\': %s"), e->f_name, strerror(errno)); return NULL; } else { buf[i] = '\0'; return g_strdup(buf); } } rdup-1.1.15/mkpath.c000066400000000000000000000020551303430127500142010ustar00rootroot00000000000000/* Function with behaviour like `mkdir -p' */ /* From: http://niallohiggins.com/2009/01/08/mkpath-mkdir-p-alike-in-c-for-unix/ * with some tweaks * libglib'i'fied by Miek Gieben */ #include "rdup-up.h" int mkpath(const char *s, mode_t mode) { char *q, *r = NULL, *path = NULL, *up = NULL; int rv = -1; if (strcmp(s, ".") == 0 || strcmp(s, "/") == 0) return 0; #ifdef DEBUG msgd(__func__, __LINE__, _("Path ele '%s\'"), s); #endif /* DEBUG */ if ((path = g_strdup(s)) == NULL) return -1; if ((q = g_strdup(s)) == NULL) return -1; if ((r = dirname(q)) == NULL) goto out; if ((up = g_strdup(r)) == NULL) return -1; if ((mkpath(up, mode) == -1) && (errno != EEXIST)) { msgd(__func__, __LINE__, _("Failed or exists '%s\': %s"), up, strerror(errno)); goto out; } if ((mkdir(path, mode) == -1) && (errno != EEXIST)) msgd(__func__, __LINE__, _("Failed to create directory '%s\': %s"), path, strerror(errno)); else rv = 0; out: if (up) g_free(up); if (q) g_free(q); if (path) g_free(path); return rv; } rdup-1.1.15/msg.c000066400000000000000000000016631303430127500135070ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup.h" extern char *PROGNAME; void msg_va_list(const char *fmt, va_list args) { fprintf(stderr, "** %s: ", PROGNAME); vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } /* only with debugging enabled will this call be different */ void msgd_va_list( __attribute__ ((unused)) const char *func, __attribute__ ((unused)) int line, const char *fmt, va_list args) { #ifdef DEBUG fprintf(stderr, "** %s: %s():%d ", PROGNAME, func, line); #else fprintf(stderr, "** %s: ", PROGNAME); #endif /* DEBUG */ vfprintf(stderr, fmt, args); fprintf(stderr, "\n"); } void msg(const char *fmt, ...) { va_list args; va_start(args, fmt); msg_va_list(fmt, args); va_end(args); } void msgd(const char *func, int line, const char *fmt, ...) { va_list args; va_start(args, fmt); msgd_va_list(func, line, fmt, args); va_end(args); } rdup-1.1.15/names.c000066400000000000000000000045501303430127500140220ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * lookup the user/group names associated with the uid/gid * Use hashes to speed things up */ #include "rdup.h" /* lookup the uid belonging to username * if the uid is not found, return uid_given * otherwise return the uid belonging to the username * ON THIS SYSTEM */ uid_t lookup_uid(GHashTable * u, gchar * user, uid_t uid_given) { uid_t uid, *uid_tmp; struct passwd *p; if (uid_given == 0) return 0; uid_tmp = (uid_t *) g_hash_table_lookup(u, user); if (uid_tmp) return *uid_tmp; p = getpwnam(user); if (!p) /* user does not exist on this system */ return uid_given; uid = p->pw_uid; uid_tmp = g_malloc(sizeof(uid_t)); *uid_tmp = uid; g_hash_table_insert(u, g_strdup(user), (gpointer) uid_tmp); uid_tmp = (uid_t *) g_hash_table_lookup(u, user); return *uid_tmp; } /* see lookup_uid, but now for groups */ gid_t lookup_gid(GHashTable * g, gchar * group, gid_t gid_given) { gid_t gid, *gid_tmp; struct group *p; if (gid_given == 0) return 0; gid_tmp = (gid_t *) g_hash_table_lookup(g, group); if (gid_tmp) return *gid_tmp; p = getgrnam(group); if (!p) /* grp does not exist on this system */ return gid_given; gid = p->gr_gid; gid_tmp = g_malloc(sizeof(gid_t)); *gid_tmp = gid; g_hash_table_insert(g, g_strdup(group), (gpointer) gid_tmp); gid_tmp = (gid_t *) g_hash_table_lookup(g, group); return *gid_tmp; } gchar *lookup_user(GHashTable * u, uid_t uid) { gchar *n; struct passwd *p; n = (gchar *) g_hash_table_lookup(u, (gpointer) & uid); if (n) return n; /* if nothing found also add to hash? */ p = getpwuid(uid); if (!p) /* user only has ID */ return NULL; /* don't return the string as it might be overwritten in * subsequent calls to getpwnam. Use the pointer stored * in the hash. This is also the case for getgrgid() */ n = g_strdup(p->pw_name); g_hash_table_insert(u, (gpointer) & uid, n); return (gchar *) g_hash_table_lookup(u, (gpointer) & uid); } gchar *lookup_group(GHashTable * g, gid_t gid) { gchar *n; struct group *p; n = (gchar *) g_hash_table_lookup(g, (gpointer) & gid); if (n) return n; p = getgrgid(gid); if (!p) /* group only has ID */ return NULL; n = g_strdup(p->gr_name); g_hash_table_insert(g, (gpointer) & gid, n); return (gchar *) g_hash_table_lookup(g, (gpointer) & gid); } rdup-1.1.15/po/000077500000000000000000000000001303430127500131655ustar00rootroot00000000000000rdup-1.1.15/po/GNUmakefile.in000066400000000000000000000017541303430127500156530ustar00rootroot00000000000000prefix=@prefix@ exec_prefix=@exec_prefix@ datarootdir=@datarootdir@ localedir=@localedir@ bindir=@bindir@ sbindir=@sbindir@ mandir=@mandir@ sysconfdir=@sysconfdir@ datadir=@datadir@/rdup # copy rdup.pot to here # msginit OR copy rdup.pot to nl.po # and nl to LINGUAS and translate .SUFFIXES: .po .gmo .mo all: @for i in $$(cat LINGUAS); do make $$i.gmo; done %.gmo: %.po msgfmt -c -o $@ $< clean: rm -f *.gmo for i in $$(cat LINGUAS); do rm -rf $$i; done realclean: clean rm -rf autom4te.cache rm -f config.log rm -f config.status rm -f config.h distclean: # create a small mirror of the actual dir layout in the filesystem install: all for i in $$(cat LINGUAS); do rm -rf $$i && mkdir $$i; \ cp $$i.gmo $$i/rdup.mo; done for i in $$(cat LINGUAS); do \ mkdir -p $(DESTDIR)/${localedir}/$$i/LC_MESSAGES; \ cp $$i/rdup.mo $(DESTDIR)/${localedir}/$$i/LC_MESSAGES/rdup.mo; \ done uninstall: for i in $$(cat LINGUAS); do \ rm ${localedir}/$$i/LC_MESSAGES/rdup.mo; \ done rdup-1.1.15/po/LINGUAS000066400000000000000000000000001303430127500142000ustar00rootroot00000000000000rdup-1.1.15/po/de.po000066400000000000000000000421251303430127500141210ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: rdup 0.9.1\n" "PO-Revision-Date: 2009-03-05 17:56+0100\n" "Last-Translator: sven.grounsell \n" "Language-Team: German\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: usage.c:32 msgid "" " -c\t\tcat the contents (FORMAT=\"%p%T %b %u %g %l %s\\n%n%C\")\n" " -m\t\tonly print new/modified files (unsets -r)\n" " -n\t\tignore .nobackup files\n" " -r\t\tonly print removed files (unsets -m)\n" " -s SIZE\t\tonly output files smaller then SIZE bytes\n" " -x\t\tstay in local file system\n" " -v\t\tbe more verbose\n" " -h\t\tthis help\n" "\n" " FORMAT:\n" " The following escape sequences are recognized:\n" " '%p': '+' if new, '-' if removed\n" " '%b': permission bits\n" " '%m': file mode bits\n" " '%u': uid\n" " '%g': gid\n" " '%l': path length (for links: length of 'path -> target')\n" " '%s': file size\n" " '%n': path (for links: 'path -> target')\n" " '%N': path (for links: 'path')\n" " '%t': time of modification (epoch)\n" " '%H': the sha1 hash of the file's contents\n" " '%T': 'type' (d, l, h, -, c, b, p or s: dir, symlink, hardlink, " "file, \n" "\t character device, block device, named pipe or socket)\n" " '%C': file contents\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" " -c\t\tcat the contents (FORMAT=\"%p%T %b %u %g %l %s\\n%n%C\")\n" " -m\t\tonly print new/modified files (unsets -r)\n" " -n\t\tignore .nobackup files\n" " -r\t\tonly print removed files (unsets -m)\n" " -s SIZE\t\tonly output files smaller then SIZE bytes\n" " -x\t\tstay in local file system\n" " -v\t\tbe more verbose\n" " -h\t\tthis help\n" "\n" " FORMAT:\n" " The following escape sequences are recognized:\n" " '%p': '+' if new, '-' if removed\n" " '%b': permission bits\n" " '%m': file mode bits\n" " '%u': uid\n" " '%g': gid\n" " '%l': path length (for links: length of 'path -> target')\n" " '%s': file size\n" " '%n': path (for links: 'path -> target')\n" " '%N': path (for links: 'path')\n" " '%t': time of modification (epoch)\n" " '%H': the sha1 hash of the file's contents\n" " '%T': 'type' (d, l, h, -, c, b, p or s: dir, symlink, hardlink, " "file, \n" "\t character device, block device, named pipe or socket)\n" " '%C': file contents\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" #: crawler.c:166 #, c-format msgid "%s found in '%s'" msgstr "%s found in '%s'" #: rdup.c:338 msgid "-s requires a numerical value" msgstr "-s requires a numerical value" #: crypt.c:278 msgid "AES key must be 16, 24 or 32 bytes" msgstr "AES key must be 16, 24 or 32 bytes" #: entry.c:205 entry.c:227 #, c-format msgid "Actual pathname length is not equal to pathname length at line: %zd" msgstr "Actual pathname length is not equal to pathname length at line: %zd" #: rdup-tr.c:376 rdup-up.c:125 rdup.c:278 msgid "Argument length overrun" msgstr "Argument length overrun" #: protocol.c:109 #, c-format msgid "BLOCK protocol seperator not found: `%c%c%c%c%c'" msgstr "BLOCK protocol seperator not found: `%c%c%c%c%c'" #: protocol.c:135 #, c-format msgid "Block seen, start read of %d bytes" msgstr "Block seen, start read of %d bytes" #: protocol.c:131 msgid "Block size larger then BUFSIZE" msgstr "Block size larger then BUFSIZE" #: rdup-tr.c:450 msgid "Can not do both encryption and decryption" msgstr "Can not do both encryption and decryption" #: crawler.c:109 #, c-format msgid "Cannot determine holding device of the directory `%s': %s" msgstr "Cannot determine holding device of the directory `%s': %s" #: crawler.c:98 #, c-format msgid "Cannot enter directory `%s': %s" msgstr "Cannot enter directory `%s': %s" #: rdup-tr.c:260 msgid "Child exit, giving you the original file" msgstr "Child exit, giving you the original file" #: entry.c:86 #, c-format msgid "Corrupt entry `%s' in input at line: %zd" msgstr "Corrupt entry `%s' in input at line: %zd" #: rdup.c:180 #, c-format msgid "" "Corrupt entry in filelist at line: %zd, length `%zd' does not match `%zd'" msgstr "" "Corrupt entry in filelist at line: %zd, length `%zd' does not match `%zd'" #: regexp.c:56 #, c-format msgid "Corrupt regular expression line: %zd, column %d: %s" msgstr "Corrupt regular expression line: %zd, column %d: %s" #: rdup.c:429 #, c-format msgid "Could not create timestamp file `%s': %s" msgstr "Could not create timestamp file `%s': %s" #: rdup-tr.c:370 rdup-up.c:119 rdup.c:272 msgid "Could not get current working directory" msgstr "Could not get current working directory" #: gfunc.c:37 gfunc.c:63 rdup-tr.c:241 regexp.c:33 #, c-format msgid "Could not open '%s': %s" msgstr "Could not open '%s': %s" #: crawler.c:45 crawler.c:131 entry.c:62 entry.c:218 #, c-format msgid "Could not stat path `%s': %s" msgstr "Could not stat path `%s': %s" #: rdup.c:417 #, c-format msgid "Could not write filelist `%s': %s" msgstr "Could not write filelist `%s': %s" #: rdup-up.c:160 msgid "Destination directory is required" msgstr "Destination directory is required" #: link.c:47 #, c-format msgid "Error reading link `%s': %s" msgstr "Error reading link `%s': %s" #: gfunc.c:41 #, c-format msgid "Failed to calculate sha1 digest: `%s'" msgstr "Failed to calculate sha1 digest: `%s'" #: rdup-tr.c:135 msgid "Failed to create archive" msgstr "Failed to create archive" #: fs-up.c:194 fs-up.c:203 rdup-up.c:171 #, c-format msgid "Failed to create directory `%s': %s" msgstr "Failed to create directory `%s': %s" #: fs-up.c:301 fs-up.c:311 #, c-format msgid "Failed to create hardlink `%s -> %s': %s" msgstr "Failed to create hardlink `%s -> %s': %s" #: fs-up.c:36 #, c-format msgid "Failed to make device: `%s': %s" msgstr "Failed to make device: `%s': %s" #: fs-up.c:56 #, c-format msgid "Failed to make socket: `%s': %s" msgstr "Failed to make socket: `%s': %s" #: fs-up.c:86 fs-up.c:95 #, c-format msgid "Failed to make symlink: `%s -> %s': %s" msgstr "Failed to make symlink: `%s -> %s': %s" #: crypt.c:257 #, c-format msgid "Failed to open `%s': %s" msgstr "Failed to open `%s': %s" #: rm.c:37 #, c-format msgid "Failed to open directory `%s': %s" msgstr "Failed to open directory `%s': %s" #: fs-up.c:133 fs-up.c:140 #, c-format msgid "Failed to open file `%s': %s" msgstr "Failed to open file `%s': %s" #: crypt.c:264 #, c-format msgid "Failed to read AES key from `%s': %s" msgstr "Failed to read AES key from `%s': %s" #: rm.c:53 rm.c:78 rm.c:90 rm.c:98 #, c-format msgid "Failed to remove `%s': %s" msgstr "Failed to remove `%s': %s" #: rm.c:65 #, c-format msgid "Failed to remove directory `%s': %s" msgstr "Failed to remove directory `%s': %s" #: fs-up.c:30 fs-up.c:50 fs-up.c:74 fs-up.c:124 #, c-format msgid "Failed to remove existing entry: '%s'" msgstr "Failed to remove existing entry: '%s'" #: rdup-tr.c:156 #, c-format msgid "Failed to set archive type to %s" msgstr "Failed to set archive type to %s" #: entry.c:295 #, c-format msgid "Failed to write to stdout: %s" msgstr "Failed to write to stdout: %s" #: child.c:88 msgid "Failure creating pipes" msgstr "Failure creating pipes" #: rdup-tr.c:302 #, c-format msgid "Failure to read from file: %s" msgstr "Failure to read from file: %s" #: rdup-tr.c:254 #, c-format msgid "Failure to read from pipe: %s" msgstr "Failure to read from pipe: %s" #: rdup-tr.c:297 #, c-format msgid "Failure to rewind: %s" msgstr "Failure to rewind: %s" #: entry.c:98 #, c-format msgid "First character should '-' or '+', `%s' at line: %zd" msgstr "First character should '-' or '+', `%s' at line: %zd" #: child.c:104 msgid "Fork error" msgstr "Fork error" #: usage.c:14 msgid "" "Generate a full or incremental file list. This list can be used to\n" "implement a (incremental) backup scheme.\n" "\n" "\tFILELIST\tfile to store filenames\n" " DIR\t\tdirectory or directories to dump\n" "\n" "\n" " OPTIONS:\n" " -N FILE\t\tuse the (c_time) timestamp of FILE for incremental dumps\n" " \t\tif FILE does not exist, a full dump is performed\n" "\t-M FILE\t\tas -N, but use the m_time\n" " -F FORMAT\tuse specified format string\n" " \t\tdefaults to: \"%p%T %b %u %g %l %s %n\\n\"\n" "\t-R\t\treverse the output (depth first, first the dirs then the files)\n" "\t-E FILE\t\tuse FILE as an exclude list\n" " -0\t\tdelimit internal filelist with NULLs\n" " -V\t\tprint version\n" msgstr "" "Generate a full or incremental file list. This list can be used to\n" "implement a (incremental) backup scheme.\n" "\n" "\tFILELIST\tfile to store filenames\n" " DIR\t\tdirectory or directories to dump\n" "\n" "\n" " OPTIONS:\n" " -N FILE\t\tuse the (c_time) timestamp of FILE for incremental dumps\n" " \t\tif FILE does not exist, a full dump is performed\n" "\t-M FILE\t\tas -N, but use the m_time\n" " -F FORMAT\tuse specified format string\n" " \t\tdefaults to: \"%p%T %b %u %g %l %s %n\\n\"\n" "\t-R\t\treverse the output (depth first, first the dirs then the files)\n" "\t-E FILE\t\tuse FILE as an exclude list\n" " -0\t\tdelimit internal filelist with NULLs\n" " -V\t\tprint version\n" #: protocol.c:123 msgid "Illegal block size" msgstr "Illegal block size" #: gfunc.c:394 msgid "Internal error: NO_PRINT in remove tree!" msgstr "Internal error: NO_PRINT in remove tree!" #: rdup-tr.c:432 #, c-format msgid "Invalid output format: `%s'" msgstr "Invalid output format: `%s'" #: entry.c:129 #, c-format msgid "Invalid permissions at line: %zd" msgstr "Invalid permissions at line: %zd" #: getdelim.c:30 #, c-format msgid "Line longer than %d characters" msgstr "Line longer than %d characters" #: rdup-tr.c:351 rdup-up.c:99 rdup.c:246 msgid "Locale could not be set" msgstr "Locale could not be set" #: entry.c:191 #, c-format msgid "Malformed input for file size at line: %zd" msgstr "Malformed input for file size at line: %zd" #: entry.c:148 #, c-format msgid "Malformed input for gid at line: %zd" msgstr "Malformed input for gid at line: %zd" #: entry.c:159 #, c-format msgid "Malformed input for path length at line: %zd" msgstr "Malformed input for path length at line: %zd" #: entry.c:137 #, c-format msgid "Malformed input for uid at line: %zd" msgstr "Malformed input for uid at line: %zd" #: crypt.c:273 msgid "Maximum AES key size is 32 bytes, truncating!" msgstr "Maximum AES key size is 32 bytes, truncating!" #: crawler.c:228 #, c-format msgid "Neither file nor directory `%s'" msgstr "Neither file nor directory `%s'" #: crawler.c:137 #, c-format msgid "Newline (\\n) found in path `%s', skipping" msgstr "Newline (\\n) found in path `%s', skipping" #: xattr.c:88 xattr.c:100 #, c-format msgid "No gid xattr for `%s'" msgstr "No gid xattr for `%s'" #: rdup-up.c:176 #, c-format msgid "No such directory: `%s'" msgstr "No such directory: `%s'" #: xattr.c:36 xattr.c:48 #, c-format msgid "No uid xattr for `%s'" msgstr "No uid xattr for `%s'" #: rdup-up.c:146 msgid "Not implemented (yet)" msgstr "Not implemented (yet)" #: rdup-tr.c:406 #, c-format msgid "Only %d extra args per child allowed" msgstr "Only %d extra args per child allowed" #: rdup-up.c:65 #, c-format msgid "Pathname does not start with /: `%s'" msgstr "Pathname does not start with /: `%s'" #: entry.c:107 msgid "Removing files is not supported for any output except rdup" msgstr "Removing files is not supported for any output except rdup" #: rdup-up.c:59 #, c-format msgid "Reported name size (%zd) does not match actual name size (%zd)" msgstr "Reported name size (%zd) does not match actual name size (%zd)" #: crypt.c:147 #, c-format msgid "Returning original string `%s'" msgstr "Returning original string `%s'" #: signal.c:27 msgid "SIGINT received, exiting" msgstr "SIGINT received, exiting" #: signal.c:24 msgid "SIGPIPE received, exiting" msgstr "SIGPIPE received, exiting" #: rdup.c:372 rdup.c:378 #, c-format msgid "Skipping `%s'" msgstr "Skipping `%s'" #: xattr.c:59 xattr.c:81 xattr.c:111 #, c-format msgid "Too large gid `%zd' for `%s', truncating" msgstr "Too large gid `%zd' for `%s', truncating" #: xattr.c:29 #, c-format msgid "Too large uid `%zd' for `%s', truncating" msgstr "Too large uid `%zd' for `%s', truncating" #: usage-tr.c:14 msgid "" "Translate rdup output to something else\tand optionally filter it\n" "through other processes. The input must be rdup's default ouput\n" "format: '%p%T %b %u %g %l %s %n\\n'.\n" "The output is equal to rdup -c ouput.\n" "\n" "\n" " OPTIONS:\n" " -c\t\tforce output to tty\n" " -P CMD\n" "\t \t\tfilter file contents through CMD, will be called with 'sh -c CMD'\n" "\t\t\tthis may be repeated, output will be filtered\n" "\t\t\tthrough all commands\n" "\t-X FILE\t\tencrypt all paths with AES and the key from FILE\n" "\t-Y FILE\t\tdecrypt all paths with AES and the key from FILE\n" "\t-h\t\tthis help\n" "\t-V\t\tprint version\n" " -O FMT\t\toutput format: pax, cpio, tar or rdup\n" "\t\t\trdup uses format: \"%p%T %b %u %g %l %s\\n%n%C\"\n" "\t-L\t\tset input format to a list of pathnames\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" "Translate rdup output to something else\tand optionally filter it\n" "through other processes. The input must be rdup's default ouput\n" "format: '%p%T %b %u %g %l %s %n\\n'.\n" "The output is equal to rdup -c ouput.\n" "\n" "\n" " OPTIONS:\n" " -c\t\tforce output to tty\n" " -P CMD\n" "\t \t\tfilter file contents through CMD, will be called with 'sh -c CMD'\n" "\t\t\tthis may be repeated, output will be filtered\n" "\t\t\tthrough all commands\n" "\t-X FILE\t\tencrypt all paths with AES and the key from FILE\n" "\t-Y FILE\t\tdecrypt all paths with AES and the key from FILE\n" "\t-h\t\tthis help\n" "\t-V\t\tprint version\n" " -O FMT\t\toutput format: pax, cpio, tar or rdup\n" "\t\t\trdup uses format: \"%p%T %b %u %g %l %s\\n%n%C\"\n" "\t-L\t\tset input format to a list of pathnames\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" #: entry.c:122 msgid "Type must be one of d, l, h, -, c, b, p or s" msgstr "Type must be one of d, l, h, -, c, b, p or s" #: usage-tr.c:13 #, c-format msgid "USAGE: %s [OPTION]... \n" msgstr "USAGE: %s [OPTION]... \n" #: usage-up.c:13 #, c-format msgid "USAGE: %s [OPTION]... DIRECTORY\n" msgstr "USAGE: %s [OPTION]... DIRECTORY\n" #: usage.c:13 #, c-format msgid "USAGE: %s [OPTION]... FILELIST DIR|FILE...\n" msgstr "USAGE: %s [OPTION]... FILELIST DIR|FILE...\n" #: signal.c:30 msgid "Unhandled signal reveived, exiting" msgstr "Unhandled signal reveived, exiting" #: rdup-tr.c:465 rdup-up.c:152 rdup.c:343 #, c-format msgid "Unknown option seen `%c'" msgstr "Unknown option seen `%c'" #: usage-up.c:14 msgid "" "Update a directory tree with an rdup archive.\n" "The input must be rdup -c output\n" "\n" " DIRECTORY\twhere to unpack the archive\n" "\n" "\n" " OPTIONS:\n" "\t-t\t\tcreate DIRECTORY if is does not exist\n" "\t-s N\t\tstrip N leading path components from each path\n" "\t-n\t\tdry run, do not touch the filesystem\n" "\t-V\t\tprint version\n" "\t-h\t\tthis help\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" "Update a directory tree with an rdup archive.\n" "The input must be rdup -c output\n" "\n" " DIRECTORY\twhere to unpack the archive\n" "\n" "\n" " OPTIONS:\n" "\t-t\t\tcreate DIRECTORY if is does not exist\n" "\t-s N\t\tstrip N leading path components from each path\n" "\t-n\t\tdry run, do not touch the filesystem\n" "\t-V\t\tprint version\n" "\t-h\t\tthis help\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" #: crawler.c:196 msgid "Walking into different filesystem" msgstr "Walking into different filesystem" #: rdup-tr.c:439 msgid "Will not do both encryption and decryption" msgstr "Will not do both encryption and decryption" #: rdup-tr.c:365 rdup-up.c:114 rdup.c:267 msgid "Will not run suid/sgid for safety reasons" msgstr "Will not run suid/sgid for safety reasons" #: rdup-tr.c:473 msgid "Will not write to a tty" msgstr "Will not write to a tty" #: fs-up.c:160 gfunc.c:75 gfunc.c:90 gfunc.c:167 #, c-format msgid "Write failure `%s': %s" msgstr "Write failure `%s': %s" #: rdup-tr.c:176 msgid "Writing to stderr failed" msgstr "Writing to stderr failed" #: protocol.c:93 #, c-format msgid "Wrong protocol version `%c%c': want `%c%c'" msgstr "Wrong protocol version `%c%c': want `%c%c'" rdup-1.1.15/po/nl.po000066400000000000000000000422051303430127500141410ustar00rootroot00000000000000msgid "" msgstr "" "Project-Id-Version: rdup 0.9.1\n" "PO-Revision-Date: 2009-03-05 16:50+0100\n" "Last-Translator: Miek Gieben \n" "Language-Team: Dutch\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: usage.c:32 msgid "" " -c\t\tcat the contents (FORMAT=\"%p%T %b %u %g %l %s\\n%n%C\")\n" " -m\t\tonly print new/modified files (unsets -r)\n" " -n\t\tignore .nobackup files\n" " -r\t\tonly print removed files (unsets -m)\n" " -s SIZE\t\tonly output files smaller then SIZE bytes\n" " -x\t\tstay in local file system\n" " -v\t\tbe more verbose\n" " -h\t\tthis help\n" "\n" " FORMAT:\n" " The following escape sequences are recognized:\n" " '%p': '+' if new, '-' if removed\n" " '%b': permission bits\n" " '%m': file mode bits\n" " '%u': uid\n" " '%g': gid\n" " '%l': path length (for links: length of 'path -> target')\n" " '%s': file size\n" " '%n': path (for links: 'path -> target')\n" " '%N': path (for links: 'path')\n" " '%t': time of modification (epoch)\n" " '%H': the sha1 hash of the file's contents\n" " '%T': 'type' (d, l, h, -, c, b, p or s: dir, symlink, hardlink, " "file, \n" "\t character device, block device, named pipe or socket)\n" " '%C': file contents\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" " -c\t\tcat the contents (FORMAT=\"%p%T %b %u %g %l %s\\n%n%C\")\n" " -m\t\tonly print new/modified files (unsets -r)\n" " -n\t\tignore .nobackup files\n" " -r\t\tonly print removed files (unsets -m)\n" " -s SIZE\t\tonly output files smaller then SIZE bytes\n" " -x\t\tstay in local file system\n" " -v\t\tbe more verbose\n" " -h\t\tthis help\n" "\n" " FORMAT:\n" " The following escape sequences are recognized:\n" " '%p': '+' if new, '-' if removed\n" " '%b': permission bits\n" " '%m': file mode bits\n" " '%u': uid\n" " '%g': gid\n" " '%l': path length (for links: length of 'path -> target')\n" " '%s': file size\n" " '%n': path (for links: 'path -> target')\n" " '%N': path (for links: 'path')\n" " '%t': time of modification (epoch)\n" " '%H': the sha1 hash of the file's contents\n" " '%T': 'type' (d, l, h, -, c, b, p or s: dir, symlink, hardlink, " "file, \n" "\t character device, block device, named pipe or socket)\n" " '%C': file contents\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" #: crawler.c:166 #, c-format msgid "%s found in '%s'" msgstr "%s gevonden in '%s'" #: rdup.c:336 msgid "-s requires a numerical value" msgstr "-s moet een numerieke waarde hebben" #: crypt.c:278 msgid "AES key must be 16, 24 or 32 bytes" msgstr "AES sleutel moet 16, 24 of 32 bytes lang zijn" #: entry.c:205 entry.c:227 #, c-format msgid "Actual pathname length is not equal to pathname length at line: %zd" msgstr "Gerapporteerde padnaam lengte is niet gelijk aan de echte op regel: %zd" #: rdup-tr.c:376 rdup-up.c:123 rdup.c:276 msgid "Argument length overrun" msgstr "Argument te lang" #: protocol.c:109 #, c-format msgid "BLOCK protocol seperator not found: `%c%c%c%c%c'" msgstr "BLOK protocol scheider niet gevonden: `%c%c%c%c%c'" #: protocol.c:135 #, c-format msgid "Block seen, start read of %d bytes" msgstr "Blok gezien, start met lezen van %d bytes" #: protocol.c:131 msgid "Block size larger then BUFSIZE" msgstr "Blok grootte groter dan BUFSIZE" #: rdup-tr.c:450 msgid "Can not do both encryption and decryption" msgstr "Ga niet tegelijk coderen en decoderen" #: crawler.c:109 #, c-format msgid "Cannot determine holding device of the directory `%s': %s" msgstr "Kan niet vast stellen bij welk apparaat de directorie hoort `%s': %s" #: crawler.c:98 #, c-format msgid "Cannot enter directory `%s': %s" msgstr "Kan directorie niet in `%s': %s" #: rdup-tr.c:260 msgid "Child exit, giving you the original file" msgstr "Einde van kind, stuur de originele file" #: entry.c:86 #, c-format msgid "Corrupt entry `%s' in input at line: %zd" msgstr "Entrie corrupt `%s' in input at line: %zd" #: rdup.c:180 #, c-format msgid "" "Corrupt entry in filelist at line: %zd, length `%zd' does not match `%zd'" msgstr "" "Corrupt entry in filelist at line: %zd, length `%zd' does not match `%zd'" #: regexp.c:56 #, c-format msgid "Corrupt regular expression line: %zd, column %d: %s" msgstr "Corrupt regular expression line: %zd, column %d: %s" #: rdup.c:427 #, c-format msgid "Could not create timestamp file `%s': %s" msgstr "Kan geen timestamp bestand creëren `%s': %s" #: rdup-tr.c:370 rdup-up.c:117 rdup.c:270 msgid "Could not get current working directory" msgstr "Kan de huidige werkdirectorie niet verkrijgen" #: gfunc.c:37 gfunc.c:63 rdup-tr.c:241 regexp.c:33 #, c-format msgid "Could not open '%s': %s" msgstr "Kan niet openenen '%s': %s" #: crawler.c:45 crawler.c:131 entry.c:62 entry.c:218 #, c-format msgid "Could not stat path `%s': %s" msgstr "Kan pad niet stat-ten `%s': %s" #: rdup.c:415 #, c-format msgid "Could not write filelist `%s': %s" msgstr "Kan de filelist niet schrijven `%s': %s" #: rdup-up.c:158 msgid "Destination directory is required" msgstr "Doel directorie is nodig" #: link.c:47 #, c-format msgid "Error reading link `%s': %s" msgstr "Error reading link `%s': %s" #: gfunc.c:41 #, c-format msgid "Failed to calculate sha1 digest: `%s'" msgstr "Failed to calculate sha1 digest: `%s'" #: rdup-tr.c:135 msgid "Failed to create archive" msgstr "Failed to create archive" #: fs-up.c:194 fs-up.c:203 rdup-up.c:169 #, c-format msgid "Failed to create directory `%s': %s" msgstr "Failed to create directory `%s': %s" #: fs-up.c:301 fs-up.c:311 #, c-format msgid "Failed to create hardlink `%s -> %s': %s" msgstr "Failed to create hardlink `%s -> %s': %s" #: fs-up.c:36 #, c-format msgid "Failed to make device: `%s': %s" msgstr "Failed to make device: `%s': %s" #: fs-up.c:56 #, c-format msgid "Failed to make socket: `%s': %s" msgstr "Failed to make socket: `%s': %s" #: fs-up.c:86 fs-up.c:95 #, c-format msgid "Failed to make symlink: `%s -> %s': %s" msgstr "Failed to make symlink: `%s -> %s': %s" #: crypt.c:257 #, c-format msgid "Failed to open `%s': %s" msgstr "Failed to open `%s': %s" #: rm.c:37 #, c-format msgid "Failed to open directory `%s': %s" msgstr "Failed to open directory `%s': %s" #: fs-up.c:133 fs-up.c:140 #, c-format msgid "Failed to open file `%s': %s" msgstr "Failed to open file `%s': %s" #: crypt.c:264 #, c-format msgid "Failed to read AES key from `%s': %s" msgstr "Failed to read AES key from `%s': %s" #: rm.c:53 rm.c:78 rm.c:90 rm.c:98 #, c-format msgid "Failed to remove `%s': %s" msgstr "Failed to remove `%s': %s" #: rm.c:65 #, c-format msgid "Failed to remove directory `%s': %s" msgstr "Failed to remove directory `%s': %s" #: fs-up.c:30 fs-up.c:50 fs-up.c:74 fs-up.c:124 #, c-format msgid "Failed to remove existing entry: '%s'" msgstr "Failed to remove existing entry: '%s'" #: rdup-tr.c:156 #, c-format msgid "Failed to set archive type to %s" msgstr "Failed to set archive type to %s" #: entry.c:295 #, c-format msgid "Failed to write to stdout: %s" msgstr "Failed to write to stdout: %s" #: child.c:88 msgid "Failure creating pipes" msgstr "Failure creating pipes" #: rdup-tr.c:302 #, c-format msgid "Failure to read from file: %s" msgstr "Failure to read from file: %s" #: rdup-tr.c:254 #, c-format msgid "Failure to read from pipe: %s" msgstr "Failure to read from pipe: %s" #: rdup-tr.c:297 #, c-format msgid "Failure to rewind: %s" msgstr "Failure to rewind: %s" #: entry.c:98 #, c-format msgid "First character should '-' or '+', `%s' at line: %zd" msgstr "First character should '-' or '+', `%s' at line: %zd" #: child.c:104 msgid "Fork error" msgstr "Fork error" #: usage.c:14 msgid "" "Generate a full or incremental file list. This list can be used to\n" "implement a (incremental) backup scheme.\n" "\n" "\tFILELIST\tfile to store filenames\n" " DIR\t\tdirectory or directories to dump\n" "\n" "\n" " OPTIONS:\n" " -N FILE\t\tuse the (c_time) timestamp of FILE for incremental dumps\n" " \t\tif FILE does not exist, a full dump is performed\n" "\t-M FILE\t\tas -N, but use the m_time\n" " -F FORMAT\tuse specified format string\n" " \t\tdefaults to: \"%p%T %b %u %g %l %s %n\\n\"\n" "\t-R\t\treverse the output (depth first, first the dirs then the files)\n" "\t-E FILE\t\tuse FILE as an exclude list\n" " -0\t\tdelimit internal filelist with NULLs\n" " -V\t\tprint version\n" msgstr "" "Generate a full or incremental file list. This list can be used to\n" "implement a (incremental) backup scheme.\n" "\n" "\tFILELIST\tfile to store filenames\n" " DIR\t\tdirectory or directories to dump\n" "\n" "\n" " OPTIONS:\n" " -N FILE\t\tuse the (c_time) timestamp of FILE for incremental dumps\n" " \t\tif FILE does not exist, a full dump is performed\n" "\t-M FILE\t\tas -N, but use the m_time\n" " -F FORMAT\tuse specified format string\n" " \t\tdefaults to: \"%p%T %b %u %g %l %s %n\\n\"\n" "\t-R\t\treverse the output (depth first, first the dirs then the files)\n" "\t-E FILE\t\tuse FILE as an exclude list\n" " -0\t\tdelimit internal filelist with NULLs\n" " -V\t\tprint version\n" #: protocol.c:123 msgid "Illegal block size" msgstr "Illegal block size" #: gfunc.c:394 msgid "Internal error: NO_PRINT in remove tree!" msgstr "Internal error: NO_PRINT in remove tree!" #: rdup-tr.c:432 #, c-format msgid "Invalid output format: `%s'" msgstr "Invalid output format: `%s'" #: entry.c:129 #, c-format msgid "Invalid permissions at line: %zd" msgstr "Invalid permissions at line: %zd" #: getdelim.c:30 #, c-format msgid "Line longer than %d characters" msgstr "Line longer than %d characters" #: rdup-tr.c:351 msgid "Locale could not be set" msgstr "Locale could not be set" #: entry.c:191 #, c-format msgid "Malformed input for file size at line: %zd" msgstr "Malformed input for file size at line: %zd" #: entry.c:148 #, c-format msgid "Malformed input for gid at line: %zd" msgstr "Malformed input for gid at line: %zd" #: entry.c:159 #, c-format msgid "Malformed input for path length at line: %zd" msgstr "Malformed input for path length at line: %zd" #: entry.c:137 #, c-format msgid "Malformed input for uid at line: %zd" msgstr "Malformed input for uid at line: %zd" #: crypt.c:273 msgid "Maximum AES key size is 32 bytes, truncating!" msgstr "Maximum AES key size is 32 bytes, truncating!" #: crawler.c:228 #, c-format msgid "Neither file nor directory `%s'" msgstr "Neither file nor directory `%s'" #: crawler.c:137 #, c-format msgid "Newline (\\n) found in path `%s', skipping" msgstr "Newline (\\n) found in path `%s', skipping" #: xattr.c:88 xattr.c:100 #, c-format msgid "No gid xattr for `%s'" msgstr "Geen gid xattr voor `%s'" #: rdup-up.c:174 #, c-format msgid "No such directory: `%s'" msgstr "Directory bestaat niet: `%s'" #: xattr.c:36 xattr.c:48 #, c-format msgid "No uid xattr for `%s'" msgstr "Geen uid xattr voor `%s'" #: rdup-up.c:144 msgid "Not implemented (yet)" msgstr "(Nog) niet geimplementeerd" #: rdup-tr.c:406 #, c-format msgid "Only %d extra args per child allowed" msgstr "Maar %d extra argumenten per kind toegestaan" #: rdup-up.c:65 #, c-format msgid "Pathname does not start with /: `%s'" msgstr "Padnaam begint niet met een /: `%s'" #: entry.c:107 msgid "Removing files is not supported for any output except rdup" msgstr "Verwijderen van bestanden is alleen mogelijk bij rdup uitvoer" #: rdup-up.c:59 #, c-format msgid "Reported name size (%zd) does not match actual name size (%zd)" msgstr "Gerapporteerde naam lengte (%zd) komt niet overeen met de echte (%zd)" #: crypt.c:147 #, c-format msgid "Returning original string `%s'" msgstr "Geef de originele string terug `%s'" #: signal.c:27 msgid "SIGINT received, exiting" msgstr "SIGINT ontvangen, dag" #: signal.c:24 msgid "SIGPIPE received, exiting" msgstr "SIGPIPE ontvangen, dag" #: rdup.c:370 rdup.c:376 #, c-format msgid "Skipping `%s'" msgstr "Sla over `%s'" #: xattr.c:59 xattr.c:81 xattr.c:111 #, c-format msgid "Too large gid `%zd' for `%s', truncating" msgstr "Te grote gid `%zd' voor `%s', truncating" #: xattr.c:29 #, c-format msgid "Too large uid `%zd' for `%s', truncating" msgstr "Te grote gid `%zd' voor `%s', truncating" #: usage-tr.c:14 msgid "" "Translate rdup output to something else\tand optionally filter it\n" "through other processes. The input must be rdup's default ouput\n" "format: '%p%T %b %u %g %l %s %n\\n'.\n" "The output is equal to rdup -c ouput.\n" "\n" "\n" " OPTIONS:\n" " -c\t\tforce output to tty\n" " -P CMD\n" "\t \t\tfilter file contents through CMD, will be called with 'sh -c CMD'\n" "\t\t\tthis may be repeated, output will be filtered\n" "\t\t\tthrough all commands\n" "\t-X FILE\t\tencrypt all paths with AES and the key from FILE\n" "\t-Y FILE\t\tdecrypt all paths with AES and the key from FILE\n" "\t-h\t\tthis help\n" "\t-V\t\tprint version\n" " -O FMT\t\toutput format: pax, cpio, tar or rdup\n" "\t\t\trdup uses format: \"%p%T %b %u %g %l %s\\n%n%C\"\n" "\t-L\t\tset input format to a list of pathnames\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" "Translate rdup output to something else\tand optionally filter it\n" "through other processes. The input must be rdup's default ouput\n" "format: '%p%T %b %u %g %l %s %n\\n'.\n" "The output is equal to rdup -c ouput.\n" "\n" "\n" " OPTIONS:\n" " -c\t\tforce output to tty\n" " -P CMD\n" "\t \t\tfilter file contents through CMD, will be called with 'sh -c CMD'\n" "\t\t\tthis may be repeated, output will be filtered\n" "\t\t\tthrough all commands\n" "\t-X FILE\t\tencrypt all paths with AES and the key from FILE\n" "\t-Y FILE\t\tdecrypt all paths with AES and the key from FILE\n" "\t-h\t\tthis help\n" "\t-V\t\tprint version\n" " -O FMT\t\toutput format: pax, cpio, tar or rdup\n" "\t\t\trdup uses format: \"%p%T %b %u %g %l %s\\n%n%C\"\n" "\t-L\t\tset input format to a list of pathnames\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" #: entry.c:122 msgid "Type must be one of d, l, h, -, c, b, p or s" msgstr "Type must be one of d, l, h, -, c, b, p or s" #: usage-tr.c:13 #, c-format msgid "GEBRUIK: %s [OPTION]... \n" msgstr "GEBRUIK: %s [OPTION]... \n" #: usage-up.c:13 #, c-format msgid "GEBRUIK: %s [OPTION]... DIRECTORY\n" msgstr "GEBRUIK: %s [OPTION]... DIRECTORY\n" #: usage.c:13 #, c-format msgid "GEBRUIK: %s [OPTION]... FILELIST DIR|FILE...\n" msgstr "GEBRUIK: %s [OPTION]... FILELIST DIR|FILE...\n" #: signal.c:30 msgid "Unhandled signal reveived, exiting" msgstr "Unhandled signal reveived, exiting" #: rdup-tr.c:465 rdup-up.c:150 rdup.c:341 #, c-format msgid "Unknown option seen `%c'" msgstr "Onbekende optie gezien `%c'" #: usage-up.c:14 msgid "" "Update a directory tree with an rdup archive.\n" "The input must be rdup -c output\n" "\n" " DIRECTORY\twhere to unpack the archive\n" "\n" "\n" " OPTIONS:\n" "\t-t\t\tcreate DIRECTORY if is does not exist\n" "\t-s N\t\tstrip N leading path components from each path\n" "\t-n\t\tdry run, do not touch the filesystem\n" "\t-V\t\tprint version\n" "\t-h\t\tthis help\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" "Update a directory tree with an rdup archive.\n" "The input must be rdup -c output\n" "\n" " DIRECTORY\twhere to unpack the archive\n" "\n" "\n" " OPTIONS:\n" "\t-t\t\tcreate DIRECTORY if is does not exist\n" "\t-s N\t\tstrip N leading path components from each path\n" "\t-n\t\tdry run, do not touch the filesystem\n" "\t-V\t\tprint version\n" "\t-h\t\tthis help\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" #: crawler.c:196 msgid "Walking into different filesystem" msgstr "Walking into different filesystem" #: rdup-tr.c:439 msgid "Will not do both encryption and decryption" msgstr "Will not do both encryption and decryption" #: rdup-tr.c:365 rdup-up.c:112 rdup.c:265 msgid "Will not run suid/sgid for safety reasons" msgstr "Will not run suid/sgid for safety reasons" #: rdup-tr.c:473 msgid "Will not write to a tty" msgstr "Zal niet naar het scherm schrijven" #: fs-up.c:160 gfunc.c:75 gfunc.c:90 gfunc.c:167 #, c-format msgid "Write failure `%s': %s" msgstr "Write failure `%s': %s" #: rdup-tr.c:176 msgid "Writing to stderr failed" msgstr "Writing to stderr failed" #: protocol.c:93 #, c-format msgid "Wrong protocol version `%c%c': want `%c%c'" msgstr "Wrong protocol version `%c%c': want `%c%c'" rdup-1.1.15/po/rdup.pot000066400000000000000000000247001303430127500146660ustar00rootroot00000000000000#: usage.c:32 msgid "" " -c\t\tcat the contents (FORMAT=\"%p%T %b %u %g %l %s\\n%n%C\")\n" " -m\t\tonly print new/modified files (unsets -r)\n" " -n\t\tignore .nobackup files\n" " -r\t\tonly print removed files (unsets -m)\n" " -s SIZE\t\tonly output files smaller then SIZE bytes\n" " -x\t\tstay in local file system\n" " -v\t\tbe more verbose\n" " -h\t\tthis help\n" "\n" " FORMAT:\n" " The following escape sequences are recognized:\n" " '%p': '+' if new, '-' if removed\n" " '%b': permission bits\n" " '%m': file mode bits\n" " '%u': uid\n" " '%g': gid\n" " '%l': path length (for links: length of 'path -> target')\n" " '%s': file size\n" " '%n': path (for links: 'path -> target')\n" " '%N': path (for links: 'path')\n" " '%t': time of modification (epoch)\n" " '%H': the sha1 hash of the file's contents\n" " '%T': 'type' (d, l, h, -, c, b, p or s: dir, symlink, hardlink, " "file, \n" "\t character device, block device, named pipe or socket)\n" " '%C': file contents\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" #: crawler.c:166 #, c-format msgid "%s found in '%s'" msgstr "" #: rdup.c:338 msgid "-s requires a numerical value" msgstr "" #: crypt.c:278 msgid "AES key must be 16, 24 or 32 bytes" msgstr "" #: entry.c:205 entry.c:227 #, c-format msgid "Actual pathname length is not equal to pathname length at line: %zd" msgstr "" #: rdup-tr.c:376 rdup-up.c:125 rdup.c:278 msgid "Argument length overrun" msgstr "" #: protocol.c:109 #, c-format msgid "BLOCK protocol seperator not found: `%c%c%c%c%c'" msgstr "" #: protocol.c:135 #, c-format msgid "Block seen, start read of %d bytes" msgstr "" #: protocol.c:131 msgid "Block size larger then BUFSIZE" msgstr "" #: rdup-tr.c:450 msgid "Can not do both encryption and decryption" msgstr "" #: crawler.c:109 #, c-format msgid "Cannot determine holding device of the directory `%s': %s" msgstr "" #: crawler.c:98 #, c-format msgid "Cannot enter directory `%s': %s" msgstr "" #: rdup-tr.c:260 msgid "Child exit, giving you the original file" msgstr "" #: entry.c:86 #, c-format msgid "Corrupt entry `%s' in input at line: %zd" msgstr "" #: rdup.c:180 #, c-format msgid "" "Corrupt entry in filelist at line: %zd, length `%zd' does not match `%zd'" msgstr "" #: regexp.c:56 #, c-format msgid "Corrupt regular expression line: %zd, column %d: %s" msgstr "" #: rdup.c:429 #, c-format msgid "Could not create timestamp file `%s': %s" msgstr "" #: rdup-tr.c:370 rdup-up.c:119 rdup.c:272 msgid "Could not get current working directory" msgstr "" #: gfunc.c:37 gfunc.c:63 rdup-tr.c:241 regexp.c:33 #, c-format msgid "Could not open '%s': %s" msgstr "" #: crawler.c:45 crawler.c:131 entry.c:62 entry.c:218 #, c-format msgid "Could not stat path `%s': %s" msgstr "" #: rdup.c:417 #, c-format msgid "Could not write filelist `%s': %s" msgstr "" #: rdup-up.c:160 msgid "Destination directory is required" msgstr "" #: link.c:47 #, c-format msgid "Error reading link `%s': %s" msgstr "" #: gfunc.c:41 #, c-format msgid "Failed to calculate sha1 digest: `%s'" msgstr "" #: rdup-tr.c:135 msgid "Failed to create archive" msgstr "" #: fs-up.c:194 fs-up.c:203 rdup-up.c:171 #, c-format msgid "Failed to create directory `%s': %s" msgstr "" #: fs-up.c:301 fs-up.c:311 #, c-format msgid "Failed to create hardlink `%s -> %s': %s" msgstr "" #: fs-up.c:36 #, c-format msgid "Failed to make device: `%s': %s" msgstr "" #: fs-up.c:56 #, c-format msgid "Failed to make socket: `%s': %s" msgstr "" #: fs-up.c:86 fs-up.c:95 #, c-format msgid "Failed to make symlink: `%s -> %s': %s" msgstr "" #: crypt.c:257 #, c-format msgid "Failed to open `%s': %s" msgstr "" #: rm.c:37 #, c-format msgid "Failed to open directory `%s': %s" msgstr "" #: fs-up.c:133 fs-up.c:140 #, c-format msgid "Failed to open file `%s': %s" msgstr "" #: crypt.c:264 #, c-format msgid "Failed to read AES key from `%s': %s" msgstr "" #: rm.c:53 rm.c:78 rm.c:90 rm.c:98 #, c-format msgid "Failed to remove `%s': %s" msgstr "" #: rm.c:65 #, c-format msgid "Failed to remove directory `%s': %s" msgstr "" #: fs-up.c:30 fs-up.c:50 fs-up.c:74 fs-up.c:124 #, c-format msgid "Failed to remove existing entry: '%s'" msgstr "" #: rdup-tr.c:156 #, c-format msgid "Failed to set archive type to %s" msgstr "" #: entry.c:295 #, c-format msgid "Failed to write to stdout: %s" msgstr "" #: child.c:88 msgid "Failure creating pipes" msgstr "" #: rdup-tr.c:302 #, c-format msgid "Failure to read from file: %s" msgstr "" #: rdup-tr.c:254 #, c-format msgid "Failure to read from pipe: %s" msgstr "" #: rdup-tr.c:297 #, c-format msgid "Failure to rewind: %s" msgstr "" #: entry.c:98 #, c-format msgid "First character should '-' or '+', `%s' at line: %zd" msgstr "" #: child.c:104 msgid "Fork error" msgstr "" #: usage.c:14 msgid "" "Generate a full or incremental file list. This list can be used to\n" "implement a (incremental) backup scheme.\n" "\n" "\tFILELIST\tfile to store filenames\n" " DIR\t\tdirectory or directories to dump\n" "\n" "\n" " OPTIONS:\n" " -N FILE\t\tuse the (c_time) timestamp of FILE for incremental dumps\n" " \t\tif FILE does not exist, a full dump is performed\n" "\t-M FILE\t\tas -N, but use the m_time\n" " -F FORMAT\tuse specified format string\n" " \t\tdefaults to: \"%p%T %b %u %g %l %s %n\\n\"\n" "\t-R\t\treverse the output (depth first, first the dirs then the files)\n" "\t-E FILE\t\tuse FILE as an exclude list\n" " -0\t\tdelimit internal filelist with NULLs\n" " -V\t\tprint version\n" msgstr "" #: protocol.c:123 msgid "Illegal block size" msgstr "" #: gfunc.c:394 msgid "Internal error: NO_PRINT in remove tree!" msgstr "" #: rdup-tr.c:432 #, c-format msgid "Invalid output format: `%s'" msgstr "" #: entry.c:129 #, c-format msgid "Invalid permissions at line: %zd" msgstr "" #: getdelim.c:30 #, c-format msgid "Line longer than %d characters" msgstr "" #: rdup-tr.c:351 rdup-up.c:99 rdup.c:246 msgid "Locale could not be set" msgstr "" #: entry.c:191 #, c-format msgid "Malformed input for file size at line: %zd" msgstr "" #: entry.c:148 #, c-format msgid "Malformed input for gid at line: %zd" msgstr "" #: entry.c:159 #, c-format msgid "Malformed input for path length at line: %zd" msgstr "" #: entry.c:137 #, c-format msgid "Malformed input for uid at line: %zd" msgstr "" #: crypt.c:273 msgid "Maximum AES key size is 32 bytes, truncating!" msgstr "" #: crawler.c:228 #, c-format msgid "Neither file nor directory `%s'" msgstr "" #: crawler.c:137 #, c-format msgid "Newline (\\n) found in path `%s', skipping" msgstr "" #: xattr.c:88 xattr.c:100 #, c-format msgid "No gid xattr for `%s'" msgstr "" #: rdup-up.c:176 #, c-format msgid "No such directory: `%s'" msgstr "" #: xattr.c:36 xattr.c:48 #, c-format msgid "No uid xattr for `%s'" msgstr "" #: rdup-up.c:146 msgid "Not implemented (yet)" msgstr "" #: rdup-tr.c:406 #, c-format msgid "Only %d extra args per child allowed" msgstr "" #: rdup-up.c:65 #, c-format msgid "Pathname does not start with /: `%s'" msgstr "" #: entry.c:107 msgid "Removing files is not supported for any output except rdup" msgstr "" #: rdup-up.c:59 #, c-format msgid "Reported name size (%zd) does not match actual name size (%zd)" msgstr "" #: crypt.c:147 #, c-format msgid "Returning original string `%s'" msgstr "" #: signal.c:27 msgid "SIGINT received, exiting" msgstr "" #: signal.c:24 msgid "SIGPIPE received, exiting" msgstr "" #: rdup.c:372 rdup.c:378 #, c-format msgid "Skipping `%s'" msgstr "" #: xattr.c:59 xattr.c:81 xattr.c:111 #, c-format msgid "Too large gid `%zd' for `%s', truncating" msgstr "" #: xattr.c:29 #, c-format msgid "Too large uid `%zd' for `%s', truncating" msgstr "" #: usage-tr.c:14 msgid "" "Translate rdup output to something else\tand optionally filter it\n" "through other processes. The input must be rdup's default ouput\n" "format: '%p%T %b %u %g %l %s %n\\n'.\n" "The output is equal to rdup -c ouput.\n" "\n" "\n" " OPTIONS:\n" " -c\t\tforce output to tty\n" " -P CMD\n" "\t \t\tfilter file contents through CMD, will be called with 'sh -c CMD'\n" "\t\t\tthis may be repeated, output will be filtered\n" "\t\t\tthrough all commands\n" "\t-X FILE\t\tencrypt all paths with AES and the key from FILE\n" "\t-Y FILE\t\tdecrypt all paths with AES and the key from FILE\n" "\t-h\t\tthis help\n" "\t-V\t\tprint version\n" " -O FMT\t\toutput format: pax, cpio, tar or rdup\n" "\t\t\trdup uses format: \"%p%T %b %u %g %l %s\\n%n%C\"\n" "\t-L\t\tset input format to a list of pathnames\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" #: entry.c:122 msgid "Type must be one of d, l, h, -, c, b, p or s" msgstr "" #: usage-tr.c:13 #, c-format msgid "USAGE: %s [OPTION]... \n" msgstr "" #: usage-up.c:13 #, c-format msgid "USAGE: %s [OPTION]... DIRECTORY\n" msgstr "" #: usage.c:13 #, c-format msgid "USAGE: %s [OPTION]... FILELIST DIR|FILE...\n" msgstr "" #: signal.c:30 msgid "Unhandled signal reveived, exiting" msgstr "" #: rdup-tr.c:465 rdup-up.c:152 rdup.c:343 #, c-format msgid "Unknown option seen `%c'" msgstr "" #: usage-up.c:14 msgid "" "Update a directory tree with an rdup archive.\n" "The input must be rdup -c output\n" "\n" " DIRECTORY\twhere to unpack the archive\n" "\n" "\n" " OPTIONS:\n" "\t-t\t\tcreate DIRECTORY if is does not exist\n" "\t-s N\t\tstrip N leading path components from each path\n" "\t-n\t\tdry run, do not touch the filesystem\n" "\t-V\t\tprint version\n" "\t-h\t\tthis help\n" "\t-v\t\tbe more verbose and print processed files to stderr\n" "\n" "Report bugs to \n" "Licensed under the GPL version 3.\n" "See the file LICENSE in the source distribution of rdup.\n" msgstr "" #: crawler.c:196 msgid "Walking into different filesystem" msgstr "" #: rdup-tr.c:439 msgid "Will not do both encryption and decryption" msgstr "" #: rdup-tr.c:365 rdup-up.c:114 rdup.c:267 msgid "Will not run suid/sgid for safety reasons" msgstr "" #: rdup-tr.c:473 msgid "Will not write to a tty" msgstr "" #: fs-up.c:160 gfunc.c:75 gfunc.c:90 gfunc.c:167 #, c-format msgid "Write failure `%s': %s" msgstr "" #: rdup-tr.c:176 msgid "Writing to stderr failed" msgstr "" #: protocol.c:93 #, c-format msgid "Wrong protocol version `%c%c': want `%c%c'" msgstr "" rdup-1.1.15/protocol.c000066400000000000000000000073621303430127500145640ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * * A simple protocol for rdup, if you even want * to call it a protocol * * When rdup output file contents it will do this in blocks. * * This removes the filesize race conditions * and makes everything else somewhat simpler * * block header is VERSION BLOCK BLOCKSIZE as in * 01BLOCK08192 * So a small 4 byte file becomes: * * 01BLOCK00004 * <4 bytes of the file>01BLOCK00000 * * A stop block is a block with length zero 01BLOCK00000, this * comes after each file. */ #include #include #include #include #include #include #include "common.h" #include "protocol.h" extern gint opt_verbose; extern int sig; /* signal.c */ void got_sig(int); void signal_abort(int); /** * output a block header */ gint block_out_header(FILE * f, size_t size, int fp) { char *p; p = g_strdup_printf("%c%c%s%05d\n", PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR, PROTO_BLOCK, (int)size); if (sig != 0) signal_abort(sig); if (f) { if (fwrite(p, sizeof(char), strlen(p), f) != strlen(p)) return -1; } else if (fp != -1) { if (write(fp, p, strlen(p)) == -1) return -1; } g_free(p); return 0; } /** * output a block */ gint block_out(FILE * f, size_t size, char *buf, int fp) { if (sig != 0) signal_abort(sig); if (f) { if (fwrite(buf, sizeof(char), size, f) != size) return -1; } else if (fp != -1) { if (write(fp, buf, size) == -1) return -1; } return 0; } /** * read a block from f */ gint block_in(FILE * f, size_t size, char *buf) { if (sig != 0) signal_abort(sig); if (fread(buf, sizeof(char), size, f) != size) { /* read less then expected */ return -1; } return 0; } /** * parse a block header: 01BLOCK08192 * return the number of bytes to read * 00000 signals the end (no more bytes to read * -1 for parse errors */ size_t block_in_header(FILE * f) { /* we are expecting a block header: * 2 pos version; the word block; 5 digit number; newline */ char c[6]; int bytes; gchar *out; /* I cannot think of anything smarter */ /* version check */ c[0] = fgetc(f); if (sig != 0) signal_abort(sig); c[1] = fgetc(f); if (sig != 0) signal_abort(sig); if (c[0] != PROTO_VERSION_MAJOR || c[1] != PROTO_VERSION_MINOR) { msg(_("Wrong protocol version `%c%c\': want `%c%c'"), c[0], c[1], PROTO_VERSION_MAJOR, PROTO_VERSION_MINOR); return -1; } /* 'block' */ c[0] = fgetc(f); /* B */ if (sig != 0) signal_abort(sig); c[1] = fgetc(f); /* L */ if (sig != 0) signal_abort(sig); c[2] = fgetc(f); /* O */ if (sig != 0) signal_abort(sig); c[3] = fgetc(f); /* C */ if (sig != 0) signal_abort(sig); c[4] = fgetc(f); /* K */ if (sig != 0) signal_abort(sig); if (c[0] != 'B' || c[1] != 'L' || c[2] != 'O' || c[3] != 'C' || c[4] != 'K') { msg(_("BLOCK protocol seperator not found: `%c%c%c%c%c\'"), c[0], c[1], c[2], c[3], c[4]); return -1; } /* the bytes */ c[0] = fgetc(f); if (sig != 0) signal_abort(sig); c[1] = fgetc(f); if (sig != 0) signal_abort(sig); c[2] = fgetc(f); if (sig != 0) signal_abort(sig); c[3] = fgetc(f); if (sig != 0) signal_abort(sig); c[4] = fgetc(f); if (sig != 0) signal_abort(sig); c[5] = fgetc(f); /* \n */ if (sig != 0) signal_abort(sig); if (!isdigit(c[0]) || !isdigit(c[1]) || !isdigit(c[2]) || !isdigit(c[3]) || !isdigit(c[4])) { msg(_("Illegal block size")); return -1; } out = g_strdup_printf("%c%c%c%c%c", c[0], c[1], c[2], c[3], c[4]); bytes = atoi(out); g_free(out); if (bytes > BUFSIZE) { /* out of bounds...? */ msg(_("Block size larger then BUFSIZE")); return -1; } if (opt_verbose > 2) msg(_("Block seen, start read of %d bytes"), bytes); return bytes; } rdup-1.1.15/protocol.h000066400000000000000000000012201303430127500145540ustar00rootroot00000000000000#ifndef _PROTOCOL_H #define _PROTOCOL_H #define PROTO_BLOCK "BLOCK" #define PROTO_VERSION_MAJOR '0' #define PROTO_VERSION_MINOR '1' #include #include #include "config.h" #ifdef HAVE_GETTEXT #include #include #define _(String) gettext (String) #define gettext_noop(String) String #define N_(String) gettext_noop (String) #else #define _(String) String #endif /* HAVE_GETTEXT */ /* protocol.c */ gint block_out_header(FILE *, size_t, int); gint block_out(FILE *, size_t, char *, int); size_t block_in_header(FILE *); gint block_in(FILE *, size_t, char *); void msg(const char *, ...); #endif /* _PROTOCOL_H */ rdup-1.1.15/rdup-simple000077500000000000000000000146331303430127500147450ustar00rootroot00000000000000#!/bin/bash # updates a hardlinked backup # licensed under the GPL version 3 # Copyright Miek Gieben, 2007 - 2010 # rewritten for rdup-up and rdup-tr echo2() { echo "** $(basename $PROGNAME): $@" >&2 } version() { rdup -V } copy_and_link() { # hardlink a previous backup directory to a new directory # SYNOPSIS: copy_and_link N BACKUPDIR # N: look back N days # BACKUPDIR: top directory of the backups # By default a new directory BACKUPDIR/YYYYMM/DD wil be created # 3 return codes # 0: BACKUPDIR/YYYYMM/DD is created (now make a inc dump) # 1: BACKUPDIR/YYYYMM/DD is created (now make a full dump) # 2: an error occured LOOKBACK=$1; shift DATESTR='+%Y%m/%d' TODAY=$(date $DATESTR) TOPDIR="$1" if $dry; then exit 1; fi [ -z "$TOPDIR" ] && exit 2 [ -d $TOPDIR/$TODAY ] && exit 0 if ! mkdir -p $TOPDIR/$TODAY; then exit 2 fi let i=1 while [ $i -le $LOOKBACK ]; do D=$(date $DATESTR --date "$i days ago") if [ -d $TOPDIR/$D ]; then if ! cp -plr $TOPDIR/$D/* $TOPDIR/$TODAY; then exit 2 fi exit 0 fi let i=i+1 done exit 1 } usage() { cat << HELP $PROGNAME [+N] DIR [DIR ...] DEST This is a wrapper around rdup, rdup-tr and rdup-up DIR - directories to back up +N - Look N days back for previous backups, defaults to 8 DEST - where to store the backup. This can be: ssh://user@host/directory (note: no colon after the hostname) ssh://host/directory file:///directory (note: 3 slashes) /directory directory OPTIONS: -k KEYFILE encrypt all files: rdup -P "mcrypt -f KEYFILE" -g encrypt all files: rdup -P "gpg --default-recipient-self --encrypt" -z compress all files: rdup -P gzip -E FILE use FILE as an exclude list -f force a full dump -v echo the files processed to stderr and be more verbose -n dry run; show the actually rdup command and pass -n to rdup -a reset atime -x pass -x to rdup -q pass -q to rdup-up -s NUM pass -s NUM to rdup-up (strip NUM leading path components) -X FILE encrypt all paths with AES and key in FILE -Y FILE decrypt all paths with AES and key in FILE -h this help -V print version HELP } PROGNAME=$0 NOW=$(date +%Y%m/%d) DAYS=8 OPT_DRY= ssh= trans= pathtrans= atime= enc=false etc=~/.rdup force=false verbose=false link=false dry=false mcrypt=false while getopts "aE:k:vfgzxhVX:Y:s:Lnq" o; do case $o in a) atime=" -a " ;; E) if [ -z "$OPTARG" ]; then echo2 "-E needs an argument" exit 1 fi E=" -E $OPTARG " ;; Y|X) # check for rdup-tr pathtrans="-$o $OPTARG"; ;; k) if [ -z "$OPTARG" ]; then echo2 "-k needs an argument" exit 1 fi if [ ! -r "$OPTARG" ]; then echo2 "Cannot read keyfile \`$OPTARG': failed" exit 1 fi trans="$trans -P 'mcrypt -q -f $OPTARG'" if $enc; then echo2 "Encryption already set" exit 1 fi enc=true mcrypt=true ;; z) trans="$trans -P gzip" if $enc; then echo2 "Select compression first, then encryption" exit 1 fi ;; g) trans="$trans -P 'gpg -e --default-recipient-self'" if $enc; then echo2 "Encryption already set" exit 1 fi # if there a no key, this will fail if [ $(gpg --list-keys | wc -l) -eq "0" ]; then echo2 "No gpg keys found" exit 1 fi enc=true ;; f) force=true;; q) OPT_QUIET=" -q ";; s) STRIP="-s $OPTARG";; v) OPT=" $OPT -v "; verbose=true;; n) dry=true; OPT_DRY=" -n ";; x) x=" -x ";; L) link=true;; h) usage && exit;; V) version && exit;; \?) echo2 "Invalid option seen"; exit 1;; esac done shift $((OPTIND - 1)) if [ "${1:0:1}" = "+" ]; then DAYS=${1:1} if [ $DAYS -lt 1 ] || [ $DAYS -gt 99 ]; then echo2 "+N needs to be a number [1..99]" exit 1 fi shift else DAYS=8 fi [ $# -lt 2 ] && usage && exit if $mcrypt; then if ! which mcrypt 2>/dev/null 1>&2; then echo2 "Mcrypt not found, can not continue" exit 1 fi fi i=1; last=$#; DIRS= while [ $i -lt $last ]; do DIRS="$DIRS $1" shift ((i=$i+1)) done # rdup [options] source destination #dest="ssh://elektron.atoom.net/directory" #dest="ssh://elektron.atoom.net/directory/var/" #dest="file:///var/backup" #dest="/var/backup" #dest="ssh://miekg@elektron.atoom.net/directory" dest=$1 if [ ${dest:0:6} = "ssh://" ]; then rest=${dest/ssh:\/\//} u=${rest%%@*} if [ "$u" = "$rest" ]; then # no @ used, nullify $u u= fi rest=${rest/$u@/} h=$(echo $rest | cut -s -f1 -d/) BACKUPDIR=${rest/$h/} if [ -z "$u" ]; then ssh=" ssh -x $h" else ssh=" ssh -x $u@$h" fi fi if [ ${dest:0:7} = "file://" ]; then rest=${dest/file:\/\//} BACKUPDIR=$rest fi [ ${dest:0:1} = "/" ] && BACKUPDIR=$dest # no hits above, assume relative filename [ -z "$BACKUPDIR" ] && BACKUPDIR=$PWD/$dest $link && copy_and_link $DAYS $BACKUPDIR # change all / to _ to make a valid filename STAMP=$etc/timestamp.${HOSTNAME}.${dest//\//_} LIST=$etc/list.${HOSTNAME}.${dest//\//_} [ ! -d $etc ] && mkdir $etc # remote or not if [ -z "$ssh" ]; then pipe="rdup-up$OPT $OPT_QUIET $OPT_DRY $STRIP -t $BACKUPDIR/$NOW" else pipe="$ssh rdup-up$OPT $OPT_QUIET $OPT_DRY $STRIP -t $BACKUPDIR/$NOW" fi # path encryption if [ -n "$pathtrans" ]; then pipe="rdup-tr $pathtrans | $pipe" fi cmd="rdup$E$x$atime -N $STAMP $trans $LIST $DIRS | $pipe" if ! $force; then # path is set at the top if [ -z "$ssh" ]; then $PROGNAME $OPT_DRY -L +$DAYS /dev/null $BACKUPDIR purpose=$? else # You need to set your path so rdup-simple can be found $ssh "rdup-simple $OPT_DRY -L +$DAYS /dev/null $BACKUPDIR" purpose=$? fi else purpose=1 fi case $purpose in 0) $verbose && echo "INCREMENTAL DUMP" ;; 1) $verbose && echo "FULL DUMP" rm -f $LIST rm -f $STAMP ;; *) echo2 "Illegal return code from rdup-simple -L" exit 1 ;; esac # execute the backup command if $dry; then echo "${cmd}" fi eval ${cmd} rdup-1.1.15/rdup-tr.c000066400000000000000000000307711303430127500143200ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * rdup-tr -- rdup translate, transform an * rdup filelist to an tar/cpio archive with * per file compression and/or encryption or whatever */ /* stdio is only used for errors * the rest is all read, write and pipe */ #include "rdup-tr.h" #include "protocol.h" #include "io.h" char *PROGNAME = "rdup-tr"; /* options */ char *template; gboolean opt_tty = FALSE; /* force write to tty */ #ifdef HAVE_LIBNETTLE gchar *opt_crypt_key = NULL; /* encryption key */ gchar *opt_decrypt_key = NULL; /* decryption key */ struct aes_ctx *aes_ctx = NULL; #endif /* HAVE_LIBNETTLE */ gint opt_verbose = 0; /* be more verbose */ gint opt_output = O_RDUP; /* default output */ gint opt_input = I_RDUP; /* default intput */ int sig = 0; char *o_fmt[] = { "", "tar", "cpio", "pax", "rdup" }; /* O_NONE, O_TAR, O_CPIO, O_PAX, O_RDUP */ extern int opterr; int opterr = 0; /* common.c */ struct rdup *entry_dup(struct rdup *f); void entry_free(struct rdup *f); #ifdef HAVE_LIBNETTLE /* encrypt an rdup_entry (just the path of course) */ static struct rdup *crypt_entry(struct rdup *e, GHashTable * tr) { gchar *crypt, *dest; if (!(crypt = crypt_path(aes_ctx, e->f_name, tr))) { msg(_("Failed to encrypt path `%s\'"), e->f_name); return NULL; } e->f_name = crypt; e->f_name_size = strlen(crypt); /* links are special */ if (S_ISLNK(e->f_mode) || e->f_lnk == 1) { dest = crypt_path(aes_ctx, e->f_target, tr); e->f_target = dest; e->f_size = strlen(crypt); /* use crypt here */ } return e; } /* decrypt an rdup_entry */ static struct rdup *decrypt_entry(struct rdup *e, GHashTable * tr) { gchar *plain, *dest; if (!(plain = decrypt_path(aes_ctx, e->f_name, tr))) { msg(_("Failed to decrypt path `%s\'"), e->f_name); return NULL; } e->f_name = plain; e->f_name_size = strlen(plain); /* links are special */ if (S_ISLNK(e->f_mode) || e->f_lnk == 1) { dest = decrypt_path(aes_ctx, e->f_target, tr); g_free(e->f_target); e->f_target = dest; e->f_size = strlen(plain); } return e; } #endif /* HAVE_LIBNETTLE */ void tmpclean(int opt_output, int f, char *name) { if (opt_output != O_RDUP) { if (f != -1) close(f); unlink(name); g_free(name); } } /* read filenames from stdin, put them through * the childeren, collect the output from the last * child and create the archive on stdout */ static void stdin2archive(void) { char *buf, *fbuf, *readbuf, *n, *pathbuf; char *tmpname = NULL; char delim; size_t i, line, pathsize; ssize_t bytes; int j, k; int tmpfd = -1; struct archive *archive; struct archive_entry *entry; struct stat *s; struct rdup *rdup_entry = NULL; GSList *hlinks = NULL; GSList *hl = NULL; #ifdef HAVE_LIBNETTLE GHashTable *trhash; /* look up for encrypted/decrypted strs */ trhash = g_hash_table_new(g_str_hash, g_str_equal); #endif /* HAVE_LIBNETTLE */ delim = '\n'; i = BUFSIZE; buf = g_malloc(BUFSIZE + 1); fbuf = g_malloc(BUFSIZE + 1); readbuf = g_malloc(BUFSIZE + 1); pathbuf = g_malloc(BUFSIZE + 1); j = ARCHIVE_OK; entry = NULL; line = 0; if (opt_output == O_RDUP) { archive = NULL; } else { if ((archive = archive_write_new()) == NULL) { msg(_("Failed to create archive")); exit(EXIT_FAILURE); } switch (opt_output) { case O_TAR: j = archive_write_set_format_ustar(archive); break; case O_CPIO: j = archive_write_set_format_cpio(archive); break; case O_PAX: j = archive_write_set_format_pax(archive); break; case O_RDUP: j = ARCHIVE_OK; break; } if (j != ARCHIVE_OK) { msg(_("Failed to set archive type to %s"), o_fmt[opt_output]); exit(EXIT_FAILURE); } else { archive_write_open_fd(archive, 1); } } char *tmpenv = getenv("TMPDIR"); if (!tmpenv) { tmpenv = "/tmp"; } while ((rdup_getdelim(&buf, &i, delim, stdin)) != -1) { if (opt_output != O_RDUP) { tmpname = g_strdup_printf("%s/%s", tmpenv, "rdup-XXXXXX"); tmpfd = mkstemp(tmpname); if (tmpfd == -1) { msg(_ ("Failure to open temporary file `%s\': %s\n"), tmpname, strerror(errno)); exit(EXIT_FAILURE); } } line++; n = strrchr(buf, '\n'); if (n) *n = '\0'; if (sig != 0) { tmpclean(opt_output, tmpfd, tmpname); signal_abort(sig); } if (!(rdup_entry = parse_entry(buf, line))) { /* msgs from entry.c */ tmpclean(opt_output, tmpfd, tmpname); exit(EXIT_FAILURE); } /* we have a valid entry, read the filename */ pathsize = fread(pathbuf, sizeof(char), rdup_entry->f_name_size, stdin); if (pathsize != rdup_entry->f_name_size) { msg(_ ("Reported name size (%zd) does not match actual name size (%zd)"), rdup_entry->f_name_size, pathsize); tmpclean(opt_output, tmpfd, tmpname); exit(EXIT_FAILURE); } pathbuf[pathsize] = '\0'; if (pathbuf[0] != '/') { msg(_("Pathname does not start with /: `%s\'"), pathbuf); tmpclean(opt_output, tmpfd, tmpname); exit(EXIT_FAILURE); } g_free(rdup_entry->f_name); rdup_entry->f_name = pathbuf; /* extract target from rdup_entry */ if (S_ISLNK(rdup_entry->f_mode) || rdup_entry->f_lnk) { // filesize is spot where to cut and set new size rdup_entry->f_name[rdup_entry->f_size] = '\0'; rdup_entry->f_name_size = strlen(rdup_entry->f_name); g_free(rdup_entry->f_target); rdup_entry->f_target = rdup_entry->f_name + rdup_entry->f_size + 4; } else { rdup_entry->f_target = NULL; } if (opt_verbose > 0) { if (S_ISLNK(rdup_entry->f_mode) || rdup_entry->f_lnk) { fprintf(stderr, "%s -> %s\n", rdup_entry->f_name, rdup_entry->f_target); } else { fprintf(stderr, "%s\n", rdup_entry->f_name); } } if (sig != 0) { tmpclean(opt_output, tmpfd, tmpname); signal_abort(sig); } #ifdef HAVE_LIBNETTLE if (opt_crypt_key) rdup_entry = crypt_entry(rdup_entry, trhash); if (opt_decrypt_key) rdup_entry = decrypt_entry(rdup_entry, trhash); if (!rdup_entry) { tmpclean(opt_output, tmpfd, tmpname); exit(EXIT_FAILURE); /* encryption problem */ } #endif /* HAVE_LIBNETTLE */ if (rdup_entry->plusmin == MINUS) { if (opt_output == O_RDUP) { (void)rdup_write_header(rdup_entry); goto not_s_isreg; } g_free(rdup_entry); continue; } if (opt_output != O_RDUP) { if (rdup_entry->f_lnk == 1) { /* hardlinks must come last */ hlinks = g_slist_append(hlinks, entry_dup(rdup_entry)); g_free(rdup_entry); tmpclean(opt_output, tmpfd, tmpname); continue; } s = stat_from_rdup(rdup_entry); entry = archive_entry_new(); archive_entry_copy_stat(entry, s); archive_entry_copy_pathname(entry, rdup_entry->f_name); if (S_ISLNK(rdup_entry->f_mode)) archive_entry_copy_symlink(entry, rdup_entry->f_target); g_free(s); } if (opt_output == O_RDUP) (void)rdup_write_header(rdup_entry); /* bail out for non regular files */ if (!S_ISREG(rdup_entry->f_mode) || rdup_entry->f_lnk == 1) { // We haven't written a header yet for != O_RDUP if (opt_output != O_RDUP) { archive_write_header(archive, entry); } goto not_s_isreg; } /* regular files */ ssize_t totalbytes = 0; while ((bytes = block_in_header(stdin)) > 0) { totalbytes += bytes; if (block_in(stdin, bytes, fbuf) == -1) { msg(_("Failure to read from stdin: %s"), strerror(errno)); tmpclean(opt_output, tmpfd, tmpname); exit(EXIT_FAILURE); } if (sig != 0) { tmpclean(opt_output, tmpfd, tmpname); signal_abort(sig); } if (opt_output == O_RDUP) (void)rdup_write_data(rdup_entry, fbuf, bytes); if (opt_output != O_RDUP) { // Write to temp file if (write(tmpfd, fbuf, bytes) != bytes) { msg(_ ("Failure to write to temporary file `%s\': %s"), tmpname, strerror(errno)); tmpclean(opt_output, tmpfd, tmpname); exit(EXIT_FAILURE); } } } /* final block for rdup output */ if (opt_output == O_RDUP) block_out_header(NULL, 0, 1); if (opt_output != O_RDUP) { // For output that is not O_RDUP we saved the data in a temporary file. // Read back this data and output the archive with the correct size. archive_entry_set_size(entry, totalbytes); archive_write_header(archive, entry); if (lseek(tmpfd, 0, SEEK_SET) == -1) { msg(_ ("Failure to rewind temporary file `%s\': %s"), tmpname, strerror(errno)); tmpclean(opt_output, tmpfd, tmpname); exit(EXIT_FAILURE); } k = read(tmpfd, fbuf, BUFSIZE); while (k > 0) { archive_write_data(archive, fbuf, k); k = read(tmpfd, fbuf, BUFSIZE); if (sig != 0) { tmpclean(opt_output, tmpfd, tmpname); signal_abort(sig); } } } not_s_isreg: if (opt_output != O_RDUP) archive_entry_free(entry); #if HAVE_LIBNETTLE if (opt_crypt_key) { g_free(rdup_entry->f_name); g_free(rdup_entry->f_target); } #endif g_free(rdup_entry->f_user); g_free(rdup_entry->f_group); g_free(rdup_entry); tmpclean(opt_output, tmpfd, tmpname); } /* output hardlinks -- if any, is zero for O_RDUP */ for (hl = g_slist_nth(hlinks, 0); hl; hl = hl->next) { s = stat_from_rdup((struct rdup *)hl->data); entry = archive_entry_new(); archive_entry_copy_stat(entry, s); archive_entry_copy_pathname(entry, ((struct rdup *)hl->data)->f_name); archive_entry_copy_hardlink(entry, ((struct rdup *)hl-> data)->f_target); archive_write_header(archive, entry); archive_entry_free(entry); g_free(s); } if (opt_output != O_RDUP) { archive_write_close(archive); archive_write_free(archive); } g_free(readbuf); g_free(buf); } int main(int argc, char **argv) { struct sigaction sa; char pwd[BUFSIZE + 1]; int c; #ifdef ENABLE_NLS if (!setlocale(LC_MESSAGES, "")) msg(_("Locale could not be set")); bindtextdomain(PACKAGE_NAME, LOCALEROOTDIR); (void)textdomain(PACKAGE_NAME); #endif /* ENABLE_NLS */ /* setup our signal handling */ sa.sa_flags = 0; sigfillset(&sa.sa_mask); sa.sa_handler = got_sig; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGINT, &sa, NULL); if (((getuid() != geteuid()) || (getgid() != getegid()))) { msg(_("Will not run suid/sgid for safety reasons")); exit(EXIT_FAILURE); } if (!getcwd(pwd, BUFSIZE)) { msg(_("Could not get current working directory")); exit(EXIT_FAILURE); } for (c = 0; c < argc; c++) { if (strlen(argv[c]) > BUFSIZE) { msg(_("Argument length overrun")); exit(EXIT_FAILURE); } } while ((c = getopt(argc, argv, "cP:O:t:LhVvX:Y:")) != -1) { switch (c) { case 'c': opt_tty = TRUE; break; case 'v': opt_verbose++; break; case 'L': opt_input = I_LIST; break; case 'P': msg(_("Functionality moved to rdup")); break; case 'O': opt_output = O_NONE; if (strcmp(optarg, o_fmt[O_TAR]) == 0) opt_output = O_TAR; if (strcmp(optarg, o_fmt[O_CPIO]) == 0) opt_output = O_CPIO; if (strcmp(optarg, o_fmt[O_PAX]) == 0) opt_output = O_PAX; if (strcmp(optarg, o_fmt[O_RDUP]) == 0) opt_output = O_RDUP; if (opt_output == O_NONE) { msg(_("Invalid output format: `%s\'"), optarg); exit(EXIT_FAILURE); } break; case 'X': #ifdef HAVE_LIBNETTLE if (opt_decrypt_key) { msg(_ ("Will not do both encryption and decryption")); exit(EXIT_FAILURE); } if (!(opt_crypt_key = crypt_key(optarg))) exit(EXIT_FAILURE); aes_ctx = crypt_init(opt_crypt_key, TRUE); if (!aes_ctx) exit(EXIT_FAILURE); #else msg(_("Compiled without encryption, can not encrypt")); exit(EXIT_FAILURE); #endif /* HAVE_LIBNETTLE */ break; case 'Y': #ifdef HAVE_LIBNETTLE if (opt_crypt_key) { msg(_ ("Can not do both encryption and decryption")); exit(EXIT_FAILURE); } if (!(opt_decrypt_key = crypt_key(optarg))) exit(EXIT_FAILURE); aes_ctx = crypt_init(opt_decrypt_key, FALSE); if (!aes_ctx) exit(EXIT_FAILURE); #else msg(_("Compiled without encryption, can not decrypt")); exit(EXIT_FAILURE); #endif /* HAVE_LIBNETTLE */ break; case 'h': usage_tr(stdout); exit(EXIT_SUCCESS); case 'V': #ifdef DEBUG fprintf(stdout, "%s %s (with --enable-debug)\n", PROGNAME, VERSION); #else fprintf(stdout, "%s %s\n", PROGNAME, VERSION); #endif /* DEBUG */ exit(EXIT_SUCCESS); default: msg(_("Unknown option seen `%c\'"), optopt); exit(EXIT_FAILURE); } } argc -= optind; argv += optind; if (!opt_tty && isatty(1) == 1) { msg(_("Will not write to a tty")); exit(EXIT_FAILURE); } /* read stdin and (re)make an archive */ stdin2archive(); exit(EXIT_SUCCESS); } rdup-1.1.15/rdup-tr.h.in000066400000000000000000000043041303430127500147230ustar00rootroot00000000000000#ifndef _RDUP_TR_H #define _RDUP_TR_H #include #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SYSMACROS_H #include #endif /* HAVE_SYS_SYSMACROS_H */ #include #include #include #include #include #ifdef HAVE_LIBARCHIVE #include #include #endif /* HAVE_LIBARCHIVE */ #ifdef HAVE_SELECT_H #include #endif /* HAVE_SELECT_H */ #ifdef HAVE_GETTEXT #include #include #define _(String) gettext (String) #define gettext_noop(String) String #define N_(String) gettext_noop (String) #else /* HAVE_GETTEXT */ #define _(String) String #endif /* HAVE_GETTEXT */ #include "entry.h" #include "common.h" #define VERSION "@PACKAGE_VERSION@" #define O_NONE 0 #define O_TAR 1 #define O_CPIO 2 #define O_PAX 3 #define O_RDUP 4 #define I_LIST 1 /* the input is a list of files names */ #define I_RDUP 2 /* the input is the standard rdup output */ /* signal.c */ void signal_abort(int); /* msg.c */ void msg(const char *, ...); void msgd(const char *, int, const char *, ...); /* getdelim.c */ ssize_t rdup_getdelim(char **, size_t *, int, FILE *); /* usage-tr.c */ void usage_tr(FILE *); /* entry.c */ struct rdup * parse_entry(char *, size_t); gint rdup_write_header(struct rdup *); gint rdup_write_data(struct rdup *, char *, size_t); struct stat * stat_from_rdup(struct rdup *); gint rdup_write_table(struct rdup *, FILE *); /* link.c */ gchar *slink(struct rdup *); /* crypt.c */ struct aes_ctx * crypt_init(gchar *, gboolean); gchar * crypt_path_ele(struct aes_ctx *, gchar *, GHashTable *); gchar * decrypt_path_ele(struct aes_ctx *, gchar *, GHashTable *); gchar * crypt_path(struct aes_ctx *, gchar *, GHashTable *); gchar * decrypt_path(struct aes_ctx *, gchar *, GHashTable *); char * crypt_key(gchar *); #endif /* _RDUP_TR_H */ rdup-1.1.15/rdup-up.c000066400000000000000000000153401303430127500143120ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * rdup-up -- update an directory tree with * and rdup archive */ #include "rdup-up.h" #include "io.h" char *PROGNAME = "rdup-up"; /* options */ gint opt_verbose = 0; /* be more verbose */ gint opt_output = O_RDUP; /* set these 2 so we can use parse_entry */ gint opt_input = I_RDUP; gboolean opt_quiet = FALSE; /* don't complain about chown() errors */ gboolean opt_dry = FALSE; /* don't touch the filesystem */ gboolean opt_table = FALSE; /* table of contents */ gboolean opt_top = FALSE; /* create top dir if it does not exist */ gboolean opt_chown = TRUE; /* create ._rdup._ files with user/group info */ gchar *opt_path_strip = NULL; /* -r PATH, strip PATH from pathnames */ guint opt_path_strip_len = 0; /* number of path labels in opt_path_strip */ guint opt_strip = 0; /* -s: strippath */ int sig = 0; GSList *hlink_list = NULL; /* save hardlink for post processing */ extern int opterr; int opterr = 0; /* update the directory with the archive */ static gboolean update(char *path) { struct rdup *rdup_entry; size_t line, i, pathsize; size_t pathlen; char *buf, *pathbuf, *n, *p; char delim; gboolean ok; GHashTable *uidhash; /* holds username -> uid */ GHashTable *gidhash; /* holds groupname -> gid */ p = NULL; buf = g_malloc(BUFSIZE + 1); pathbuf = g_malloc(BUFSIZE + 1); i = BUFSIZE; delim = '\n'; line = 0; ok = TRUE; uidhash = g_hash_table_new(g_str_hash, g_str_equal); gidhash = g_hash_table_new(g_str_hash, g_str_equal); if (path) pathlen = strlen(path); else pathlen = 0; while ((rdup_getdelim(&buf, &i, delim, stdin)) != -1) { line++; n = strrchr(buf, '\n'); if (n) *n = '\0'; if (!(rdup_entry = parse_entry(buf, line))) { /* msgs from entry.c */ exit(EXIT_FAILURE); } /* we have a valid entry, read the filename */ pathsize = fread(pathbuf, sizeof(char), rdup_entry->f_name_size, stdin); if (pathsize != rdup_entry->f_name_size) { msg(_ ("Reported name size (%zd) does not match actual name size (%zd)"), rdup_entry->f_name_size, pathsize); exit(EXIT_FAILURE); } pathbuf[pathsize] = '\0'; if (pathbuf[0] != '/') { msg(_("Pathname does not start with /: `%s\'"), pathbuf); exit(EXIT_FAILURE); } rdup_entry->f_name = pathbuf; /* extract target from rdup_entry */ if (S_ISLNK(rdup_entry->f_mode) || rdup_entry->f_lnk) { // filesize is spot where to cut rdup_entry->f_name[rdup_entry->f_size] = '\0'; rdup_entry->f_target = rdup_entry->f_name + rdup_entry->f_size + 4; } else { rdup_entry->f_target = NULL; } /* strippath must be inserted here */ if (opt_strip) strippath(rdup_entry); if (opt_path_strip) strippathname(rdup_entry); if (!rdup_entry->f_name) p = NULL; else { /* avoid // at the beginning */ if ((pathlen == 1 && path[0] == '/') || pathlen == 0) { p = g_strdup(rdup_entry->f_name); } else { g_free(p); p = g_strdup_printf("%s%s", path, rdup_entry->f_name); rdup_entry->f_name_size += pathlen; if (S_ISLNK(rdup_entry->f_mode) || rdup_entry->f_lnk) rdup_entry->f_size += pathlen; } } rdup_entry->f_name = p; if (mk_obj(stdin, path, rdup_entry, uidhash, gidhash) == FALSE) ok = FALSE; g_free(rdup_entry->f_user); g_free(rdup_entry->f_group); g_free(rdup_entry); } /* post-process hardlinks */ if (mk_hlink(hlink_list) == FALSE) ok = FALSE; g_free(buf); g_free(pathbuf); return ok; } int main(int argc, char **argv) { struct sigaction sa; char pwd[BUFSIZE + 1]; int c; guint i; char *path; #ifdef ENABLE_NLS if (!setlocale(LC_MESSAGES, "")) msg(_("Locale could not be set")); bindtextdomain(PACKAGE_NAME, LOCALEROOTDIR); (void)textdomain(PACKAGE_NAME); #endif /* ENABLE_NLS */ /* setup our signal handling */ sa.sa_flags = 0; sigfillset(&sa.sa_mask); sa.sa_handler = got_sig; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGINT, &sa, NULL); if (((getuid() != geteuid()) || (getgid() != getegid()))) { msg(_("Will not run suid/sgid for safety reasons")); exit(EXIT_FAILURE); } if (!getcwd(pwd, BUFSIZE)) { msg(_("Could not get current working directory")); exit(EXIT_FAILURE); } for (c = 0; c < argc; c++) { if (strlen(argv[c]) > BUFSIZE) { msg(_("Argument length overrun")); exit(EXIT_FAILURE); } } while ((c = getopt(argc, argv, "thnVvus:r:Tq")) != -1) { switch (c) { case 'v': opt_verbose = 1; break; case 'h': usage_up(stdout); exit(EXIT_SUCCESS); case 'n': opt_dry = TRUE; break; case 'T': opt_table = TRUE; opt_dry = TRUE; opt_verbose = 0; break; case 'u': opt_chown = FALSE; break; case 's': opt_strip = abs(atoi(optarg)); break; case 'r': /* expand relative paths */ if (!g_path_is_absolute(optarg)) opt_path_strip = abspath(g_strdup_printf ("%s/%s", pwd, optarg)); else opt_path_strip = abspath(optarg); if (!opt_path_strip) { msg(_("Failed to expand path `%s\'"), optarg); exit(EXIT_FAILURE); } if (opt_path_strip[strlen(opt_path_strip) - 1] != '/') opt_path_strip = g_strdup_printf("%s/", opt_path_strip); /* count the number of labels */ for (i = 0; i < strlen(opt_path_strip); i++) { if (opt_path_strip[i] == '/') opt_path_strip_len++; } opt_path_strip_len--; /* we added the closing slash, so need -1 here */ break; case 'q': opt_quiet = TRUE; break; case 't': opt_top = TRUE; break; case 'V': #ifdef DEBUG fprintf(stdout, "%s %s (with --enable-debug)\n", PROGNAME, VERSION); #else fprintf(stdout, "%s %s\n", PROGNAME, VERSION); #endif /* DEBUG */ exit(EXIT_SUCCESS); default: msg(_("Unknown option seen `%c\'"), optopt); exit(EXIT_FAILURE); } } argc -= optind; argv += optind; if (opt_table) { path = NULL; } else { if (argc != 1) { msg(_("Destination directory is required")); exit(EXIT_FAILURE); } if (!g_path_is_absolute(argv[0])) { gchar *full_path = g_strdup_printf("%s/%s", pwd, argv[0]); path = abspath(full_path); g_free(full_path); } else path = abspath(argv[0]); } if (!opt_dry) { if (opt_top) { /* this is not 100%, but better than nothing */ if (g_file_test(path, G_FILE_TEST_IS_REGULAR)) { msg(_("Failed to create directory `%s\'"), path); exit(EXIT_FAILURE); } if (mkpath(path, 00777) == -1) { msg(_("Failed to create directory `%s\': %s"), path, strerror(errno)); exit(EXIT_FAILURE); } } else { if (!g_file_test(path, G_FILE_TEST_IS_DIR)) { msg(_("No such directory: `%s\'"), path); exit(EXIT_FAILURE); } } } if (update(path) == FALSE) exit(EXIT_FAILURE); g_free(path); exit(EXIT_SUCCESS); } rdup-1.1.15/rdup-up.h.in000066400000000000000000000037261303430127500147310ustar00rootroot00000000000000#ifndef _RDUP_UP_H #define _RDUP_UP_H #include #include "config.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SELECT_H #include #endif /* HAVE_SELECT_H */ #ifdef HAVE_GETTEXT #include #include #define _(String) gettext (String) #define gettext_noop(String) String #define N_(String) gettext_noop (String) #else #define _(String) String #endif /* HAVE_GETTEXT */ #include "entry.h" #include "common.h" #define VERSION "@PACKAGE_VERSION@" /* #define LIST_MINSIZE 15 */ /* signal.c */ void signal_abort(int); /* msg.c */ void msg(const char *, ...); void msgd(const char *, int, const char *, ...); /* getdelim.c */ ssize_t rdup_getdelim(char **, size_t *, int, FILE *); /* usage-up.c */ void usage_up(FILE *); /* entry.c */ struct rdup * parse_entry(char *, size_t); gint rdup_write_table(struct rdup *, FILE *); /* link.c */ gchar * slink(struct rdup *); /* abspath.c */ char * abspath(char *); /* rm.c */ gboolean rm(gchar *); /* fs-up.c */ gboolean mk_hlink(GSList *); gboolean mk_obj(FILE *, char *, struct rdup *, GHashTable *, GHashTable *); /* strippath.c */ void strippath(struct rdup *); void strippathname(struct rdup *); /* names.c */ uid_t lookup_uid(GHashTable *, gchar *, uid_t); gid_t lookup_gid(GHashTable *, gchar *, gid_t); /* mkpath.c */ int mkpath(const char *, mode_t); /* dir.c */ struct stat * dir_write(gchar *); void dir_restore(gchar *, struct stat *); gchar *dir_parent(gchar *); /* chown.c */ void chown_write(gchar *dir, gchar *base, uid_t u, gchar *user, gid_t g, gchar *group); #endif /* _RDUP_UP_H */ rdup-1.1.15/rdup.c000066400000000000000000000275021303430127500136730ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup.h" char *PROGNAME = "rdup"; /* options */ gboolean opt_onefilesystem = FALSE; /* stay on one filesystem */ gboolean opt_nobackup = TRUE; /* don't ignore .nobackup files */ gboolean opt_removed = TRUE; /* whether to print removed files */ gboolean opt_modified = TRUE; /* whether to print modified files */ gboolean opt_reverse = FALSE; /* whether to reverse print the lists */ gboolean opt_tty = FALSE; /* force write to tty */ gboolean opt_atime = FALSE; /* reset access time */ gboolean opt_chown = TRUE; /* handle ._rdup_.-files specially */ char *opt_format = "%p%T %b %t %u %U %g %G %l %s\n%n%C"; /* format of rdup output */ #if 0 char *opt_format = "%p%T %b %t %u %U %g %G %l %s %n\n"; #endif gint opt_verbose = 0; /* be more verbose */ size_t opt_size = 0; /* only output files smaller then */ time_t opt_timestamp = 0; /* timestamp file c|m time */ int sig = 0; extern int opterr; int opterr = 0; GSList *child = NULL; #define CORRUPT(x) { \ msg((x), l); \ l++; \ continue; \ } /** * subtract tree *b from tree *a, leaving * the elements that are only in *a. Essentially * a double diff: A diff (A diff B) */ static GTree *g_tree_subtract(GTree * a, GTree * b) { GTree *diff; struct subtract s; diff = g_tree_new(gfunc_equal); s.d = diff; s.b = b; /* everything in a, but NOT in b * diff gets filled inside this function */ g_tree_foreach(a, gfunc_subtract, (gpointer) & s); return diff; } /** * read a filelist, which should hold our previous * backup list */ static GTree *g_tree_read_file(FILE * fp) { gchar *buf, *p, *q; gchar delim, linktype; mode_t modus; GTree *tree; struct rdup *e; size_t s; size_t l; size_t f_name_size; size_t f_size; size_t str_len; dev_t f_dev; ino_t f_ino; tree = g_tree_new(gfunc_equal); if (!fp) return tree; buf = g_malloc(BUFSIZE + 1); s = BUFSIZE; l = 1; delim = '\n'; while ((rdup_getdelim(&buf, &s, delim, fp)) != -1) { if (sig != 0) { fclose(fp); signal_abort(sig); } /* comment */ if (buf[0] == '#') continue; if (s < LIST_MINSIZE) CORRUPT("Corrupt entry at line: %zd, line to short"); /* n = strrchr(buf, '\n'); */ /* get modus */ if (buf[LIST_SPACEPOS] != ' ') CORRUPT("Corrupt entry at line: %zd, no space found"); buf[LIST_SPACEPOS] = '\0'; modus = (mode_t) atoi(buf); if (modus == 0) CORRUPT ("Corrupt entry at line: %zd, mode should be numerical"); /* the dev */ q = buf + LIST_SPACEPOS + 1; p = strchr(buf + LIST_SPACEPOS + 1, ' '); if (!p) CORRUPT("Corrupt entry at line: %zd, no space found"); *p = '\0'; f_dev = (dev_t) atoi(q); if (f_dev == 0) CORRUPT("Corrupt entry at line: %zd, zero device"); /* the inode */ q = p + 1; p = strchr(p + 1, ' '); if (!p) CORRUPT("Corrupt entry at line: %zd, no space found"); *p = '\0'; f_ino = (ino_t) atoll(q); if (f_ino == 0) CORRUPT("Corrupt entry at line: %zd, zero inode"); /* hardlink/link or anything else: h/l or * */ q = p + 1; p = strchr(p + 1, ' '); if (!p) CORRUPT ("Corrupt entry at line: %zd, no link information found"); linktype = *q; if (linktype != '-' && linktype != 'h' && linktype != 'l') CORRUPT("Illegal link type at line: %zd"); /* skip these for now - but useful to have */ /* uid */ q = p + 1; p = strchr(p + 1, ' '); if (!p) CORRUPT("Corrupt entry at line: %zd, no space found"); /* gid */ q = p + 1; p = strchr(p + 1, ' '); if (!p) CORRUPT("Corrupt entry at line: %zd, no space found"); /* the path size */ q = p + 1; p = strchr(p + 1, ' '); if (!p) { CORRUPT("Corrupt entry at line: %zd, no space found"); } *p = '\0'; f_name_size = (size_t) atoi(q); if (f_name_size == 0) CORRUPT("Pathname lenght can not be zero at line: %zd"); /* filesize */ q = p + 1; p = strchr(p + 1, ' '); if (!p) CORRUPT("Corrupt entry at line: %zd, no space found"); *p = '\0'; f_size = (size_t) atoll(q); /* with getdelim we read the delimeter too kill it here */ str_len = strlen(p + 1); if (str_len == 1) CORRUPT ("Actual pathname length can not be zero at line: %zd"); p[str_len] = '\0'; str_len--; if (str_len != f_name_size) { msg(_ ("Corrupt entry at line: %zd, length `%zd\' does not match `%zd\'"), l, str_len, f_name_size); l++; continue; } e = g_malloc(sizeof(struct rdup)); e->f_name = g_strdup(p + 1); if (linktype == 'h' || linktype == 'l') { e->f_name_size = strlen(e->f_name); e->f_name[f_size] = '\0'; /* set NULL just before the ' -> ' */ e->f_size = strlen(e->f_name); e->f_target = e->f_name + f_size + 4; } else { e->f_name_size = f_name_size; e->f_target = NULL; e->f_size = f_size; } e->f_mode = modus; e->f_uid = 0; /* keep this 0 for now */ e->f_gid = 0; /* keep this 0 for now */ e->f_ctime = 0; e->f_mtime = 0; e->f_atime = 0; e->f_user = NULL; e->f_group = NULL; e->f_dev = f_dev; e->f_ino = f_ino; if (linktype == 'h') e->f_lnk = 1; else e->f_lnk = 0; g_tree_insert(tree, (gpointer) e, VALUE); l++; } g_free(buf); return tree; } /** * return the c_time of the filelist */ static time_t timestamp(char *f, gboolean ctime) { struct stat s; if (lstat(f, &s) != 0) { return 0; } if (ctime) return s.st_ctime; return s.st_mtime; } int main(int argc, char **argv) { GTree *backup; /* on disk stuff */ GTree *remove; /* what needs to be rm'd */ GTree *curtree; /* previous backup tree */ GTree *new; /* all that is new */ GTree *changed; /* all that is possibly changed */ GHashTable *linkhash; /* hold dev, inode, name stuff */ GHashTable *userhash; /* holds uid -> username */ GHashTable *grouphash; /* holds gid -> groupname */ struct utimbuf ut; /* time to set on timestamp file */ FILE *fplist; gint i; int c; char pwd[BUFSIZE + 1]; char *path, *stamp; gboolean devnull = FALSE; /* hack: remember if we open /dev/null */ struct sigaction sa; ut.actime = time(NULL); ut.modtime = ut.actime; /* i18n, set domain to rdup */ #ifdef ENABLE_NLS /* should this be translated? :-) */ if (!setlocale(LC_MESSAGES, "")) msg(_("Locale could not be set")); bindtextdomain(PACKAGE_NAME, LOCALEROOTDIR); (void)textdomain(PACKAGE_NAME); #endif /* ENABLE_NLS */ /* setup our signal handling */ sa.sa_flags = 0; sigfillset(&sa.sa_mask); sa.sa_handler = got_sig; sigaction(SIGPIPE, &sa, NULL); sigaction(SIGINT, &sa, NULL); curtree = g_tree_new(gfunc_equal); backup = g_tree_new(gfunc_equal); linkhash = g_hash_table_new(g_str_hash, g_str_equal); grouphash = g_hash_table_new(g_int_hash, g_int_equal); userhash = g_hash_table_new(g_int_hash, g_int_equal); remove = NULL; opterr = 0; stamp = NULL; if (((getuid() != geteuid()) || (getgid() != getegid()))) { msg(_("Will not run suid/sgid for safety reasons")); exit(EXIT_FAILURE); } if (!getcwd(pwd, BUFSIZE)) { msg(_("Could not get current working directory")); exit(EXIT_FAILURE); } for (c = 0; c < argc; c++) { if (strlen(argv[c]) > BUFSIZE) { msg(_("Argument length overrun")); exit(EXIT_FAILURE); } } #ifdef DEBUG msgd(__func__, __LINE__, _("DEBUG is enabled!")); #endif /* DEBUG */ while ((c = getopt(argc, argv, "acrlmhVRnud:N:M:P:s:vqxF:E:")) != -1) { switch (c) { case 'F': opt_format = optarg; break; case 'E': if (!regexp_init(optarg)) exit(EXIT_FAILURE); break; case 'u': opt_chown = FALSE; break; case 'a': opt_atime = TRUE; /* -a creates race conditions that can be solved, but using * higher resolution timestamps, for now disbale this * feature */ msg(_("The option `-a\' is a noop")); break; case 'c': opt_tty = TRUE; break; case 'h': usage(stdout); exit(EXIT_SUCCESS); case 'V': #ifdef DEBUG fprintf(stdout, "%s %s (with --enable-debug)\n", PROGNAME, VERSION); #else fprintf(stdout, "%s %s\n", PROGNAME, VERSION); #endif /* DEBUG */ exit(EXIT_SUCCESS); case 'n': opt_nobackup = FALSE; break; case 'N': opt_timestamp = timestamp(optarg, TRUE); stamp = optarg; break; case 'M': opt_timestamp = timestamp(optarg, FALSE); stamp = optarg; break; case 'R': opt_reverse = TRUE; break; case 'P': /* safe filter string for later processing */ child = g_slist_append(child, g_strdup(optarg)); break; case 'v': opt_verbose++; if (opt_verbose > 2) { opt_verbose = 2; } break; case 'r': opt_removed = TRUE; opt_modified = FALSE; break; case 'm': opt_removed = FALSE; opt_modified = TRUE; break; case 'x': opt_onefilesystem = TRUE; break; case 's': opt_size = atoi(optarg); if (opt_size == 0) { msg(_("-s requires a numerical value")); exit(EXIT_FAILURE); } break; default: msg(_("Unknown option seen `%c\'"), optopt); exit(EXIT_FAILURE); } } argc -= optind; argv += optind; if (argc < 1) { usage(stdout); exit(EXIT_FAILURE); } /* be as irritating as rdup-tr */ if (!opt_tty && isatty(1) == 1) { msg(_("Will not write to a tty")); exit(EXIT_FAILURE); } if (argc == 1) { /* default to . as the dir to dump */ msg(_("No directory given, dumping `.\'")); argv[1] = g_strdup("."); argc++; } if (strcmp(argv[0], "/dev/null") == 0) devnull = TRUE; if (!(fplist = fopen(argv[0], "r"))) { curtree = g_tree_read_file(NULL); } else { curtree = g_tree_read_file(fplist); fclose(fplist); } for (i = 1; i < argc; i++) { if (!g_path_is_absolute(argv[i])) { char *path_tmp = g_strdup_printf("%s/%s", pwd, argv[i]); path = abspath(path_tmp); g_free(path_tmp); } else path = abspath(argv[i]); if (!path) { msg(_("Skipping `%s\'"), argv[i]); continue; } /* add dirs leading up the dir/file */ if (!dir_prepend(backup, path, userhash, grouphash)) continue; /* descend into the dark, misty directory */ dir_crawl(backup, linkhash, userhash, grouphash, path); g_free(path); } /* everything that is gone from the filesystem */ remove = g_tree_subtract(curtree, backup); /* everything that is really new on the filesystem */ new = g_tree_subtract(backup, curtree); /* all stuff that should be ctime checked, to see if it has changed */ changed = g_tree_subtract(backup, new); /* some dirs might still linger in changed, while they are in fact * removed, kill those here */ changed = g_tree_subtract(changed, remove); #ifdef DEBUG /* we first crawled the disk to see what is changed * then we output. If we wait here a few seconds * we can remove files that should have been * added. */ msg(_("DEBUG: sleeping for a while")); sleep(5); #endif /* DEBUG */ /* first what to remove, then what to backup */ if (opt_reverse) { GList *list_remove, *list_changed, *list_new = NULL; list_remove = reverse(remove); list_changed = reverse(changed); list_new = reverse(new); g_list_foreach(list_remove, gfunc_remove_list, NULL); g_list_foreach(list_changed, gfunc_backup_list, NULL); g_list_foreach(list_new, gfunc_new_list, NULL); } else { g_tree_foreach(remove, gfunc_remove, NULL); g_tree_foreach(changed, gfunc_backup, NULL); g_tree_foreach(new, gfunc_new, NULL); } /* write new list */ if (!devnull) { if (!(fplist = fopen(argv[0], "w"))) { msg(_("Could not write filelist `%s\': %s"), argv[0], strerror(errno)); } else { /* write temporary file, add little comment */ fprintf(fplist, "# mode dev inode linktype uid gid pathlen filesize path\n"); g_tree_foreach(backup, gfunc_write, fplist); fclose(fplist); } } /* re-touch the timestamp file */ if (stamp) { if (creat(stamp, S_IRUSR | S_IWUSR) == -1) { msg(_("Could not create timestamp file `%s\': %s"), stamp, strerror(errno)); exit(EXIT_FAILURE); } if (utime(stamp, &ut) == -1) { msg(_("Failed to reset atime: '%s\': %s"), stamp, strerror(errno)); exit(EXIT_FAILURE); } } exit(EXIT_SUCCESS); } rdup-1.1.15/rdup.cron000066400000000000000000000004101303430127500143770ustar00rootroot00000000000000# cron.d/rdup -- schedules periodic backup # # Copyright © Miek Gieben # By default, run at 03:57 every day PATH=/bin:/usr/bin:/usr/local/bin 57 3 * * * root [ -f /shared/backup/.mounted ] && /usr/local/bin/rdup-simple /etc /shared/backup/elektron rdup-1.1.15/rdup.h.in000066400000000000000000000071161303430127500143040ustar00rootroot00000000000000#ifndef _RDUP_H #define _RDUP_H #include #include "config.h" /* copied from: http://www.boxbackup.org/trac/changeset/2054 */ #ifndef HAVE_DIRFD #define rdup_dirfd(x) (x)->dd_fd #endif /* HAVE_DIRFD */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_SYS_SYSMACROS_H #include #endif /* HAVE_SYS_SYSMACROS_H */ #include #include #include #ifdef HAVE_GETTEXT #include #include #define _(String) gettext (String) #define gettext_noop(String) String #define N_(String) gettext_noop (String) #else #define _(String) String #endif /* HAVE_GETTEXT */ #ifdef HAVE_ATTR_XATTR_H #include #endif /* HAVE_ATTR_XATTR_H */ #include "entry.h" #include "common.h" #define VERSION "@PACKAGE_VERSION@" #define REG_VECTOR 30 #define NOBACKUP ".nobackup" #define USRGRPINFO "._rdup_." /* files starting with this prefix are ignored by rdup, they contain user/group info */ #define LEN_USRGRPINFO 8 /* length(USRGRPINFO) */ #define NULL_DUMP 0 #define VALUE (void*)1 /* g_tree_lookup returns this in rdup */ #define NO_PRINT (void*)2 /* don't print values with this flag */ #define D_STACKSIZE 100 #define NO_SHA "0000000000000000000000000000000000000000" #ifdef DEBUG #define _DEBUG "%s():%d", __func__, __LINE__, #else #define _DEBUG #endif struct subtract { GTree *d; /* diff */ GTree *b; }; struct remove_path { GTree *tree; size_t len; char *path; }; /* chown.c */ struct chown_pack { uid_t u; gchar *user; gid_t g; gchar *group; }; void chown_write(gchar *dir, gchar *base, uid_t u, gchar *user, gid_t g, gchar *group); struct chown_pack * chown_parse(gchar *dir, gchar *base); /* chown_parse */ /* child.c */ void close_pipes(GSList *, int, int); int wait_pids(GSList *, int); GSList *create_children(GSList *, GSList **, int); /* gfunc.c */ gint gfunc_equal(gconstpointer, gconstpointer); gboolean gfunc_free(gpointer, gpointer, gpointer); gboolean gfunc_write(gpointer, gpointer, gpointer); gboolean gfunc_backup(gpointer, gpointer, gpointer); gboolean gfunc_remove(gpointer, gpointer, gpointer); gboolean gfunc_new(gpointer, gpointer, gpointer); gboolean gfunc_subtract(gpointer, gpointer, gpointer); gboolean gfunc_remove_path(gpointer, gpointer, gpointer); gboolean gfunc_regexp(GSList *, char *, size_t); gboolean gfunc_tree2list(gpointer, gpointer, gpointer); /* rdup.c */ void msg(const char *, ...); void msgd(const char *, int, const char *, ...); /* getdelim.c */ ssize_t rdup_getdelim(char **, size_t *, int, FILE *); /* abspath.c */ char * abspath(char *); /* signal.c */ void signal_abort(int); /* link.c */ gchar * hlink(GHashTable *, struct rdup *); gchar * slink(struct rdup *); /* reverse.c */ GList * reverse(GTree *); void gfunc_new_list(gpointer, gpointer); void gfunc_remove_list(gpointer, gpointer); void gfunc_backup_list(gpointer, gpointer); /* crawler.c */ void dir_crawl(GTree *, GHashTable *, GHashTable *, GHashTable *, char *); gboolean dir_prepend(GTree *, char *, GHashTable *, GHashTable *); /* names.c */ gchar * lookup_user(GHashTable *, uid_t); gchar * lookup_group(GHashTable *, gid_t); /* usage.c */ void usage(FILE *); /* regexp.c */ int regexp_init(char *); #endif /* _RDUP_H */ rdup-1.1.15/regexp.c000066400000000000000000000024311303430127500142050ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * * regexp helper functions */ #include "rdup.h" #include GSList *pregex_list = NULL; /** * Read the filename and create the compiled regexp * in a linked list */ gboolean regexp_init(char *file) { FILE *fp; char *buf; const char *errbuf; int erroff; char delim; gpointer d; size_t l; size_t s; size_t re_length; ssize_t j; pcre *P; if ((fp = fopen(file, "r")) == NULL) { msg(_("Could not open '%s\': %s"), file, strerror(errno)); exit(EXIT_FAILURE); } /* read the regexp */ buf = g_malloc(BUFSIZE + 1); s = BUFSIZE; delim = '\n'; l = 1; while ((j = rdup_getdelim(&buf, &s, delim, fp)) != -1) { if (buf[0] == '#' || buf[0] == '\n') continue; /* buf[j - 1] holds the delimeter */ buf[j - 1] = '\0'; if ((P = pcre_compile(buf, 0, &errbuf, &erroff, NULL)) == NULL) { /* error */ fclose(fp); msg(_ ("Corrupt regular expression line: %zd, column %d: %s"), l, erroff, errbuf); g_free(buf); return FALSE; } else { pcre_fullinfo(P, NULL, PCRE_INFO_SIZE, &re_length); d = g_malloc(re_length); d = memcpy(d, P, re_length); pregex_list = g_slist_append(pregex_list, d); } l++; } fclose(fp); g_free(buf); return TRUE; } rdup-1.1.15/reverse.c000066400000000000000000000016101303430127500143640ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * Reverse a GTree by putting all element in a GList * and reverse print that. Needed for rdup's -R switch */ #include "rdup.h" /* Let's make it global... *sigh* */ GList *list; /* Walk each element and put it in a list */ GList *reverse(GTree * g) { list = NULL; g_tree_foreach(g, gfunc_tree2list, NULL); return list; } /** * wrappers that call gfunc_xxx for GLists * In the conversion function (gfunc_tree2list) we * skip all NO_PRINT entries, hence to harcoded * used of VALUE here. */ void gfunc_new_list(gpointer data, gpointer userdata) { (void)gfunc_new(data, VALUE, userdata); } void gfunc_remove_list(gpointer data, gpointer userdata) { (void)gfunc_remove(data, VALUE, userdata); } void gfunc_backup_list(gpointer data, gpointer userdata) { (void)gfunc_backup(data, VALUE, userdata); } rdup-1.1.15/rm.c000066400000000000000000000054711303430127500133400ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * rm.c remove an fs object (recursively) */ #include "rdup-up.h" extern gboolean opt_dry; extern gboolean opt_verbose; /* ENOENT */ /* errno */ gboolean rm(gchar * p) { int ret; gchar *dirp, *q; gchar *parent; GDir *d; struct stat st; struct stat *st2; if (opt_dry || !p) return TRUE; /* noop */ if (lstat(p, &st) == -1) { if (opt_verbose > 0 && errno != ENOENT) msgd(__func__, __LINE__, _("Failed to remove `%s\': %s"), p, strerror(errno)); return TRUE; /* noop */ } if (S_ISDIR(st.st_mode)) { ret = remove(p); if (ret == -1) { switch (errno) { case ENOTEMPTY: /* recursive into this dir and do our bidding */ if (!(d = g_dir_open(p, 0, NULL))) { msgd(__func__, __LINE__, _ ("Failed to open directory `%s\': %s"), p, strerror(errno)); return FALSE; } while ((dirp = (gchar *) g_dir_read_name(d))) { dirp = g_strdup_printf("%s/%s", p, dirp); rm(dirp); g_free(dirp); } g_dir_close(d); /* dir should be empty by now */ if ((ret = remove(p)) == -1) msgd(__func__, __LINE__, _ ("Failed to remove directory `%s\': %s"), p, strerror(errno)); return TRUE; case EACCES: /* no write to dir, make writable */ parent = dir_parent(p); st2 = dir_write(parent); if (remove(p) == -1) { msgd(__func__, __LINE__, _("Failed to remove `%s\': %s"), p, strerror(errno)); dir_restore(parent, st2); g_free(parent); return FALSE; } dir_restore(parent, st2); g_free(parent); return TRUE; default: /* not ENOEMPTY */ msgd(__func__, __LINE__, _("Failed to remove directory `%s\': %s"), p, strerror(errno)); return FALSE; } } return TRUE; } /* dirs are now handled */ if (remove(p) == -1) { switch (errno) { case EACCES: /* we have no access, ok ... */ q = g_strdup(p); parent = dirname(q); st2 = dir_write(parent); if (remove(p) == -1) { msgd(__func__, __LINE__, _("Failed to remove `%s\': %s"), p, strerror(errno)); dir_restore(parent, st2); g_free(q); return FALSE; } dir_restore(parent, st2); g_free(q); return TRUE; case EPERM: /* no write on file, reuse st - and why is this needed again? */ /* this is dead code ... */ stat(p, &st); chmod(p, st.st_mode | S_IWUSR); if (remove(p) == -1) { msgd(__func__, __LINE__, _("Failed to remove `%s\': %s"), p, strerror(errno)); chmod(p, st.st_mode); /* is this usefull then? */ return FALSE; } return TRUE; } msgd(__func__, __LINE__, _("Failed to remove `%s\': %s"), p, strerror(errno)); return FALSE; } return TRUE; } rdup-1.1.15/sha1.c000066400000000000000000000013341303430127500135500ustar00rootroot00000000000000/* sha1.c - copied from /usr/share/doc/libnettle-dev/examples/sha-example.c */ #include "rdup.h" #ifdef HAVE_LIBNETTLE #include #endif /* HAVE_LIBNETTLE */ #ifndef HAVE_LIBNETTLE int sha1_stream( __attribute__ ((unused)) FILE * f, __attribute__ ((unused)) unsigned char *digest) #else int sha1_stream(FILE * f, unsigned char *digest) #endif { #ifdef HAVE_LIBNETTLE struct sha1_ctx ctx; uint8_t buffer[SHA1_DIGEST_SIZE]; sha1_init(&ctx); for (;;) { guint done = fread(buffer, 1, sizeof(buffer), f); sha1_update(&ctx, done, buffer); if (done < sizeof(buffer)) break; } if (ferror(f)) return -1; sha1_digest(&ctx, SHA1_DIGEST_SIZE, digest); #endif /* HAVE_LIBNETTLE */ return 0; } rdup-1.1.15/signal.c000066400000000000000000000011361303430127500141710ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup.h" extern int sig; void got_sig(int signal) { sig = signal; } /** * we received a signal */ void signal_abort(int signal) { int status; switch (signal) { case SIGPIPE: msg(_("SIGPIPE received, exiting")); break; case SIGINT: msg(_("SIGINT received, exiting")); break; case SIGCHLD: (void)wait(&status); #ifdef DEBUG msg("Wait stat: %d\n", status); #endif /* DEBUG */ return; default: msg(_("Unhandled signal reveived, exiting")); break; } exit(EXIT_FAILURE); } rdup-1.1.15/site.exp000066400000000000000000000001521303430127500142270ustar00rootroot00000000000000set tool rdup set srcdir ./testsuite set outdir ./testlogs set tool_exec [pwd] #puts $tool_exec set all 1 rdup-1.1.15/strippath.c000066400000000000000000000056051303430127500147370ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup-up.h" /* strip n components from pathname * sets path to NULL when the path didn't contain enough * components to begin with * * Symlinks are handled as follows: * with path1 -> path2, only path1 is modified (shortened) * the pathlen is adjusted accordingly and the * and the filesize too (if that is overloaded which is * the case with links) * * For hardlinks we must also strip the part after the -> * as all hardlinks fall in the backed up directory part */ extern guint opt_strip; extern gchar *opt_path_strip; extern guint opt_path_strip_len; /* Count the number of slashes in a string (=path) */ static guint pathlabel(struct rdup *e) { gint i, j = 0; for (i = 0; i < (S_ISLNK(e->f_mode) || e->f_lnk == 1 ? e->f_size : (gint) e->f_name_size); i++) { if (e->f_name[i] == '/') j++; } return j; } /* this implements the -s option */ void strippath(struct rdup *e) { char *p; guint i; if (!e->f_name) return; for (i = 1, p = strchr(e->f_name, '/'); p; p = strchr(p + 1, '/'), i++) { if (i > opt_strip) break; } if (!p) { e->f_name = NULL; e->f_name_size = 0; return; } else { e->f_name = p; } e->f_name_size = strlen(p); if (e->f_lnk == 1) { for (i = 1, p = strchr(e->f_target, '/'); p; p = strchr(p + 1, '/'), i++) { if (i > opt_strip) break; } e->f_target = p; e->f_size = strlen(e->f_target); } return; } /* this implements the -r options, strip opt_strip_path from each name */ void strippathname(struct rdup *e) { gchar *where; guint len; if (!e->f_name) return; /* the other way around, if the path is a prefix of the prefix * we should discard the entry. But only is the path we are looking * at is LONGER than the prefix */ (void)pathlabel(e); #ifdef DEBUG msgd(__func__, __LINE__, _("Label %d, strippathlen %d\n"), pathlabel(e), opt_path_strip_len); #endif /* DEBUG */ /* if (pathlabel(e) > opt_path_strip_len) { */ if (g_str_has_prefix(opt_path_strip, e->f_name)) { e->f_name = NULL; e->f_name_size = 0; return; } /* } */ if (g_str_has_prefix(e->f_name, opt_path_strip) == FALSE) return; len = strlen(opt_path_strip) - 1; /* -1: discard the trailing slash */ where = e->f_name + len; /* string starts with opt_path_strip, so we can just jump * into e->f_name[strlen of opt_path_strip] and discard * everything before */ memmove(e->f_name, where, e->f_name_size - len); e->f_name_size -= len; e->f_name[e->f_name_size] = '\0'; if (S_ISLNK(e->f_mode) || e->f_lnk == 1) e->f_size -= len; /* hardlinks need to get the same treatment */ if (e->f_lnk == 1) { if (g_str_has_prefix(e->f_target, opt_path_strip) == TRUE) { where = e->f_target + len; memmove(e->f_target, where, strlen(e->f_target) - len); e->f_size -= len; e->f_target[e->f_size] = '\0'; } } return; } rdup-1.1.15/testsuite/000077500000000000000000000000001303430127500146005ustar00rootroot00000000000000rdup-1.1.15/testsuite/lib/000077500000000000000000000000001303430127500153465ustar00rootroot00000000000000rdup-1.1.15/testsuite/lib/rdup.exp000066400000000000000000000000201303430127500170260ustar00rootroot00000000000000# empty for now rdup-1.1.15/testsuite/rdup/000077500000000000000000000000001303430127500155525ustar00rootroot00000000000000rdup-1.1.15/testsuite/rdup/rdup.a-flag.exp000066400000000000000000000002531303430127500203700ustar00rootroot00000000000000set test "Run rdup -a (reset atime)" if { [catch { exec ./testsuite/rdup/rdup.a-flag.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.a-flag.helper000077500000000000000000000000731303430127500210560ustar00rootroot00000000000000#!/bin/bash ./rdup -a /dev/null testsuite > /dev/null 2>&1 rdup-1.1.15/testsuite/rdup/rdup.chmod.exp000066400000000000000000000002661303430127500203370ustar00rootroot00000000000000set test "A a chmod a on file with an incr backup" # we expect no output spawn ./testsuite/rdup/rdup.chmod.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.chmod.helper000077500000000000000000000006551303430127500210270ustar00rootroot00000000000000#!/bin/bash rm -rf A rm -f $$.timestamp $$.lijst # some some bogus dirs mkdir -p A/a A/b A/d touch A/a/1 A/a/2 A/a/3 touch A/d/1 A/d/2 A/d/3 ./rdup -N $$.timestamp $$.lijst A > /dev/null chmod 400 A/d/1 # we expect, A/d/1 to be removed and added, this # should yield 2 lines out output OUT=$(./rdup -N $$.timestamp $$.lijst A | grep 'A/d/1' | wc -l) rm $$.timestamp $$.lijst rm -rf A if [[ $OUT -ne 2 ]]; then echo BOE fi rdup-1.1.15/testsuite/rdup/rdup.dir.exp000066400000000000000000000002661303430127500200230ustar00rootroot00000000000000set test "Test a mode change on a directory" # should not yield any output spawn ./testsuite/rdup/rdup.dir.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.dir.helper000077500000000000000000000006131303430127500205050ustar00rootroot00000000000000#!/bin/bash # script must not yield any output rm -rf A # some some bogus dirs mkdir -p A/a A/b A/d touch A/a/1 A/a/2 A/a/3 touch A/b/1 A/b/2 A/b/3 touch A/d/1 A/d/2 A/d/3 ./rdup -N $$.timestamp $$.lijst A > /dev/null chmod +t A/d # incr dump, after the chmod the directory MUST not # show up in the dump ./rdup -N $$.timestamp $$.lijst A | grep -- '^-' rm $$.timestamp rm $$.lijst rm -rf A rdup-1.1.15/testsuite/rdup/rdup.full.exp000066400000000000000000000003751303430127500202100ustar00rootroot00000000000000set test "Do a full rdup dump" #if { [catch { exec ./testsuite/rdup/rdup.full.helper } msg] } { # fail "$test" #} else { # pass "$test" #} spawn ./testsuite/rdup/rdup.full.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.full.helper000077500000000000000000000010531303430127500206700ustar00rootroot00000000000000#!/bin/bash rm -rf A rm -f $$.timestamp $$.lijst # some some bogus dirs mkdir -p A/a A/b A/d touch A/a/1 A/a/2 A/a/3 touch A/b/1 A/b/2 A/b/3 touch A/d/1 A/d/2 A/d/3 for i in e f g h i k l m n; do touch A/$i ; done # full dump, there should be not output diff -u <(\ ./rdup -F '%p%n\n' -N $$.timestamp $$.lijst A |\ sed -n -e '\m/A/mp' |\ sed -re 's|(^.).*(/[a-z].*)|\1\2|' ) \ <(cat <B\3V˜fS^!^熇28J* ) FZCz_H E dl`lؾ4IiD@ Q줟Kc]~ _Ӂ%%$P]\%Lvs64WvY|x 3_L<*o&wc72P?𑙂HF 9%<ك*rDvfVM3RPTqQF8﫩H`K ExȔ|6o~1'PJF cE;E _ #V(d8!ZC2kNğ lә<t4zd73Id$edKI@c,m ۆtSZb04px\ =6N#ZJrHoн. 9@Yi1.CnxFB;E z(4J^5ӷ+gMԉĵḮv[Μ"t|a=M,Y$ͅ(^qfDTU sMᐑq|}C[<4Y .zj@H3VB='MiY&~&7oS8aO42UR84~f<T) : %`uA,))OИձc҃S ܆0;M t D\J7pR-Vf=OCPEۭ P5Lh*mHOY< v](|glsU_u=⽤cDND t6-,)hlXsOQEHnw*{B6^ߣƺG(~[}ƻտ lQ$ Bp^UDCrwB%NDUy`<;kP3m~뚑ru[ɮQԜƺYpOX!W(k؄dK$]3c:g SՈlDg Z\4b%[Jذ; ?5[6@XqdD~|1AHYh L"/,tyHCXkvᬪrx$M|*.m'(}C0gu1gd;+nxdZ5O,>]Qܫ":ٙ9Hrѐ$ -5YM fuqu t۩-0x_e s43ᅥ]8u;nZf1&9,]kᦹ< ' w겖 0lHZ^ vbQ]b|!tTX v_v]zE Q=*D"r\*.A@FUv_doD66&~KMEE+9O85ӛ! ,JKQN]'Q>EY~Qe8@֏lL2, 5m #T/‰H?jDk ^2 1os,}!WneI9ybI!t-~(_bkh)wE XK0N&hƳ̴ "b;fB#'Pi\ʝ% }*B2R-7E+ݫmͤ";.Bh鴦1A pU +B20~j6TBsi^8e\'H넇-@\li"x8+-O;/kLCⶫb07#"FRVHS[ F(WF/ {n٦/]Ud@a+}JU鎠uԌKK@:j~d }=KФ٩3ƣOha0y"J[cRx Q$IU)*u_.#8 29~+7=5y%oNsi> X9|Sȑ֦=bL͉[ trotzuʅeգX$&) %2aa0O" ~^>O6OhC! HpXG~ ݑz0Yҷ:$.,>oB:x ~TCL~|ۤ7B8B|7Shƅm4ރ.Z V?yխ΃}z{(AbAg|$q=ПG >5ݱwL=)q[HGC23ƒ^Ż ߒoUgzܬH{鎲]qR- Q򞠋Rz`IYi\"hcdPNB?Վq68qHiW Q;{'ye Z4hO(q ѢrBÛo%k[;֦}uL%# 5/X;2!$rĜw)g:稛F E@ G ZI"\l\!ySO 3}KF㟿rA%,1lt+}N"~m\oDµ4- Y?jkFh~Kj|X>2.hڡo91+[UM V~ ch(MiUHyH/\' k.b=Mzm'as{X! c() ["V@{#ik ۀ ۲(ApCM57)_Jnz5ω ( K e̿ᴕ_U))lح hxL3;,Ѕե/aa#3YKѦ 8;R!|Gǖ D&lN*6{JrAYڻ4[T\k- *c+SudgvTKM |ٿMQh $u){2Ń`ہr&25NӠyO 0'SZ |xNC(I ;W_+J^7AX[cX /}@s0*+qdj{6(PAQǞk^7 ~5Lz gK,U%_k%2픻)CuuN޾?6{Zܐ@6SE'妑ݥBj9ڧG$ApgGx]~g.9)D$i+^0ؗ?qrEJ@Ka;_"ާ K8^6n5 5 4z;ۄIfza dqB/R7΂/t~pTȈV*jkǚ<b0FDCtx_i0Bt.2#maԨ W}CTi8;+ƚ4X_0+ Apo)f% 1Sqh"ŤȒ!R m4);Fj)SN*swdthuC 1~mΗ6͇ZpNf%U"8 ΀%ϞST& qu6Uu̹oz 6JqKY=X-5ȞsA/Z^ƀXyC߯QGqO$Eb}F j*{;`O$:/ `%}`IOk[>/tc$hOVj<_Y Tl3>]yeQCJK+Z BhZCUbnj,9VF捁Q+FtO6 hxʲ~kPeYO)n]1  s: F01?PW$(ii aZP01!s 0$sh?li07g ,)|8"}I`p,Cg2Ϫ6]p^/ E}3s`*"GGȍG r^>.&ztbi$`±Bo0NV@Qg~1tA?d|ȱܳ ͋9Qҗm۝s@D[PV IDYчdAޖgSF 56{>E#Q8@3̺:PvGfS;ZBfq/=MC #|ffNNA敧J:siXZjDzN׳bJ®CeWHǰ\ae*C龲ꗪ {RDWjz0^ZtvނLE.WYc&$ϊ=A`v'#ʭجXfJE/&8.B;b/5Ű{rE]B!s7q~/]rNkHϞ|fl*SD8[eFxHq)\ QD4ҝ>b鋠3oOH(fyKOia߫&w%#t1YfmFΨ%yE 8pk?+8S`xNV~gYbzDY@ ʛ E]wdƨ.Z %)sp=,(hSŅ<cdl217 <ܺ(oGXP}sQ!M;p,],}nvq"wf4T'Q1"0u-1wi(I[_XvR&,rk'YMZHfTC%cLԏl8}B6wD`X8[Lg8h],6ʸO,\OƩmh}g AOT$K(El<Ӛ pV3 1_WW*@n0D_(XY1?oOŐ pڌ4KML@_3Uw g 5d}h@af`QNNk@sפT@po)|)%ο:,31'AYe09- jIdcLJZt.`uҒm[0S$4*ݪU)s7~hxTakm՜Ru E8(6ͽ` py+ iV/0wc˃엖MDԼ{0@_7WDP܉~;<썃)^(@ T\f]J(h=ǐjȩ@%.:}3DJ< :ҏH)ލo~~1SF.ɦ{ЕK^@:M_hf'hGuv|AUޅGLEk\QI~'p'*.+))67JyKS:[Y@帀lVS7Uj<ⅵpq^ ?^$Z쓏-gP UZLuŹ,s`|], PļngsӅGBgAYrNb6VH}BmQ9T|K'%wlNQ` W.n`O-9&Ci( rS*xO"E2WsTe0)#Mk)82t_k כ|Z[/VHHl09rc$c0|BL~} dgjLM4<,g!Ƃ|}Qq(g4&J.(6zG'pR< RD+mmoA?ҫ Hy֕nL'J6ڔ>ff(9Z6}hN>Yq3T訪d'a>Ěf g;kn?IKLC3 dq!.aėeEH)BK} I8Ǥ#T+,ұ6p6zvLx(ٛڒn@,b8` Z)Y!mڒ"SXGgǥ0J:"UBl_-RsX<,Y8r,+'@ct_n,IZ^ i@Q AQoyqF\F^ܵg6bxu.j XԺ33c*T|0m-Ż߭cpy:͑dkN^O; TlEtIj S* oަ Sg6,ԯ>gZ4r!~QKJ_g ex Z'7[`ְ&ޤ`G,Ы+-d).Tԇ٨HMQ/<C0*v( J ;RJg2(hצg(.(j@Cݔ0͜>>_is=xVOm&Au Wlb`tE%u8pBq[: a)ie_\^q/]ޮD¼@u߭1L@~BĖĮ(Q}xN0]zLI]mPqNo;dDTrST*saH6_h:[(r'Hd͡-o B;7K]t3{<P%%bKm K9Lş/Kw%Ov[0x;vu5)v*Ǧ)JڐpS.*vM˴ p[D$*IM]0d$k&5}d/-[/GŞvίڏk@vJNf EZ(fQH&do}u>#_?45;#ݨLŽ1~-?y/)sqe9Yj^{ 6k6UO͡cy*Ds|\DNqs18Rh^'-5r6R47~](Q"@v%~ߌۂoj]FH \l>X`]VkR+fk,P`1C.pBV_3k44YX͉4V M/Y v%v8f?:,34iN_J;~.b7 Ɔ߳0(%F3#e:nӫ G7]sH !Y5"뛜Oo;¨5bD\#*f"u<.PمH[`ճO݈܃i4)6;+Cd~zwn;I,ޱhrc?уyZ,wF r#j%FӑaPuVP KSЫ 7*m{?Yz,9BZ9ޟg{Z~<[#z=O{H\RLi*R Dij4Ws&HF'dQ.@ZT@eJsm?­÷Z$?UUBH囔"5R 6 ~!1 Sv1Z\1@'C!.9>4ч+f'FBl]"T`c("Iݎ^˭45:Ld{+b/|~b}3=={1MzeQd):]7Q *{b̯_Bo4@,d}<%'#}x"lj8@%E!CLRj^6$^I$,9k]ʼnpm/ft7uv|GsL ٱ|`N/JS`Trgdt]R@zWe4*.1#zc%zV(\. FxZwUxU&<JF;JH%qPf Ϩ7Fq=ȩI{%(cfʆUJc>sm(uO{`Dv;=u"m>P(lK@8J*pf6~4N_R6,W s,~ ؚkeRHN;* (gzۇMjsB#-q R3'@&~}`w̹2BuYvh?S@ot,q?o Ach0R  fK'SߠFڴ2·,eo0Df?椛:]N+ ͧ5BV{G}m9%-4hGҕ,5`x±鼵j/ݗxٷ/?f Ɨԩ8}6ay XI&M@x1M1+n9G0G1j4}9w d}+̧]mK!q_}}{6d| ?8 Wm$:t"A߄u3S[G%{[ېI$&eڢ=*L-ŝ+qa.) ) KrPy'R+D9&Iwm}nz;˟W#חր_dplR`/^:9_%L0Aw ~至 W+ xKXҠR.8 yY'ڤ$]t5fYk.ƥ 5| 3>% _.^[V0"čw% JHB*i:$}9 t0V}!dE/#sqs*ή R#"x%[ *jȶ{G' &G.k*xDI]}8zd'Xԯ|6V7,<>{q)AUW\hL%Ƒuֽ n2y ^IÝ 0"6dzy M~^ŜH3OM E=s8%GlA|FG!n}Ť'.㗆M=& f!Hɨ&V-u8'DC!FbWL FճgHx0/@PIvA[y(@F/|.CWkZ?,#jP]˽tEϞ b*g/VXLuI_F y[>`w``:MS1 q0d&3 #(kxÚ XYHA`yұ佔Ia t/unKRwd]Y.\J+L H-ī}`+x0/.$n:j-Qek) AM1I,zՅ(tC*pz.Cq n}*?I6b6)rE,#~IɉX- zh,U_ȱX<2*,g4w?P唌7O1yniP, i  n6Ptw6 ;@#'.9^1wSs 5q:'4[Zao]*{jEͽж2S(m8+'Agk'Y)muԒ OT2]$N6 (3]LcŢ{ƠcO[1)C8̬d]w_a7 K"ErʤuCUR&Ocf]m"fס)!X59v_lwٲ /ZVn2gVh$[p'l૆ퟆT/ΚA'bfZz Fc5)FEl ht"AՏ2Y#NUrM^ |Z#2s3GHqvbg$]i$40֔m,jF(CYxϚfCY^ޚwS[sMX_A`V _nhݷeQ*-h6!2YȖ[qe5pۯō{Y3ѹ#{cUCNaGEfWq8|:$՝!} G`a]s u]‚p"E{9:ϋ;5$oZka g$ $.q1@o^қmߜ=w'߯+  qSBb{GF艽F dKUT؏9l;I3,icW FGEb1dgQE]F1K,\"S= !< ?k5iH%&yqS(wZʏaaϥA 3aLYh=ȂG.g&'N>fȢݨ}>,p"uq |Χ| qgvG6<)ME3@uHw3J1(n"B{ҡ-4`٠_If3"./ >v?Xk96\hbCUT k `׈,׭/8 L@dސ .U.6BkjHfysW keTo\NʦmVnƭAH=1YV51 /k4dCxbTxp:J"TpE$#|hs-~b'GZG-hmD_$ܜ"l'oeYbб9 @{8(_nV@B؍9l*-zq-z&NͣJӱRS)n]I|]Ω} < h5R3rg' ^"yoVFC&/[mT@K+_lmF8%9?I5 Yvp0FC9[ک@ L¾U^!B@R~îm 3µV:~T'?GϞgu$沛Yvc%_f/ $h6kix,s#YR>S#]lnPD-Vz%R| 3PH$]< ZjL\7QU0 kv#ee8i6Ĝkʚ% UWMD m/4rc& nюZ6I\9Oͳrj IFi)1`w"f?<7E㷰$ VH339ga8HqθTdL\[)CtSjY";Rvˍ5,f1Κh+ods}vWd-i€F?N$][tlc̩;P$WP;;w qxdZpv7[?:$Bn%#uIs^Xd3T,܇v|-)|%z!f Pzz>Wz[rw$d wqWk&:iy CN:a'E^nM:;D0c pK ~D}H%T+h J\m hHguM߁ T4  <չD04 CLOGE[ l)J(pc|/xL)ɕd =$#|X@I(A|QrGY}g)I c&jDЗUVs7yg-hW Ԛ.5D9{yYթeQt΃DI }/NYא^K/Y|tgßVS9@aS_JȦ+– g-T˷\@=㝒sdrLٺFj5OF`[ JJe:>'ceeuzm㓂5D23Vw]HaVS)/)>>m#d}%.fVWDd஋bge)Q߫=!ŶgkQtx-?brk\2LRnd&;p?_L ʕ- P2K2aokH ;(*QQ+@l;œX5+I 5'Wr n! '8Mu>!AmUFl/ɷ)OAi<"'xO#+ ֍*#?2wd\T :͢]m%ム:wXY{YZ:o2N6MZ-=Ҏ}6LRr׌c G^  si7Vܚ=WJ0>6ȗ!; Fz#H6]6 [[2jdzBg`8n K q41B/}'e"O:  [@[ЮZ)} +dԨROo㷞0VdU@%yii߯jR55Gb`r~u}8c=j(j2\Ơ-%:xO,p| z礌cJKQФk|,<-j ﮢã^`}H$yG+z$Zbߤ7jgeI:z]&%:8Hl{"C[%iEQ&Q\:opލx:+EЇ-P|aOcyFCWӂQ G4{O/)Tm;%[P<>Ыzb!z  D~5ĐY`C$0ݙ2 3OeLc(D0t#pcrXP#+7>5 \ü.F(S״vz% /% !Wj:|b&;`yj!] z:cɂw86T1)[l-#0)?4ۆ_xڃ{z6v Z0\%]oz> ,Iđj0 /}M=TQT*.B Pյ`-F?ֵUSؖw3.Ѐ '*J)4:YBQpak6<3ÂU+FtYoiyFïL= b5ʸ9_|HS j^>1aDj-iozբG\WH;i7Wоw}6OBUoa{"5]PF-Z+pemEC/0]0" D(m2AGH{)"iTZiW;uj;N7;J703U;K8g54 RM(*:|k%G[YB{'У=(cP`i- L~(;*KuIɳp~F(9qxgi7IϸG&YZ0
TܾӰK1Ǫ5,ިGpq#65jɏ6@&9 ̔eFD#$,:q&p ׸ G~Im9? (5Lu7 ~MզET鮻A9ӻ8}B(cQQw vj,+K^Х F_ [5|FDtf>/ƝVq![4/Y #OX0UyV0[?_`р)K:l1%>;b=Y'X1.xJ +I6im.-Heٟ f)moOQ~$Om|P a9fuf ImОX .ʿL!ѐl`YplD?2jE[);lta@"՗ưpИBkо^2Gv '4"`J]Bz_0(5kE@qR|Pw\XN2$b@p䢏 ) $G"\IrY河0YCvJfJAćV"n]%| tCW&YCTϸl18WBm ww\ 9hnm@Ok KxTQfTwsn ۅ?cEkHzq5*8~?(0E|8`0,$b1O1F p2Aafp q`y YÄƪU<*%hlW*{]YqegR0 9u,_JMD{ 2>Ew }a-(SQqD"dvKT5r2w`Nv$H/x.E 6|,3ORϷ$[ iL{s#G[hy  q$?c_*Ku\79`]qAɆȇ!~Jʦ/ gF wL92<-Y uƊɝLY4a~> Β.A4!3?@T^CMjW|TQ\pUyߝse^T[xia2ؠ р^N@0JęZHWκ3Ch-kXHP<|iiG!lmi(ABu<:[ژarŹ,m)+0Lm?ns-d11>Td-6zMg}%|CƔnӃ Qbq挍/L_t s!t6vu*R*Gzsr#dIڐuf$ 2)ra[*yuwuXqrR{Z"M_EqlmY=*.ш~o O%pliPѡ:J-cEaJbFPQ$^b$ yfAHT?skG U"cʷevȟnk9.tS-s!X|'1|0]+Ĝ{,V=d|R9q=K ӥqWN2]m7gYeL`˅~.t{`Ol׺a//{Ed V 9y"ֳ_^˛fU3҇2XG۩#5oOLu~w3w䤍V+]sa`RPC>sNbP>v4d[hXie$<AI03 >^íE a?wd%bޜ߱Vlʹ,q Mw{/퍾`R._\D2 sz^A|B1YN6F]Q$%Bw|j[rƤs/ Ŕ Dy3P!MM#o* [wX[gXKnOA1>ɛ8y\6|cd߉fB?5x([!x=Wۇ s9+kX:G6BۯMaHѨ 'Um,䘟-ٲҪf>;:qRBK{˜C HT!Ͻ7X$QqwhR8QYʺLBB3[IZB6CJ'/VEh} S$Xτx!gj/r> 7rIȦ}xf[r:ǣf @V)rQ0 Մa-3Q)>xpVor)\OKv{i=5( EsHK%bH0Bq.]}7zLg˰2N2wAemߖ=dSqx'D>)yt^0SIs~t/6Z-ԖKa1.$9\w"U'v[4D/ ZEɠۊHrS1lW@@;yyXP•Eć}7]dЕw({^,3+  lj0p"sƕ+ɋMb-"=8=A38ՙZX %кHxO,59*12޲%rUoXbtx)<#eNGf U6o_9HTX~00dunDzkV?|jySÛlFC=p"`C蘖~8os^ $I裘 w1P"4o8/0XjKi pz*Qm SJ%r֘a!Yv]+i*B=%iRAsuC_ĠKtL8,ӷez2  g(寙u;q,}RƑA J]W*`!:qA; Mɕ$>hKHz|+vɏAte&WXxڍo`kL"b5AqNl"nnAmy h}CkЙ6k9*O]w>,˒Gs^HW9cH:}Qc-mAwl:Vk-Yc8+x'AцՍC6(Q) 2wD(g/S@19iI+6i4ʧ$8+h.0=mWfn<RKUpFrr/.jx1XΌI1,?We5>BsAkQqO9].o0q+V**!Ѣ$gEv }L^_2yq-]u);pԝ9x$j>}DXz_R7;sY R胞@J]NmѿTI- ͼjJwA'l-@͏щaݘϿ(ub+]RH`7>ӫ9H Avε"TL<~ۘT1 ʲj ~z[#;6*o!3K]ÏmΒI1[(/m2FG_a|H}4;LF&:,浰債Kl s 0y#c/^CY\cäFT 6>{yC) L$Q3B'7v;N7geTiE] iz'Ux ʃosۇD5[*6!rQ%_K#慻\kY@\N K(DGv HLW\&hj&\`1n2G0oeXl}鏃AtڄJ Qqʗv2\)QOJ\[֎ H9hE+"QRn(PT,i*H(?taAQ#öA(*fy6_.tv{eSo>NLaUDFE *(Q5>z&."E y ,CJ Мԁ" ;Mg+N6 =*̇m cH?H$uN>OY169kuaP*WQ=EQIyt>jV}\ښ`zU9~&f>A`Mw b<{ e7t8Em8qզP~>>c*BjJquUQJi6pg LEQY*#'e<97d%7XEN{Ctmipz on} Ա^/.vwcL@6D̘aLoV7Z|ʜM2lH:Q׭l)Đ*;EHmXrb3! JoEu֋mxڦUdcl|U+bTVmw{OYβ5Z}KQ.S\q䩯G6lL#o"n.H7ZcCfŔ= i u7t.zWa/4vЋ$ tSky 9"_H4GIX[Y Q쐗J$"VZI^s b/><88E qH4y:eS\4RO;4M\!x{y6`aP *VENn/B&bT0d8nK/il jx3%lϒRQnezωI,*C( /1ݺb8'NG ŽVZ5O%t>][-j=X nd & ׺t;[q)=K=X_) \qhvTgOzKM;ߤ&5 M9UDi/u.OQFɦBw+6 )q[I6_bv(XiNtʉN`#6s3Y()D00!iz$䊂7oIܱ޻R%Wv=vFudH`,KyI-2_6!D;=`q_mZJ-Lo.1C+@U?Gpg,J%a,xF}|zz^Q&{8=dظ[1֏8% Bf=PMy}ZzQlM+E{٬-myPQoe[[ 3hDKkYk\K;;Pm(5x|a_ڹ!Pc^m3y] #r )ko%ٮkD"%kK_Z!\%#S$#T˥IC[4357Lmu~8oڏ6s6?cv]4||oX,҉fFcW QOWi_r ˗FvK^/.ڼ@b>@h p2%PnI%+fm)[-W=6< oԀx\ȾZ Tt}2p$b#*tX cgV1GDfñf7*FP#pL\wSC=020! з{OAvUd)Gꊉխ:-n56: ;4 jϗFq]\ S^s?=x_ U>;A7.77<8Kqt,䤶Bgު=+qW10܄jS+1t-dҀ|0rE2R*f%=/3rI&^ƍ~iB+u~Ӓ2qÞeE/8f2H=|KF"(ERـ;uC5`,@D9C C.h%~+-j#!<+Y)lm Pܑ M,O%jo;#8 h\8i7 ħk4@P5oel`3(s'ohw/xvr6KTg8M uKEJlQ ¸Q* &4 Еw4s٣SIhQmkmj7Bu%9FX΅H?֊M[ʩ`l7v'7W~ YR&(RGsL`ـ\2:зas=(vOg!c֤׀Ew#4} lx"ֽ[:Bn }PIfMhPsX Zcz_iUO\{pW04s]w#Q}h\w|RhIO6G'?m=O*N~͹ 51C$Zjx3yhyKӑLKg TD/rEAԴ8(")יW0Dд7`\q6/lC-_DTh~Ɯ ~fm{>O*j4i̅8KS0g0JKvUH N,5ʠOR ih#.TԳe$ߢ||QOMr.G`m+ѰRTT&vV`(hpOv "HnjX78hˇ;d ?k2F%oq.HR ~Pc}+ƯGCn:0HI]Ɏw)Q*O+":)>ek}5S_c|[)0uE\8?Dç~EͶ[1D^y X;4$`¢Pi%_|?NTs D0/BA[ȓ@ۏ~NyVnB _LaBSR$"?KqHUxR:"כRK!\B_w\*jW]g_2pI-e'"a@ƐXHVVv203*t O,˩$P:b4.<!>E"7Dٱ?rz2a,LZP vIVnoe {CJsWHsfnB*Ѝ{ $1(a%Z-X%\CHcY^;(Qmⱎxd9~fۻԏe/QF׸YyIR\7#)~=~PxCrg^06m68t2W R9:Y-09ӌ(+!w#n3FB$dS &VjEё*R-RvV(d-^HsJYt)8+U$G))JBsˤSDv;*w3ofNw V˽)U4%"=չww$0HqnWxj)on|/%VnD"DvB{Sh?ɡYHtd:(!uGjT fܤQHB b"Ϫ}e9oMA+CpLQ[\NoRWeȠbiID&")H&牚Ʃ287@7‡lgP PΪsݾ{Nه7Rkӆ-Mhay#޹6f9!.fD!ahiJg b9.}^!tX_`Q0MRi %IU <9Bė|vҢ!@@K-֡=f.5EKFmwnR=ZҠ&Oߛ3%՘cN]ʁ/ 5 k?7Qa}Xo0Ys;0FbLx5YMm6,ƚpEu&i /O[TvNSX@Ձߔ:tJ\(Ww%}ϫ11A2U.Ɔr\l||\.|bp*O7~Qb$T+F8$l3҇KXp_^4 6xoѢ7=}Q/Kb7;# ݶ'_Uo4BBP@SH폻Y\D :<L]ͬw-|l q\Ym{]oDPUMN-m|GH1bD#"}6]C[U-%9P'@[r}Sj@6WMϊ?w&k,~XH1R近("jH#Z6?ߑ$-#t#ly0$Vpov?;_MW#rRؗi==2C#ޣ>xE,-Qv5 % /z0˨nhf608 e`LS91辢m:y \uZ84!_ ]PpnVMTovL7RHRn{RLĝ("@\h{x-KR)ez]v{@(rA>/Dtl Mzi7 dvc1lsT 0~Η c ٠|JM?!SCiUٶ* mqIr쓈e Bu$1ҔM$ikaXG`~'U2Qj eb&~yRCGڸ- >y ?<8hza"_ݟX 6ҲSBCy ] uGV6HUO.0XAO[ażWvAqR\h8!<Ū VO/7N0,8Ħ3Jhp%ezFC<߄`F<= N:p89&r%J}؁ZȆIeƱrƀB 7.̘fg+/~OfsIQFD7ʏQy:Uv5LPD\ނj=ߎ XBȀfM>*5x7l J7#`B!9^آxAHTa2\DB@ *ISʇrFP]_QoM̝w/]r;B=RÑԕ˄|+e\+u :|1%q#63%=$FXVK7:>G{YIA#11B,U hUs8tY~_͙tlo1ETtD'¨]-lZ,h M|"mq̗Q}esD- V.@И0rArdʮ&\K_n(R' <\$l\=5B;GR/n3=aG;͹DW"qAac0gUn$!W2l9#wzE Bl' r2fk뭣nVk;|h6G F^5sS NO2ٙl3sR x7x{K`M̫lO7d9C>ܦbO~>0gIX8gkY"-CrN:E}d7oNٽNnl”Qp KT'oD$IKk*5 _†GۀeQG9Q|+:4N'5GfCi}[wc# hs}\&[ TEc#hمj- n#QF%#gRX奺3csuZ2oCƉ\rT^.?8 = .z>OCN\q{\`Yv{w@TA:&폂!53 mL)Bo wh/SPZ%ˤK7cVmp#C]_,A*zBP)>%U&(QJR7?^QtmfnnkZѽ /;l)z;t(__?Pa 92ՔL'J >Ը8ݰG鷉ey㚿9K+wɶnPʪcq>~"@_seU*B[)#҄YҠߏbZnM ]SjPS$Ȕ _o/7\'Vl4r 9fص{%_JCbj7*8beɉ s(ޞ7%Ë_$cOOKoaƓܟO[]GXSx Ȍ٭ n5,c@`tdm)q",_Fe|J:cz.˰'[1.&:HBY_b9]XU8Q *>qOkMg G䪞kl%0|vj֖\.0zӨ7,eIRZFSuJ^u_dvЉͯ#$FǑo+gvʌZGI/|+L.M/*<SipZ} |4(<1ԁF("~Al] 㧭E^@g+M/ XY[w'U1 >mF&zIe\Fd~^2nm݅۞RԒqݠ)Xj>l.s=#cH2pjѝMP4U~ԫ")pʑn:}IvIBrbU,Q;_.tmw#>beduC3s>/-Ε " Bd &Dyaǵ޷%K͏zrhsVJv(kQ;` _~:mQ0G^aD}Wdd ?19K99ˎ4waH1$p_tXeQdtcԯ2\?m  Ԡ L߆e6g1#,]@VdX_}2CGi$up͍1y-ʴEVP~HЇ=ʻ%Vu@b{+AYsDjX#xL5L:s$^PBpÒiu8ϕ1gH7&Zm[Us"nhCw1fnЕ)8ְQSn|\)qkdẖ 7 0i?+U@pKĦlR8nnYioVE8wVB3rBN 'q$/LtM̍0k_aI YUƔ`[;l?n(fFۮ\}l)b,R&ӈl%{;4SZaye>P1(uVn7ȽZ Nq SRaT=ιgި ~kYmbha"6)t2rlU׀e=ߝv]1wl:FZyM ;O㨩 ۰yΰ 7-s_3 xU<08,ȺH%nXjtjQHљیIq溄K% x}csT΄#o(Xt1 p z7QeI4:UőLknyd5;125 _bzAݣs΍č'. P{T&D1Z6.?p"Z'Y6|x2P^g\zqVqOuP}6?ӊ :$PY~LvhqL.#$%ea_1Lrw߉͍r攟+%jlexO}H9o+5K jxg&u#)MQ&lΑ J0[E)NY2L z6ui sZoImMe5lZT64[kD\QvUw 0#q4Sb|Hd7ch_Ft )7ټ35P?i OVQtLDz܃U6$n~ROGA(rt=2Mޏ}:8p(ƫ'Xnf\#`@y3M2MߢIw0M}z'́8i`A(l'û}S6 ̹ ƻ8.h s 2`Q,|k6aΗ'k, UT Y!ūj z]G|Ř[8Iﭙ#iŕa2 qg"jG5ҫoJ`{ďqnRp춍2xYkV m , .Xޝ(J&P kGij2\S@.\{ E>A, 7|мw߮>4]4Z*Dh2}.Ʒ/ )f%=0{Mj-GF?'P&xiwstTɫЮW0V5qgzdBsШ8ma>iѨg?Sec ؖE%.pfQS_h`@<6ea0ط3;odl*@5[=Bi!Ma:RhjJm`^<.Ij m^7%Zs|`<̨/3q9K@Qrk(JᑶW{?`@0Hfڥm& 3ȥ s{3, R7[;=HIF2Y雤AaDZ2#T/IJ̶Mp'(:X6 u!Ұpָ-=EG$P` @>^`'XPzSkw j/ h zj}{R`ddB % [>~{TF FVHH4-nYPiG:̜r&n:؅r2xT-sՍ[tf8 !\ˊȩG2j͇7`}Qݔ*ARgB8tz-xWIsP9V")` w 'rȮ21EhP`?VN }_YM2aH^7 hgϙؗI`yWDO߰#)tc7Rjaޜ;H}dul"^4b;0$W >m'!ڧ5]J$[HE :`^c ˊ<&t6n<*E B>J޷@fL+% tX]SmOø%Pr\USo 1L ;i{]Skοşeb}Ͳ/F+YPA7g&LPCUB׭`RNԒ(Kj+h([w)9/"|4P7 uYQ9,á{lQTT ?ZߖݗRH顊Ǔ&DA,CԕzSڽe~k~y([V4LW?"-Ld7yM>i%DeDW '~đ_F*KL6DvU g?q d()ؐN%=y&V߰Ju>#9EN&J=xjxcvJĊ}8 +ڙ}).e@m>H/YP@"2N:@PYʻá :ĹC5n~茉R=+jDIΰ %*g? "{C/H{/]Qx^ckn=Kޜ8,0) ߼0@`UVnebsDLTi䇕.G;"bUmU1UUO@?Vx9;UIM3xZRܡ%QEfmۥx8z| mL041hlgE#V?7H>S.8BVe4CU.XcLՋr'i67x. "3iFx YZo*C`ݭm|TI HEdRi<&d^[ܖɈ!bi: !;x {/Bc[|I0}!UT6CZ7L=Ycl>݄ΛGPF4>^yrFlFSjrQZ^Fk!0f$M(Ok*U8U{I 9^+U/s.)U3{T(t;(OF ʠ xt yS qΙn[bRHtl c'{VP~wh[]))Hˏ]} &(A:c w(g] V7@֗ #ε@Hೄt {ԣ҆,nL)?sl)f<[&|J-``$ʃr(SX%`3KYU2" _sPwٱ}@ۢtΠ/z:YGppڒËu.N'88ȩΰumoLnǚWa=>M5^ 8*xL(6`zƲtjz"DA, DC}="鎷w.G#Z*q`) Y÷&?SXaصڑϓMA(Bk菏 '"K, e1D:/"p>}.ɇ/))mYqзaT=3#UͿ`r=>C,6y'{%s>q]Hj50ӈ4j'JV7"E[B,X;j*a{teN2 X$u)V`goqZQߐĞS^N)# ?o N5E_ISxFQqGԠb65~GʝHûePF!R|(&,)n܁ ʲF4Om+z@81qF*X?7+/ҝ2 1R;.^~jp9xW5^Bص 8[)(mh~0٠9<$HYwTu"`rAzu;vX6p+fw⟵*)9F%f8]ve H-z!~PKwVgdaoki 7"JKYd3 =G<+ك`ҽab2e؋8b@;iј k;,-xW6]CK>Е -΄#VTʌ6eY 01^K*LYPef@2\R`plEԏsuBK.!h]%wcƱ.(A#tFJsTOH.B>P: ְ,k'`#;AFRm"qVBrd+G[}Ѷte(}*{x]}@o䮖^U}\|nU1 o]H_g / {b9fU{kj: o^̜v*\~"$Z/!-(_xh!E>O؆_-SF&w{Lxyoq I d?l24O(<M.nØ! u<)Rh1b6~so -xoQ@{+ab!O]*]q ^d?gzhb\:lSOr,>ׇEn"?YE -Z-šUt庯a ]oV%o>fu@v1|)x-RD@MaŐo;(5do($A5onvqb@_ZUL[۲ԊhE^,'r&SUNq]|qy 2͐%U6IOy0L4P$x/3m1\S飴HɁfF;_7֯ [ǒ2n$r°$\>etI2 qbA#[LลK65,C zIXD;͞l)ܺs$2 iT4N"mֳN=`:KaHówۃ4^G',Haܝ9\WLZ:|fc*H0st?6l)BGئ})'! @)&|aE!\eΗ{ofO롬>y!c^;f~X6Kz@UKAǔ%kB K/Tq-3 * b{L#jO{Jˆ9:f H*F@syAdxɖɀه":dH|%5ws8XWtӨ揖Z?"OW"]E2h>[or^!qfV>V"/Qu^B6P ǠxڞfMY){aDҀ,-1Ϩk;aKzMKVyєBŗ 24l=VU[|}2@&VVИ%uM޳("y/p:wn :RVDḤ51C]"ݒ".{RPK IOn&n07dP+<';Y{lZL ;Ֆl:(j񩅕E].n')f:bQLtU7|۴BavTXYBږFLICH|>]+\f_RD dHFV>DW|@2LwV L5TCM&b!eODmG)S͊}eK/1%#8(v!Pmg +'0t طvm"gsܾ~ #^4k3݉o|2x8TfM0()<8~k3~o0w ['^yOx}pty^tbR%Iz(fco=T8bCq5_+bMb:T&9ku@ FwW3$5?lW1K~%0~[p{Վ?;$.1%ĘPٯ9ђXYAM5Fg5Ծڈ\"tTUNH zw׀I*>qeRU7#WXރULܰ r.쿯jzZ gTit =:y%qL0-!o?"mltk$S A?"u0VC-DtN=~VV ZVN$K]⑘t]Ŋ d&Re0fNl!$8GeGc/4UIȣ䟳͆*qtL8EYZBbƖmU8{hK6<)6%uEquxLB?x4uռ=ll_J"o O+=ZkP416:w|FTs>r1 KWwXB̉i:04љFDr|Z "JWQez,W,{OuVe ; |beqp,t/4?@8&IT/8">eg;8Gucxi92k+E5.v E^{HcdmM>$7νRa0ut% D3PqŎzı(@|TO-CA@yμ9 ggP^*[VW"z+_bJB6] fE24۠(I[Yw%_ :rhפd[J6ohFu.3X',Ŋ#G1!W% l~mu() ew#BK=apw5;ڇD[@i4a L[^9{=ΆI$GZj݈Ju0YK_ X޹ S?6!ia ?DJ6,$g A.re3}[`^ !J|6g)i l@<-\G V>N KOFS7&@FݱBd?L>=x'FKP[,麔 lA;!7{Ԇ~K.GD/ϭmqRs!_߳j/c(TGlc `pk#.,wɉ֪EP6fғ2. HB((yKn}iH7bL%qNh$,1]*zPsb1I]&5=a[Y5huԋDyKRrL^ݧrxHm9Xq rla9S?jjT `$ 5\cp$ +ؚ۪+d}2U¯;TT3|̠7/'^VKmB˼uġ Yٍ5ؽ&LcoJ=n}wH\Tɂ)0yarF (ZCA#T&ëcG;&Nt&'Іߒr=5vR` е@ D{?+w B* JN0WǰdF0*wQeM{nYյ㰜 A e"6`, AZͪ !F艱m1LBthK}1܆!<;ˮqx"v (jc?܏4søI`Ơ=BG욣f&ض™NqEDZdZP1m_ujYNL:mvHDO&3DVӨ `Rs{\1ׇ'.U:5 ]g "HIy{q/"a'Bp+^0iklTO6/wbR佌. کFR910im=ʓlRݣXĶ>ʘ)k<˛:Q@=50 >#dvɑuL6Uݔ#!~W\ϐȿ ޶~9FN pD21@VMjX+.C3A~$2P0XMq ױB~ nfғr]bwP\3Em|VRH'^q[5@;_=2S052A"(0 P?q_;T~n#fFb,舭f\>t" UH 9!@/fotsxuf&mbץW>9&iDGT؊@oC֘ԃq kk_]+Cz5p]lE)w](. n/SߥBA};ˑ&'ٽռpM ғ]Id֨tJҤ8K*G4B{6R-t0* Pq#Xhb{.àխVa&=Za^Sx4- x?Ln%NuV$6 @oUw9z=SssSlm#&=#pUqƆ5)5fKN$m  Nh.OmccGQ{-םCwvC= <1~`x|»!Ge-| $%WnV*.rb&p'B|d'[ 򲖈y'R=b=?{6Z_ g?a"/<:V=-܍©5þ2JѿxB8 očƐP< d( "7KLǻhoYuȁS4+r?-\[)h)̄.HH>%Qroym''"^ca6}}D~m B10qH0-HI܊z"[BHzV"Ij|Մ0_|ڮ\#}˨ḃ}պ,ڃ*n mUD6hE! G4LO*|YՌpͽL(8~ izݠ" F9cOH!b/YӖͳK&k- هhMiFM74Ŋݮf |j%@ }~1PE͜Yai%'C|9!W7&pdEjuM!$ͺ UK;;-xş3b'M~~h0PڈA&zۘ?֌bVf- [ NdPe-H+"3բKX/1}iߍ&'*$kNl}*9gG)Mu,A\$Z 0n I OKEu 3UoȻx8(_oXxaBtn7-?ə,E8 ,IBA+nOJhRA%!$rxm&}EL>TbQh_tbmΝ o-Km kI[idq |ۇ:l|܏rKPRE.L[[n㳌X5&ǡ7sQf/0Eٴ+}xD7sRZ'"gI^&[z490qJ %PmlhETP3z2-dW>[E6UdnQ[shTe5z T]pPVuL3*Z>D"̻ĂM'4IDm~@V,Q#t\Kg`ljGP{Ay$ dL{T#\>.q={\tEO;CN^X*z,Rq?Yqդ~ōw+CfRpP1JW`L\C8u0 ;SZV ގ_Q Q#NMzPZX+6゛PGP" ^nlֹ|I![ 1:X2m~jp oHѢH,ǮH1}ADcXB'4EqgL % P\[K =*b'Q@S`$*2R(VY!oWFN#1e[#p5~޲[#7Ѡ33ZrYD/r 9R2w CƤ'"J'0ԍ+0ցO>('Mb/+2w4 mRNofmΪ:1?\ /"cCJ07wܰƟ^W'cv.C+N'%$P^+ G2V$oΆmTWXAJ' g)N٭EztԤKAeAuH709wY;yQ *#_fTp*#Zi_sHtٵW%,: 4VɔYädH+jυR*N#V;nRJᮊtE)[vx@/ I{ 1Wv&m+M/=.;"HVA5rx9ZK[&Jô$jO@Q"? nS8HpH7?޶%J"(n{G+f$CdhN2bk\,Ϧ牠BO -O8`dSyFߐEkD?8; S(ypHJ Zqb{ԫh|*,a5]&Owq&/L C:uɫɼ8eo8E~(aڥ;Oi^YRuB UE%#X{E}L%2=TK3 {k!Qpiw\t@5>T" .r;4(QKsUQ3qb$=?1:ÖI% (ΗC{"g ^]O6/yE(!©(󾃣O-@6Z}.]1'ӑqn҇\͜'$/{buEN+ e&֮y\)Eng :NZoL3CLEt!l-z -ڭW,%{|j絯y{ @%G27m/Uߐ-7LPdSn"ZZ*X|}s9Q\Flc"ėXHlwV {g^ɻfd(pHSs+$lbVAh`)T),PDW?!XW)@^JI#wFdtLI)ެ>/i a /~NB\p+ʄ;!cXѣ\[Pq4M;i.g%OffL(W*WNVYFa*M:4k7 m 9,W޶_0%r'<ә W&WHݚ R8BK[@] _U\o~vpAKiܯ=6X[FdEe'_㡆 &˶HRI4s1ze D쯳Q'.oĊG7=s,>-;c٘,meuޭi9\9ā?^=7Y.Y+Y5 ." Y:2[m}ܾ| Ȳ^X$li Z 0|8" K" F|Ti*C[//ʜE7&+Y}QH( UbgǬ2i#8 k:ۜ&V2T{0Ʉl!JIE1lm^34/3HG6?Nu0Ͼ2ďWK^6^4#= LniN xF4}ôǶ Z wt_%:m s~WEZ9iZy,7j9Wr:Ԙ8^BiJ{f~87MK|@V>Ʃ,BëM7\2ܐh$nTO)ky_gJrb圁8N&Qp)~:*`s,5D=HH_iPF\*tJ8 I֗<)?~+L5_RTSw@8NuołrЀsgNH[s&o)vi8=VB2~JQV4R>NA,(rM;,ӹ ݉*3D:f3 YX:"C1 k\6MRiRS$%-PhKW ,{R;_7$a|+l}j4$3{H6쪛# B"r?:g};HNiikv!׬ 1z|[K[p2VX!xN v@*vlސvy=A^qύ+]r0Pz?8ǯc!pt#ZXR%'kocH{^vKEbQBngdU ` a}AXX i^ZT2}Rw_iJdCξ @Qn^es0K9L&%ugKJ[j#m @c̍,,W[ $&;Wvu2(%mwmND[&OӣMmnOl'7plOhMC]#g*1"҈{?s$L^3 zS5""pD"z뛘eFܵɈʐXFXoaܨ2yh-ϳ҃ "H{"b W_E[6'6]." 5˞k8-sǠJ߶ge%P~"b5>wl90op"cN,[X9%, bQH4_Ev-|2JԆ 5g@B?H8|؏FƏcǑєkJ!"ɒ pv "~\^8sRUNFȊ VJ EfXE[ \B۷Y}zyxa#%v07$]  >jw㓬s4ӛ+hJ6D R>^~޽H+m]w1QzxK.l<\#XeyTeJg;hĢ)?l@{C'i֍.\wOxTr6/!8s,ґIxjA$nLQ:y(_A$o;8vb>[SD Lk~_Y1-3t-ڑ!a *M 7!՟/p"|.^\,.vq"͓~KyklP h G7`!*5Kސi {$ok~4c*pv5 % 3d\50w]:Ua$/:`,ǖUf4-ۯ`sõ>>;gJviG 0eru\FfcGĕbx&_Ui?,Ds(JeEJ 0[#= [3嘳DR#g/8@ɹ0C:3NZh2%*:zDžBT U ByB[aPJ3MUv\vտ*߀D48ޖuzH,m,FAi7;ncN0dUw~ŀd/< DHuh|"EҊlfHvK+x_Da*'ܚxOc: o+sz}j9iAذ@n=eOKΙRG[8_Ԓ!Ii LxyreA>G_LX #ADCAEmLk!T5Ypmܟkϖx ,J![dY?ځv_ )XF6(~䜏(V FɞAmY8Ce,[[׫׊C'\DV-ȞNH,G-#G2dGYݭ6fj%5jU fXe+x!4'\}5mvh@5L1 ᴕ +Ōu݄'+CqY`UحO2C^#UB:(-ڶMl7i ~e k*j&Ա 65gn9#|W^v KBNTv6dfb ~X<G-1=|:l)ىRYWf&###q BFlK=BnR4bq P6p.A SN('򁢋FhŶPCAb+b 1'9zA rRJE;|(sCC37lzmuxYa xՔ$ Qy}* |co;sLJgO5}4jƳBjH,cQSֹk=dLbXyAI)T1(%x@1WپCi5q+EH™i~.y8TmDA2n/nٳUsn<9.6*~i^:]Y]~T+Qw,Я4@_ @n4%T?u'(#dgOmg Y-%ްREېFte6v[:aNj7v"XQin¬^(GJ~jFPe@tl׆oIYi&S4q4EJn' YƵ8?o 94B9-/_`mGz!4-U)å-e3vIiH${8HDg&$-JV2vda;e G9=_<.Y+Ŗ|)` H^~oYbn/=zD6Tda 3峭-EX6ʣbw 7Uk~[[đxs[Ȫf*1gBC 6'q)*~8GDI8/H9}륿0e~YLqs No +>]kA;%̈ؒW8ŘqnNvq;4;OmeJ|߀ckZ<і QK܎~Q w{7eQ!Ģ;p)FyzYۛ%RY/|l=ft Gu"NRKGWa XFVGHR,kZs(*'׳љϿ=X hi]U5ܪ9%au'tO3VY ̲"X\:i$^ks?[#-5hC k'G2x&΀ C $9L@$L5ݥ 'Aam(vZta}X(ӓ5QQ'VBG2# d[=576)!}d|r08zPquqܝ ]47\OsskNT"Tu MZ5Odz ()Za2fZӽR w#7D(lij8a q+gxLDzSȈ[+VCq CYtմISh\s) a˕fGM 뉝0l?hAsqE"27 Y Ù*O:NhiZ|ӇS Xv[QFGj@*o-*k ;ǣVH&Mew|j#곮7V+ q;/+$!Pꗷ[Z\IYd%f`vX]V?,;&ck.S 7;`k{^cQ/ci/AF+^%iʝZi2u9b8οPiE[P&jC1Mg5ė? mw;_|"F LV6duVS{[OѤl4\d8,?Rs+H -4r di̽*V>N܏4-5EH*eg_V,$;c[#a)ix#`jA<`\N j6'jn.ZGaM..Ԭ1n? I㜊\M1Oڀ˄d@RSfՏ)Lsv~9]`(~[_!xW"[Cd.%Y66[V9:.ϼŬN{箅K¦ܡ5] ?=dntw #>d‡hAdSqp3ve=+ m'p@6і,8ҬCVQ(0gَ^^fE8?*X z)x*_a'ΑB}NG|L}8akFkE=g?+05Y #;eÅ@Q.5lsyrq~˺l|"c{쭻^eշ65Z!`BAARGOiN8ˬeX64yG*0t'1(dWBz@ /#vS@{ctwvj`'!ig/#?xcYga٣h?d5P_ )N9S1~rXUқ(R@Ra,BnyUQZ5pnh+ *v,G)| Gp/+ 3Yo&) 4r6v'iFͲ#jh7Gѱa'jKWLS-0|(/izf|)oicBʤNB >ȺJ@0ŵPq$/^HK옮Oeǽ#gdE)LH7{# 1AhI5F2 0@V5h߬TBe@ڨY)VN!Y)iq^arH6DEcc4Rod'͉O[}1egP( ѲpVs2_IP֮b7( Hh0sDBTGb}LQndn%Ԟեɼt,tIU2ʠ*L=2ه{Qٞ㤗Zf`$W?3,I`FV5w8NCE:KR~o7u~ʻ#q +T&1de a#(]u=10RPgyyz/Xb2_1 l(&%뜞K#wR brw5?7vUʳc$$ҡDFN hvAH1+$VJ!mҕ pNͨ2kՖּʫ; B?SSJP.,uMK%.K _ێl^F)ߖl\_#zg]tad"TKtK10 t!yg}3;ak6vUC7DZSb8D&m !y%ERVu~2,-7RV,ǏݕCL孮Ǚv414WKQ;}+ Hw1=qw! 9+kD|t Yg m 7 ܋Y[C;-Oh2l(.BȠCjaOW+W -=4B !Yu{ V@-6I͘L#pۋFưR?;*& S14 ε^wvѡt?vt+)O  5h@PE#| US 2SuLޘD%:?tq,F$EV11.nڕH#e 8'/5G(KFėn,r> :QQ j4".p% zPH2'On'Z1S*lnk!֟q[@ E%/LA9p[ 1^eĴ+T-w }8O<ʖ(ڍFAuV\Bq;.VJ8¼ ~>b|[Eh?E"!> q$G !lHZ\fW馑%{X5렪'{Ik)_3H4~`I }x-bU ò|LUx$-l߹Z i J#VeP[?5lb6>\3.{ 9)M9_U0%Y;8 3hh-V -t a.VKp߭a jO&;1?#) 6&8 N#ՅU`^ C ^@?AqnǺ-L&e|3nrT] ldGXW,13'?#->\CjP 4XL5ޝ7":蠟hkdW#Ŭhu\bk%8?.T1Es{`6~+taU9M2m_NL颯mIǔa>TlP-rجtn_=NE!m5._u+2̕dvec1D8eޫ/q9@Xv ĀŊPXޓEQ`]-ã[F ~a1 p[+ :UOZH>˵Q;FOudd{ 3*X>0aIէfk'Z2X=A )dDO_bAzq PjbIR)wHC/AXvPpz/} &jM Q $,-r&ܨ}ןdKsXyqYXnBh-;]ELzJ&L! ͅ Ya' nUFZlL3SRB 1Hԙ֗k;3{D5GvumPiA,-Ǩ[gM6 4Y4#II9'!iKHbFf% ]8 lʓ?ҹu[3Nb7OH.Q:^u'A' s/NV;)u\RN/ߛ ~k5("qM&go*;NGv5Jpdo.vFYY$N.]; "(,nu̽}G]lVwDz~.~}TN =BokY7a:Y3E?2zSs[D3G,hZ%e*68W,+GBSN|&EFc@ 6@7u{s sUzfu{3sX?UskR,JQH#F^(|V0J~]bSQ{9 5WDXRqSg/A sU6|&SPf`TB[h mC wISp Q܀~^gX߾0m2Mv/X! ir*@rU fb1_:YNcDzV#d% ݌D?#. "Q[ONR@,XH-30ni_ERwunS*2 9F6 q"m[`m<%KRm:FBgۼehdPoӾXgYb%eόrqvjd y wz~"Kc5n+XLbV"h6Zk+\?F9Ehj$/mE7I6v`apKX[d5:zAuy_?D^\/i姧p'â_5Q*\K$m$FAՙ˪,'-V978[%+ lPڴ_Zro{gnЩ L KCD2.P5u-~f%eĺZs;R˨ts(aQ[VL@uصD."gOʣL'ёriDi8MF*+\K1dS==0d.؉]ϑJʿ!HSR&G}3&gMj"Ekҹ V.#?!JnQQiOdƿ4 Lqf1p ~d"W#CoOҀ {J/@ *}Ӻ; >"`!FG!+]Rs 55aX + 0M8򁜚Pϝk葩a9X?W%)A؞FC '~8w2wIfq"m*/G ;ہ͜5 w[#Q-bL6:P;9C4r<>M9՚k)Ke";M@łWTIY~ s*%qCͭvBu ԹGqcK$p1r(ϼ‹! ʀ@$ƍ'Peޡ#*썷FhEZ>^ܫx"CDz]&A.=mSz]'@p)_keyv Ďy( '1mUۂڇIFp429+V7`Ԋ^G{%BPA$?xϛ,11m|B5MA>2pE̠ $Y?%&?ϴd ^ J%<,޶k']d0O*A$V 2x# g^佯bF,S*IMZf2W7{RI n^M `և6 YInD&~qs->[ Ҋ˹vᢅǐd3rUN :Ml<?D4“:脊9jN8_+ZN x6Լ)nYE6v2M(Ub[2<2P'!{aU}sLPvffvȁo7CuUprK^1'GTYt$i8CW=_ O}7! IPQ YcuXah|(Q'yM;I_tMSMq`aG0b K9w I'k6l#q6I!7;D{h1m7"DC4+u-/XP(+9ic3$4z̕45pvp wv4?q6j\oBè-' "xҔ>J zjY m&4n>ANv`5[T /Fx^5[bT$6+V\WL nwC\T֐Z/KI)j`niɼ'ynBP ء@1ܧH\0Cg Zxg4>׸x^7j2dt 0L؄]} qeO}?gM|== pүJqm?R Z L!1-\ߔM7{ޕZ[ 'bb[3]]!O244mzuBl Z!Sm1P2paa^w;*OaBGB%-SOd3h93z?UK*.yA# };gTM '#Q dEAqXVދXW]ɕ,er>[Sޕ%E=NՎ'dF,79d=O(@@3"]Wp tuq.Bm9]l1)mo>\*f&JrLn6*Fr~(z"`/(7WOW<,9Vz vovF~dS@!bZRCB.*=NcV'N'5 ʓ!u1PUy4OꝝמsQ^["'XY;]\[kYWss]]jD\E;׋<':s̑C3hj1~0ACgS|ts(*-,nW`{[zuex@qM P:7ӛYL*>5: 2Fej_e'բ"fO/P~HO Bk[`Хn>)EYdQ\"Iu @/'NMv0="^0[7J ):-Q97/iN8< sҨ6T[" ZZzi4hSƈ̶b:i0 #0PP yQjZU}80rqb!ЄR 3U(D db/pYҎS|)Tw3J_JR5h1HGv1CiY!gv |R9OƒvnN A;{1*o=Ci?#ơ͋] 7MR/oP7UzA[j`M5hEpЦ_9`ּX+gWBn>SK*;7qjѣMEԢ$ПbXdvHHWKM@&[wǚ8 ls5.m%yAiXNw+Λe2|m?O[ Rcݯ-𯷯$oJI,>WRިA7v3_ tPwC4 "ǭ {-Dq÷ZFƾ{X)AobuO$;*%'RJ-Ԕt#f:p"$>'A募b8C_!E;LJ¤GW][oS|mae?]gg }sCXgSB\VcSCLSiˉ[ /M\& ~HOʂ]˃$㽕 RhG]QY.G cՂȊ= 歭$}M`n4œG\ 56Ȣz}VX=?wt5)ˍ!_zk3RfRtXv{w4dE;oDS=r'M]N~] }K"&* : -wb agX ~dQ{qe$sWIղISdFk[5f, b Еr/zs'>]Dw<Ї'/.s6Wz}&'㹘9+Zl hLh}3d倈,TN!_y ב=埘әiG=dFѯ ɌV}T /͜ æx?4D薠TMRV\?W*i34z8(ǂO2?e4N$%#"ъ3R*>%ՍeX 8"q QK1qMG2fa ICo`#UX0ä7գ0h~ (4аm*2 ǟ923^6TUUf/.+ygI${)vTOSA0TjRu)[դ3\,0H(IhpN2ίݍf7M} nY#wg|'^uM,*o;V,L;17[pѝ|)bQ4G Lr3M=10xGJH]y D_T2%8[=ءgZ ͝uML!HAG(N-B^60{0ߥ{ ҚBU}iU}?[eU;Zs^~@k^d?WU\1MvwWw9omk7E6pKnJjG+;r=3S1q/@:xJVtӼBe'#ᐵAS,yHN _?O  bV JSa\t; P]uM )BK5=O`ФY8-4RMT(CKq1W9DJ&"BK&^}MS^R耳XfY\Hyq:nLBdOu+{=JFm$XxοRfM!sfYmhM:繀ӭiˁß cފx*ɺ\aV;H+ ){Zh&ҋ QHO"(1wo ku,sFB@Flp5Zx'\ef\雯*_MgcDeLgؒ!-{5ԣ /6&ґtvt;Nb4JVXs$@m J:K kjcL/2Ÿds/CZ6%Yۜ>b\T7(Fh9[//38;?Bd[qtU/iQ]`w{ RT4m1_q}P/w ,)l,>WV} 56ײӂʳWo-5hc(6}OUXhzW"2gVI1ms1劙63υ뛒!{vLzxa3*1Bdk+PkCR! Xln+9R:%dǦ(Eayb) 0 !}t'8ԈvU`s蹗̩{;>C7Їㄶ^u/ai-%j8ΎEVU+(G$U䐆' niMٹCf# iYɇI(yi؝;yhiN+&Pr9ͯEzHKއ*ưLWTݕ%b "4d X٨S n uQcu0Q_3u` dr2SXz!8|,U~O,AǾ[ЗitcɱͲRV/.u=,&O䙔JSUQlx'cPz%b[Ck[]>5PQo%$o+hc!C(Z_Ȧ~t`3aW~͑{;JEԆ,Roe|Qs_/wmgIM@x"}TY_lކ^LMYY-8c QOHXI >-SBioÐ2HgyV`ؚɬ҈f%S,yᦚwa]r8Ϋ@(?//tȲw"Bn-GkE(J\n&-VFWrhוnqرMu9˨l8t-7](JC=Ӡ)S)e_(q)>XWhjKAK 4i㸫N +DCpcAh wA*_1["$~NM`iqmtrMɊIX&wچ q7aes|-iF|a˶ יvR1$_ y@,@xK8UH`  EfF9!S+~"Ͻ)݂SON[f.%~g%͡ Vm_XmacLѬxѹ0V0DEWp "nOfK)5`ly<牌 wҲ>v6!n#2e3e3jvBbqdH"}<wo MSګ_/s.O/(hrXOqFWEԾPK m-qmS=.uH;WJɞ]`G@",?d]K3Wpb쎔YDz[bT#nDWY>'+ ƺW2Md&q}D?Pb>~6xWɐ\Z;,ddUd:,f8j#'ZZoQm#ԙAݸ4Gf9uGl $F")DkT!=FcsAͷF/#αeT(]CxWq}3 ш6rbg FuBTgpTacdxA[q)qd{еJeY2~7r|tJْCN49U.}Heߨ(evas$g'li; 1H\[åCCHDE$ 'A&n k:f}.o,M]\M˓·DhyqPmujs-p%B߸FG W=i2{CR1r&4>-ĉokx/To9-Lt1|."zo-0m5{_w@g['qՇ@G%\f𽁒y1Cӡ;! u; Yj>s!Hԩ0-o. =oGyK2~Dn,>9]zjG]ڭ2[y3.8TӜ2S=tה-~KVˊpMkG9,b% oK͑ʡKĘ&w[q0ޘ4h޼}Z08#h'n)c aCYoaiheIKj DC]jQn#`((j"mj >A7p >{[I||bd6p˟#3-Yu]뀧_FVVv$X&$֧̺aTCr Wy6\>wacl4&qt:ܧ/ GZ.Yl4kOSL-VjX5~G"X򈡋~8<2[L옹H_8ج\THK"?qV&ѝ_D 7Qu~IE\:/T8w;^,S9 kyVGtz9ml\:{%+߳+,LvRtw(3#3wy@,K.ؾ'j11e߰Ȝc$li4M(.rni_1鸞&^Ǘ4 BJy~ƙ J\)xLaʲ %Yie$|59f/PG9=j}b*i_p롳(ʨX* x f +}'E0-5d0\DBj!DRw>]n]/ʜ"5bqTĊ!3I;6C2,/9FvjO[}6i{Kٰ α0}Pq=LFH\|9O/4*eiHmkHL'^5Vwr2TZsT T*,iuW{g0hAW)c~]\a#A^.9b)%sfRʼnW:ޡE32Giuh K? %h;`3tK=zPVI}7c | Q7_ lv=U+y*f6&U!:-{VO^2j{] 3Lp/M!"&/_7XJS |t8UMWu |c\rMY0Ad (D./$/z~-"n~iZfd߮7Ҩ"Ou'HUJ. JFTDqz> py&ƶ;`]ҁ 1 QkCπ`iK:.opEgsC3Fh'# #FdMki{d}b?9L 2.zd:Ft9~kC^휧a y|h~!ec#򌶞ֻp9F><\yc>+_x8c%1ӯ a],مzün a4[̉?>$Xqzt Z#@`6[<*9K*o1ٮO:*Qg(AH*tD?XO ky+<ݖ>d4n }ή}7-/u$/SJn[wۙEH /[ykuבpB#ԉ!JH>əKRł| %Hy+}gwW 8|bH/a7`7Nu=ELy$)} ޑ怦R }cjH^C.OH;$ P/O|{|-䡐 w(1jVLGj@=S=bkC>5CG`V>4Al`~uG/`.Ե9ڸ7V[)`*a%nj8cf|xP':Jɠ0'plQ .43W9Xs  > ҟ&o<_]6doX <0N@G` 3}C 6}A2ݢj{1P:kJSp4i/Bq:GTٳ^,hɲ{Te`Ϧ+m@Z-S BSGANj#cś#aD*:ciTw1J4>+sO8CncYLK;s[ܴĽ ^<)Y,%si 韻ڗۛ@ ƾiPOr4]ԧ  $N2uG3鱢tm@fhmOCX ~}'RStUH]3;'scD-./)&FP)b>_mzπF]3Wfbh1tŔ$\+S6`p5ފJ!wa$/3m5 [rJъ;hA VM/t~{xݲ,|^öDtL*pk͠gZ 2E+^rJ ].#t+$b],f-A,ڑ/JHCFsxxϠOI`jfdKr]\}n3}"iXw WAŊ3V̡4v^Y K  ׵V~2vLtUbTFLAE?kʼP_0~_u d7{gOw[hAb2߼uBh>"~,W !?tzqDpI߅wdʕ"P)5?bAn 9=KI`299G_(v> 3}c hkď8g 4 p.(dUSU f}bBzS\f-NTd( ~363pCREI^n .9dqU:1x>v FvĹB<7<Q%"ͪȱ VE <) %4Ǎbu^O)a}Oc ]BD -:5  ++؇&+qOF?VN+6 F9 FC Iңh+v0+nݢ/dtyҿ+7) ؚp^5XUġ͑l)/,4!1eYHkpjbm-o?d}%~AF Fgp. ^zu9A*h WNLB! z ! @1*2'13JF寊`0g+/Ն9R$V}O:XaG`%e0LN}-] akhei~deDg4;H斜#A֟ZM{[ ն GuZSЇ!l'~%t5*Bh-jOM; |dU*GYttt fkzKT@q 6bH:&jjsgAc={FC}[MYU?hTuq͇~֩P !=`쨎N6nUI|:+ﵰa(q+$ȩKhoή\'"s\#gW& Bzq)!ik:GCJldY"3BtU䃪Co㛽i:sV}糏ׇmhrS@(\&YAH2)kdB3DF} jkMUg.& ] ۂvCYjhpZaj,'j[0>nki$qػ"^r!wz2(+YG'!+9VYEN`EqwRJ7Hc[e}krJPe~ܰEv"[znKSc]yq=0٨3:jY"`h]wpyNBѐI]6Oq|VJ3 hV{ZҶLAδFyK ؞d9JW^_ER0[ob&em AI7 oU)ϝyg]iN-+)r*GMt1g~B'X-$ZˆLb&n}ObhLUN$F'RA*Y 1:.A Heɍ|O>^PSq: O!qk'k)$B1Nf\#ZorѸ>~Iw]D['x!5~ISNHjy;&z\IFq"ݬȮ!nsLH GMDgm UxHņ/:p{$R Qݿ:9qBbVT1s'S.l(W}|y@Ap3dNSXIi{^ҩh>UomsOEc'h(E^F?\RhJ  y.@ЎX+FmDP 'з(¼ĝ[Dg0"at%URh.I↠XJƣе `f<2<7'YSA&~uޏ.5wS}ˠBgDhlF*2ߵ1%kTYP%&YF]ekD|`$琄s˟ivR{Z!T#l}̢2&~ <3I̩U`Qz̤9=!m:Z {؜H(1pcuAgnbHpM^ڌ =H7tDO8p 9sraV$dΕ%TCLR*`l5fuWI%i#vks7ڟk뗨˪UB,fiԹ0 +=\7`SR095 pѿ=IqZ 8X1U>Nu񴜸+pI&&='Rg-G)GS @URB?iW;Cjp7["fnc`bqj >[~v oӦ r}<W5W5͊ntGJ_.aPLkJUӧh//u1VYܜ8Zئ 2r:Oudt)$@ )auiˬc]&3U&kA\p{@n.6ћ)?~>~ âi$˟Idؗ=9KCC/K|a~^١PM5qy3y)k[_]Y1C'<5V)TrOLuc%q?gL ږ9{+Z@Eک9 !t ~:D7Mk=siuXn*J^[ π3S'Dmc)AK"eYUGwx? dJ*\afȮ$%%aBpP y&.i#Ch;hYoEF53$ oAs.)0⋚6NPuաۗ[PZNIRc" hTUw!Klqi{xU}et=%V\TU?UfJۗunBȐd\bV"  kRi3 :՟@Bdְ̬mK#Ȏ/a{|)H]wBoɔ8ER*E,M%tB*0Ohwdk;LΌgkkbB{H/G*4dp#IDe+{:D<yST9]SP8u$6"FҘ1#9 a%TC V+;@4#W׮%txIg4W+ќOu&139'~YيMV$t";d7ۢg,KoH~|F#_.2P_U@H@^S.&lR`eՃ׹:zG$}o!R{l'UKOڝ@o;#=@,];/#-M#A˄&; (K脙1nϤ ;`#L|{X,vzZQnҎwi+\HH+(P])ȓjH 1OLyeAB>F`lN>7&PqSIP!s k#2s%׎Kѐ])B = $JˎLߚ)y*(w[vpu>)O~}pis*5nپi{MRHy_ˍ͢jr ʍϳ5b{л>^|Hk:Dvכ_p1p!EpT 1+ԓFpӃ?=w\=ioh"869H9# ](ȺCGP껧f!9eJ4{#,Q?çC#0c? xa#Q#6}RnHe+-QIB@ޗGD=X!w p. |5&%XxtK0]U_Pg*dbۂ*} Cq@mS>Ұfx_W.k5INnk 5SG4rz{Sp(%Auh*@ MoWߩYh{geM[Nph {q^8vs,G>m r#m$ "Xф%s3z>Xh>^YSfgO$R,4%qSzČךbWjcq˽+  ?N S[h0Ђ$5N2X'Nr<児(Rkp(\&șav΂n_h9d?FmEEQb,Yw?/C8M&~saQHx>⿃6O.( EJqY ީv!6ܲ_ 1\+^X:Y4gd( 5 &$&ruI6{z&=gFtp(e$g\$俍?5P8.HUGf3D`; ZT7'OL\!wdckV}|%,eO @be2|6ݫ``,b)T>pe{cw Oĉ԰H[ӻά ˕?# dfATMd}1$"i^~m@_'Ž`x XbtcU&%O}gR(TYݯ;q4KF.ʳ]*(Q?]6 .toFV@! fp[HrUY|kΰQ`0+ ՗YWz-(%0S n]o|S.q띞cB݂i7U0݈EQ=fJlFB>Y;|;]8ٝhH Da6G11Ь2de 9 ū!nƘ</Qۚ^2{.`~8a'1J:6N jBV?&@n  wJɕ1m '#Ox,R^PnZY"_AybcNxE་ Ơ1MZ_\p(JBxEK!HCk@7*޲a_eC'2R|o:/7&:\K͹p6 X{\3.Mb]Z6u4k l;t@5|Ƒ>Nee֍}2{xtm- ağЗ:RLjdOw=j,~-)?,uUsSlnGy((L SY庖vR™گ#pQw7G@Ƌ6QRd!n:a\/41x?/븶sCizYZgP{hm=IbJgBB_K c;`rPtL&O2u(SS6՝p{\th-\5}j>15FDKi! :cFn ֏ϴs[SdT*`t1o*Ļ\p>XJd@q k zNՑ7a6<~ Pcϲ(,l" w^& ggʫ`L>H&x!!j'ݵh,`P6J9FXZn"/|{9pl:wlҷD^Dy6o8&8ng' &;!#jJ;t# ڀJ:X}z 1Q鏨 zsU(s~х:nK9@ ًjMn$8Z_S=U}nIJ̿ag{0ׂ+p=<sS0^`<,XZ}vf}kfy?ӻiTudSvxi*q'vY͍4j.:C>n-4J?Q 8x; o6+w%>x)xad veBTCSJZjy2DZL)$"FשbX  -g3:1 x 4Q ~xLpc[*dpӯGXh!>3A/'ZjZnN7 wC ,[ 5*d1)h;EViS8\l&kbQ=M7%)1/Oiz6tÇ ez|p8x\it:~iyKP!eGGh$&&YMٙALŠ88P "ԴB2ˠUG{{+ziS/~s/KҹgTC }92Lgql0O8*GZTXkܽC8i|yj_–Q>0o܃{pw( uwKEIRõ/YkZ[8U&\QVqU@mapQ>V??"?eC䝴,fUɣ; :- u9yto|Lt]'/]|XSN߱2mJ3qbhaN|p#HA59?aX.Ukk#T?'DN벾6VmsO2AqLNDG67s j)n'tȷ硆C (&>]d@> *RҸ]Zk'0nשB'YT7HpGk$-G^%k6V FJ)U q0}+qc6XkY;tofCA_P?E@z)e8q }Ҕ:\"*`,$-(@NsĄ%z"Ӡw^cګХle5&X+`nZ绢(`n YUs~`A+'GimtMΤ JihL9u>gV)S ^3 c lMU %B/ B$(uDH<|8 A^oo,aϑ+9H!G֕39Om"\JTUJX{.pa]&J(5kzf "Q[^vRKUiv~d'xu/釭w*0:S|oD8_GV{$q9g%bqO k,d-g^~mMob, u1i~*7u^:{j_M$d$ ߄#3S r꧎SvM03EPy()jڮ-g2Х4n~>![; -s,Ht?3зc CtEs;9 &9-ʎ\{̹٦HYr> 6]~=Gz `I)YG2;)0v~KYlp ٝp>D5~b:y-gT 4[$҃M@%a)"S܍u|WMG6IMiA)Á4M^LI>{!C&!k,@3F/y[u^OHlCOG=SЧ-@'VU1h5lHo@7qq;vi&Q&C{@2R߽2싟gpUB2BOatوTb=b9ognP[(pa֠=dٖ]lޖnk mH?HF$6=azY#`L$ժۢF 6WLKX D.Ű`t!^Wr;*5RWuu>4*i4x+1.;;mKVn:IV78giP:k.v.1aa 㚸Ex:SY"hrmT[mj'9/o,wc\43isH)eQ! 8Od2r )%P1jDĿF>Thxj>}ʋXHd.+h ӊR\'[!pN茑I'L.K1D}аH dDwwq )W#*g Cޢh)Cμb+|D ";+h yDgqt"|I|ݥ^O鉖 ~5 tTrJ~'SCW ވ3a/RcN$&IG059|c j QɅuvx(TBW|}J> (uFK*@%Za'ŚB jxV$9qCαv>ss);3S.Љ_H^kTxiHiCՒ7 !d \mD}Өatv*0]_`bJxR;%J-F;FWb7##.ɎFE%~Džv)&|Okd[4BᒂӤ8Qm*5πzdrž>ki ^EQ٭mQ&57:WK3 544xȈR|ovϧv4!Iu|aͯƒBTatSKaNT-+d`ZC;n CG^E+ƭWZ!<9n6/ *GM4K'i:ZH]GZ%+y!xoڑ+p\ήGk>iFY]Wyq7S\ƹ int[ݏ\1|`vGZt;8#GH7BթVH~7Յ$Ǫb5yJGg~~"ͼH6!ΔXr Ϋ!Fia$IAJ;y>7{1̠eYn;SvOni<7wbptʮ{=[r`ʧ$:, +rC7Ϡ]vaڰnjG"RX!ҥ ygꫛpq*+d`a* ~8& M˿׼ZzfN6m_s$.\= ra#s+UvN_:2hXW$J R92]{9om^lpDLT63+b?5nŮkT^3af !}A!%K&cUɑ*-@sb umZ̈́wp򺿮 Íd3r+ "xr!O8+6XD9 XeKy=v[/zF|E{yy,hA#jvSIMl(Csك}$!M*jX߹Oťv+W1Nlm Hd@sf_2Œn&V}mDqKTOu~quʰTM'itgRd:lbXCſ 17A~uil83Z..q`nn$dy_S'oPRB~QYo.aIKqQD5-vFbP 4v3dw1-7/$`?2-kIvi!\e4qyZHN>ƌ'`ٝ;)t)U@S, Q;1 /QF1?cuэ>pGxdMyq$6|l+d k7KTLqCm)O脑:Et ĭQމ+^@3q7|?W["Akݮz=@xãЊYjTpߩ; 8 ˃QˠVoOm ܣIs GQ[gbǤigIب0he˜ #$&\0~X/8kA >8I!e^b> k#1Jǂ sz!|m|d |1<. : `P94l~o(],S Bh"*cKDrYDcE7/g˜+;4 M$zJ8p{)ĽNϏE n8ŵqzajBTWԱ'?~oyceDS/N)@™pN`mPA2hUg SG e⩱iҺr7]WB:<M nC' AUlxu,G69dD M`2QǛ 1˿Y)'[S/K&6 3]}H]zw[/; H,A7LC}ag_sGgNP8,rj2rrcaRbpY_4 )cŶ0<ϯS ZFo_N%.9bTBX.&q@h%D"#ʆOzb';Mݸr ֍RD츝W q| W:2L0.Ț~'TځBsJ^$P1L,ᖖWuvo8Ih΁Pğ5E4ތPf Q>G0vHxQX /9(q;-~R00RwȰNTRkyK愁!JU@2N:>lvNp#io/F\NRG߂fNs)vuЏX LEBAw”6 O\b|3*ga)C2ʍLM}[4.KC]=@ef"b7ck1@d G<OGFھ7aYCH0^_M ^A~;:dOM7$Dzwk%z`?rxf03TwLj3W><4b t>b%{#3Z/7zDOa_K19{n\DJڇH\8!jP<#z[];~J͑ 458Y9|cxIKN&բ_>௘0 :ϵp$Q@bDw~gu2[6+#.ύm -yK@*@~ԥWXn00d*7)FxM񓡮)#p5,>:Yb$ЏP\\a4eXKkŤ.!B;,r|2"NA-d9ť [GNL#'܃)*-S|N(ƖYYD?Ґ,=X| y8rtP׵A`<$CU71:i,np&TCO'6y'M1@ OB^X\n:ޛt=͜^a eM!u52ٓ pvօ>R瑞껚&9̆) a-()s[;Y_h뛇s,}ĘxvY4,!]_ak%c(8;Q-/"=4-P7d}v)"헭jïTg'8#2w7"ħ2E$7qδŻ6%+4LZ85;jC.<,PD15,ZKKy8hakcLYFv_Ta,1t7QTlB }`xT4HcAO >(k:0a bi.0L\o9jiE;~!Nŭ iMFa1=E-N?<1rB.r@~11;>3? 58 K/M׽aʞ@8~1iϥM [1/kߜlBwШjhM~4MAͶGC(a 3 b $;5F& KDʡ[/ùۿ_T>dQ:«,)3{y7 =Ȟ.$ネV5w >\J27&xb^.,3䬣F ?޽u6£􊺝|"߰8r_%{4_INnmQ6}5T(]A7FReS:6 }~X(D3< E "<H,k;|ܺ.KeYr3cp mqiN4MlE lmp4B*sP>e{:M+$-o Pmu'po&9+7A[OIV) w5\%"4FN˅&P;į2Q6,48шJM8|F@SD#P j-$ކ>R]$mqpd ߨ4J<+{!OWZpwa9]db40)|E? 3IJ9 Ԅ:(:"`'LǛ=Tl_ѦzC,1 wu<{g~# }:uR Qif/SQ +`Q)=\$'>)6VSF|Vܨ(iV!Oۻ`Fܸ#i/3Oqr? ZB-)j;c hXk;h?nʳHm+yj5zkNȿ#МcT4w KzTǭ] 0J%]f{ERRyUlSELGοceG2pc֍)6BV1v%H4UͺW9>@Z2w .xs aUts)3W*dnRFm&nϖ[k~;mGq䬚uvcuA3ac;ŊϤ yHҖT>N: )2xqJ;x7] Z kOY\3/^ \ 2BȖyߨ1}ϛ0U0*mʫX@K W6_Ƴyfk%v ]LMCC|EjUb;-.p#7}cM~n -Qg C ´>IUFMLyOq%ٴ6%o&[8}_羐m!]e^UnⰸE(4X42?] m3m FlJPX{'MX*5MQxm4O%9ǼmB&b8&-C.gmUHeu:rSr YHo; 5ܹ4l9 /vWVfNdȩeH1-d3(z I<8t8DaM??a84 :ykU0kO- *wN<j=^5GvsYuJQ /}ӒA9ُn9[)Qt+vF3 Gf%[d6-1h2I /BSՅ ]<+}~^3֪!d\ Yܼ[ow6G .(ZBJ_㕇f1 I,K>,?2樋it4/ #B:F:n1釽="wl+uBh_{UR[X⸃!X>_dC, Smj 95R)68g6{b*`I0rm4: To<'8tq0CׁDZNNYƷ+;fFfSA%fY'wA pȶ(SBFSMTNq4gTuښox: JwmReG۶/|sbn@ͳVPs[\~|58Wi;ifGze'o L͉]1`Rx` VzO/üI,GFyuULV_hEm&Lc7HJ!SZiyc0I?hލqҷ&ișۈ2/N]8ة*{# ɛǦ"k߂3ו Cҏ&j+TVȤ``Hx&=Vj]6EhFaXDWҙUfy1?y3 ʤivbKݭvz \}1l^ 2hI,t<#IrMMC"q< ?n͐e)I&YrM7i4187=P똍BV`; $˨r3i=ZWq"OJ[Tv#JIn$: ޞ,kk v286c#nSsJN=O;Xih޿Odu(XPM|br,l(Ns^;u@$PUesk/ݧŵ=SdtfG'$Sgjzy+2lyu{l$wNN(x1b׶!9_;Otς9yLϣJ|2 Ǹc߀Z9c_;:i>&\^ 5p%KȜUXG.3hJ6RA<}E6r.J;¯W!3dՑ{}{\w+7GJdT2 ٺa2PrN z\~uF5!>6]nP; oB$$=lm޺5f8ʘ(4`䨶[!T=ҿ JO׽3RVf'T iS@kxyiwWj APC;.r1ѥ;d  =T֘+8 y;pm!Th+T%V;|G9錊'x ə ܿz+ r2bѼjt Gye9[ajP m){ V/-?1r Fb7x^yB쒣a\,?7Tv*ꉑz'iMg'ޠeW;1 x8tx!ӛԳSϗ7T*5  Oɼ+HG.ֻ/i8uLa+)y K!ݭ8ˢ.DϏ 8SRbx˼uߴ4sz k'~GC+n@-`ٞOITPE6,Zѕ nq=QdksZ뽚 WF 'c,F ;yٳ4]s #6%+=砰S07n+l[if銍\^cA}P}7v<!  h`Xz7Z>Ś rT(kG˞msֶQý Sc=oyf2sp$e~MƞS5:T$,E^d [0^~+t[ ō\EJrfM4U}Թ\;"df~ +d?b BØ̼a-S\z#sTV#X-jKFV-y=w wj,3mSdpP=+#VGv .MQ:(!8!7aSP!>Y(.~.QPl!rĄX*gIJ>0n$/#vۍFhw.\4N2K>LϜE`C$+F ژ?#}GUN`$n_Zf"\yi>LBAV)ZG=R2 ]T7h[Lì$X{40Ka_6_|xL|41v [A{QhBEJUD@EBh!``|=خ9Uw%?瘆iT^rNY.?,T$Ӧ ˻ΰD1HhGfC0A9~0$Mpm!N3UPףڿ?g!df7y+;rؔ@+"] c>y=~ dҠ4 HCcáBOyħ2'.̘[|/@Sj!ꧤ.hϟFVҺh!; yFܳ>WcHIߗ~< L |&].!C&c/|puOB]M튍Ԭ< LT+Xj Bt,m>9ZCƧILgv_\W`;7c(于`p  s!!\ԤxoJclǗȑ4cA 5)*[ }!k϶ږ'^Ğ '*#)'` fysH5V0ElSAlG+;:+s m<á')I> 0'Q^lL=dT CEjA:N?o+XT` i;p* &48^Q_BZA@l&I i\ed!ɥBCӉC/# nhcɘ1? lO(![u^c*=vΐ7%ưs5^vxѢیӌ3A p1t0;HQm5=KxK'ǂ۫ eƣNhjD$x(W9n%_9Z,iX}} K#f) Ss Djl Vaذ"A xh̃'{ngH8ʍFG^wB,XqK4ᷮ1РMܤ+%JX@H!" :Ż0hzU)_MjvP&`q=ù eW^=dQW%.0wm&#؏m/9,޹63Z42 @gkȩkws]o<2n>"DI#kg{oř;"br@iW%+=qҬ:V K}N%d 'ǺYɾm+fx:1]65=VbY  @0ٕ]$?Ϧرx ռ]]OjonWˬw3"/ ewHECJݵC"}`ZhB>uD[8e~`!g=u2耢xe[O]5\{jCẺFpEڵ/5 Xu:6ޭ8ȹdyHi[,0+42˭unR61CQGEqҲųL25B+Y&T!cY5p'[L NOLZpLIy?>9̤ivN6χ݉5tr*nE 54 bc3T E/=Z7Npў߬4, ^ߵO/n!B-  ]XqNn1W? !e3o\gטʰ_FL]ZϦ6fkG;#p=HWkZMzɽ*\AU^s.$5Հi&rN\:m !Hi4.VK9Ciw@"hn [-  $wmN/r!~ (A6.{W $W 2qj"5J}aV[èF5*,LލF{ lXavKo @ ]lXdk>?`U[t'L0b陚\yo>ƱJO@ScA^o.yEcGww_JY>4KB $,cӗe#rե<ݳT}#$ôw"(IJ#TD{ƛk ;D [J`+Ѥ.=? t@fJ#*hs{'9z>#$c 1GBR/ܸr 퀨_\gr^nnKBkZHJhTaL|cYԬa:'W! RV p˩Ki)%f yD_0&4$> Sk)HS播Eo?>J#pz:J|8K%bφ!FݯZwFIFbȧ>>.Y4D3)|sm0McˁԈZ&EWrˍ> v&SAs7 !=V$[ȧ8Ɣ1/)l|[1C,;WO96wܙ)?+#nqx*ޗ+h+IgJTY>͙Yꏷ=@G6Kopl?dS nnU/, $@[^\ww[x[A@~oUeXЦ ŗr]o*652,ULLO+*v/L!1PX'ՆmPA$1Jd^e z8y؍sf@r i8* F*V.=yYL+d(4 _ b7REjp'm*aX;[] o9Pv3!$;c_3k-7$R֌uf9hP`뽅 qm2hJ_n̉x ֔ylA9?rjG/]l2Y>FMHTaT`v8۬"w bͬ{ل"XЊeW-ԟԩqxa{v>՜߬àŔZ_%?UWNvz4hċ)p}7|=-w9,z(B<%unLt  g,y .$2ǛUⓃihLװ >3{#~=2^ Y]mWS Ku)P4P1ϺvҀv~4&*KFc|F/Ґ^/ڀ5w6 V,j yJĻ-7U:'r-X YYb v;  =d*"owwPǐ?v\~rJyKZ1n3#7ks]B JvOi!RZ=dŬhx,=H^)MVk'!usɌb3R;G Q}k\eo+:i(Bb)^/t ˬi.X(H(.ro *tT>SabM,c{yl>eԈ`09!}xGI"? )Y fBd )2@bLi5`3{SjJŢkimR}MT_:)G/4<=$ZPW v;Շa$bz/-.r j4v9$%'A\~_7KQ8X7f4e`ZGWH*"C+@?s.:mŠeȞxxlM=2H&/-t♀8z_=2Q5_nJs$Ir~^vV ـ(L٫ Ԧ|ޘo-w''WVe$kk;ol{؉d1˵n}L~Nc.H߫"2-wQTBgȧm90KPOb/Q5LE-{AmA:S~ !*mတC`luB!D _Zz-̼ rn.ܾBL/ W?KLcqMu:$| IF,\t븦s/ˏ\cy e/ɐEWjZhX TwY1X}ˠ *& FZ&R5zǩs¶p5􍷚M[5Qf oK$ϊR?=ˣc>q<fÏ֊vOnu ?$?:c?AQe`{G85<QhI'"^˔U< lmdξr!Ep"/VʝYS!]lX1 =XbYY8kyg*|u.TJ$2Mϖ د9r%i$FJZȵ)`h,w"BEkVOl((`x*_~3)!Iʡ8w߇͘ f:[%{-( ɋs2LQ8z!R*f6 "CFVj)g8#T蹺 ~ o2_tk~)N e S0 !{y\)a!Z!?ܳU d mi)dSspKWdp MO +Uʎ]Q $ \Jm[a JuRA?옭ϢdhZb]-xts1G5+\1])m Z{;x}v&EGņfooi/ONj"Z U1UYdc!PJ,Ԗ G`^hy "l5̋41 A|&(a+0hdmK=Oi L(xЍo6TgSe\qШc^~8hO NA MʰI kaՕ ۯ쫠GEOR@m9 P;0 EI ԦPjV= U}&sGeZh`üU{²)ی!8JIt`&o:%S]~ўyzc"EP2axV "NǍjS6N @7' )+ap$!P jBJ&+Gj(,#w:?Ze5?gW$d|zg[,"AzUl*i JzK/ԨԀlf{!#BGH4RĜ}ǒN`-Ovοp7rsxm[ו9KC5xi{[/q hyEdqt:[+qp-? OqR,acF f~9@zDRe?kQD(x1?jb÷k K+Еd[;Er^93#GC' 6[~E 7wIX8&up$~HO mϢZˋ S:-L>ϵLpdfmu^ XױMњ_(/`las ilD/B oOM##<,k }/L=kZxo妳i!胎(p¼mg(<_2Ƣ_p_0 &V a+SfGGHGRA|X*}yCÀCNYovo p@t=Tb'7l>fљLOCG&y.y2ŕc%o֯gw5vIaL* (J#sC|?emY|c2 3:1t4Ȱr Hշ?ʕ,~`lOŎ]Fe؃l6/s4{zd,9 h-)cs#dٱ:n Dօq</ e `>U>yR/~K"*iXnS2.V41Ό,'ә~}d J״x ox >^Ath" GO$9+˞r."JvSa44cfvaїGF,$8w싏BA-&Z3K0079願ad _Bc)c.4O24XmZP8ŷrTsk[޿S\OLƶʏ{'t,;٣ne s|y*"C'o\MU)E=icDͺ&W 23|u~?CEoӿ[b+Sbey}JGK /(S o:Ké̉g0<987IJ\0hZEߐ$8Y^<$!/̓$\+(,g%wXti⩘ے9L^VC uyP;v^wslBj>ޗז5 ݰ58 ߾-Eo;zyB} Nwr){9䡄(Op|.ȑg5zϥ9Wt\Epa*wȍH,1_"榳:%dɵJ6kymwY<bߟS7Km`r^/&c\*zfĝ^IƔMϨ/3AR p?#@1L(a6]~Cɵ1b 9/ zh(Y)0 {Oo1u:E- +={$tExu6IY-'xMsM(h^V>! ; Ǡ{Fգ+C<6(1'i` iVhՏС5ͽM.{h%9yTb 皼P l4DJiQ*bu*E@KsthX7BK !:j6c}L4 5(2T!3Nw>ގR!ZZ/~6HLM=XNR,}}^ܐ⭴tKrcXfO*٠f;allҪ]tIIu{pZy߮@}#Et+ëuF >%h?iI퍒q@|, @S#~)2⬙2=I \ӍD] Fd^ TbtseP3FY Sx/@XJ##y R0TdM1Q!:S&^wcшދr)WʋOk1U="]:aQzކC~iӻJHY^xZD7H (N},+: Q1l}z," ]ڛ—OVߤ{!{0#ie\; gr/.$q9(*[`%+k]vXwnm-*"9C4`[aQ:7>A۰AD~ķk$ (!p@b~JX΁8>ԇԱZ*~(foѡ-u0x# x $AP9[\Q(ɽHuN3pe rPa̡Jf!]o~)ɴ[.OrIvч.9n$<4zs(3˓Hy0wEn'-2Pm~3N@ZaWHyb1Յ4aO2~r5!9%L"ӯpvyj$g纔 D` dUP&)11ڠ n(QL(y.+(^ONfp0WjF,aY.V1K>mzok󖘋f@nc7Q쟒lZUp|mHiK• /FPHIfG9[@;w$Wؘ>s1]~A;t4M t~ Q ֋$R٦C?dR`d9d#DKh/Ȓ*QߨIQ%㪮p|&2]"8P4E)s.%O7^B[/wHx[̙4+fRHg1{o=+z:AJ5>f;6't.޿fzp/q3PXDYO}#u wxR[>ȤƓzWEfG;^_O0R`yMY̥i|YkKSr.`_"}qG4X 'ti/fzt!5ڃ԰5>E((q0rWׁ0z W L޲:`^}?+_@܁pnYoζxx{twY\n- uNgchk)W 8iofW@&/-a!'!,o'R&oFC8 _zgANmak;r Ϫ:+ҦEϓ3Yv5PcB>M8-!b@M)Ԉ.[m6ֶ"c"n5\p@5il\ndzrt1Nzhr5l[.]rVr`xPqsK$UeQ^0DhZ_[XDu|mQg&0 ۬Loh]B3mr^,"BBFG 7-KF/P(և e^W EA=!Ou|Eo(( Shf2참gU8> zny)p\fK1[$~m~c|gN'FFBƌbQl:ab׎wc8x6a7K?8#/Mb HzkZQ 3ft Xmʅ*/۫[z obtl N(\-y=[bz ^+4nLጉK_pOF$ 8׉ϜYjTKvG$˦%kRrC5@l]l,,25Ne h:I(&NCI@=(cL^ &b?P*#)8q8l7=*S ˸xám}7׼⿌c_<vow5<(8YPksgdsݨzJv KZt7h!M{f'fb]jv55}o6QSZ~\iOSѷyq#2.&//s [3;us `丕 ۘz.8rQiwijA3'5L!o'lAνlaOX2Caoӝm5'1J\[h'fFz>KmnԦ-эRlF66 /b\ g xNJdQV !)Ml)cSxβw^[(bj^ T_d~А{9oбSws/NJYػO=Q2ݿ`QqnU8bj]Z5M(Gk/p\|]Wc=v{ (>ml(F\XӃ&MQYA1I. gkzL=9@٤Sh7=D FޗΉ"#C$*qfV T]BVU&m`U#wI-'.MAAy{!jbJ/*iD]3ɛdAтNǶ{::,=W4C_~[Zq xΌ>k?;zQ(FƱȫM&G34oJ5Ċ~n\ERj=  1h;]WV+vYfb5/gr{/6Ƶm'a/:AfլgѲesseʮ;v4=1WaDb վX@35ζe].k 1mM|/V{n”2!|guJb9²NSs4Ҽ;DcfA%ݸ}Mw^X 6Q(Zq9Z"TbU_sʘ BԜpw.7}Ƅa}+~z.OuyeºdMF;ͭiutT6Ĺyb:*Qc}#ANX">=&l^^眙ի#yXGU uo9ߊc=+;8f }^=CNɠ`Duvn ӑg¹8?ً[7Eȇt9s_\%Q܏0(h 4B{vַzv̚Y ǯsG*c|+yCylb.h&vÏg3}YZ*mWt$1[2aڳqE葎V?bo-ϟ`{UV.__q{ZbHՙcu <7;2|fz'=8'm/Bp #$ ?OD Gr`p)aAK4|A)o| ̊犭5evOpj#ڪ AʹuS?=Gm7B` q5G40|/$#|p=&эU쭂Viȗ5o lsN ȁdm_V|c@96v DY/o5֍qSg oZw"hu}}3XR:>2DL۪E,kф!BSH/fk_`v(C-r|cy#td؏O۾'ULI`e8?r"tt>:wwP[2V@ sMIl/t|aI, Z6mٹ06_`teԏq&jnËFhL::*՜bzcǻ=kgnU}JU i*I;yzoL{eT?Q5a_|eR04ԓRjWRX #}rW l EA^U̫6k'J'\)f8/CH[ 1xeOSyձ]nmӅNTzμl9XFXEAXu/(sǑd& 2^AȭMNhk--X&:a;a?s 衻c xȇqtzByĵy#uh-p <4Iab;{nK)22'AR 2:P-^v_ܚ="uN͞L*Gij dg]S!G=mEh?]:YJH,"YЀH|J CƗiFlwVvg؆p{Uyڑqۺd/qҔ+uA.qoo=ju>j;Ĥ*/U[9a U"0u1ΤtcӲR7xr3WX2Z.l53\rg9('\wfmP~$,>Jh\q-F:p)ȣe@-~sgAv Ehi=v̄ϸmn-OJ&Y4⹧||9J aikxk Ҭ\ oVK0 (FWZDu^/0!&-KGSD]fIw<3q}! h0yr&X9bJvOaQ6n@"8"qT8r#ntXwzӹ"~y 2Un9GS Ko|6m8X\f=,3}իh `k6!dZQ̱֯V҂2s8xI"R"xD^1͎Z~hp蜈u!ZXiIl괱={(lxηY/:lUsK;\@u| d3_VPLw6ill S*XT܈Ez_jj$ć }% %WXG { YXiS"b'֛'رl 7c%6DBW2' f2l@:AA.s0%{y]ڜ!|L<ݕ 51Fe,x>;֨w Nj p@ݨˬF[(Qbcui0l֓*Rz+T(!ɷVf/~HY.ٲ!Vݢi4?̽LÕuh{](TsVN_cs5_nÿeWS0>X dkP<0x/ i1wa y3"\K9j4.g/Cj-CC8ȟ-_zn O-[}; B{"n!SA=Ď\eOgrGOcN{[?߻ Aaȯ9yP\h3a$$z :zGUhX$h]z؜|?y &Ʉ0}d c6_OB`b_DєFh**2F˹ln]nk;g-.cSg3OEp nw!KP@})d`GP)G4yE3W@ʵׁb̲.]{%4RH%LʱZL[v׼"kCmVTV ½2r3 7fvE(V3X(R(p"vv3.6A> 5c/1j/zy$z-6mi+r5aWBZ>i v6j۰bd"AheKP0WagXMtS nxf[ 5(u3AOprk݅ՆA7my"'z#HTJw5q~6L.ќ#*m@CQ-mYRlk] uG~/sij eZ"$V)h݅eB+Zډ ‚ƪyιDrH$e!ǶnMn2J9:-aqu\2n-7# %騅9*NF (x_Xa(s689yWށ)-K~{JsތCP ,VIS{%Ke3q%ʛpWjCO'~mMVTzѱcV˥묇L0x 7[j66GH$.#\:dh'ȟ-N}Gva v5d:=QvO`M17A+FКLS:_l؟[{능sM(ni_X.Đ2N88R2`_P~<4TD"#(vl̂`GV'fҪ{leW[sLROkρ ÃҾf Ofu1L1w~>\7Sf n Fxdg'Lisߟ(E'[ M\[Sf22 O 2_o^Æby> yMJS!« 녃]5 G&q(7A˚[gc[_Ŭϭl97OT:ħ5CRГ6 h$QFwxb=2vިV &|q?ME>@ gj5'Ʊn3ԸC'|' b*~9 n}7htĭE/H&58&a*e)WvM5540PpZ̾i{FE?ǶQeĺ쫨U`6ͭ1r+27۰|N"LiP%O_T(}ۧ[izck)=ٔ5Ǔh簄FJԨɝ'%E @+)dpvyBYx`.D@'u]X4I0Qb_ħ6 (@J7[çnLr%̠a2&Zc8Gu^sy(4T[sa{<1=ͥt[y}HI{Oُ,(Ԇ / J^*/ ߻މ(nPʻxee'I r:Deպ)y_H=#l!Ŵn2o!i@1]S42~)Kiv"nI}˛z NPdFx oW5ѶOOAL4noI.Gp:C|.*J-MቈV| ]f`4[eމ!lUx!>SM6,9;XzOuW8uMEwm /i06L0>Jo|fd~Nu:ddz[FE0AS(h]^.V<p`9NmÖ1;VsctVejz%rL(E]jK$zeU:,4xMi8ִR.U>XPxhaƹI]4 /^@J0Ls>VsS?&Z7 Qg R/D BD5w{T0w' ]hFyriI-3MeDZ9Zէm(/ikjDي!ެ8=RZion~n0MP^L!"k쒴X,q*jgx3-F| +Ɇ2xg'j'~tpщN@C:#1<0SPSfP&;6}f^ {.*"/g2RxX׹%X_vHB0elAߟ `OaTZ9Cx/N$ `#/z1^9¨ "GW NcKGR 9dgKy+Z 뇧^Q EV;zMQr|EsK7֙[j /e[vw҆)ʬb4zZ"V 3Rk~n͕J}'\t]5,~},&YwdT:AIV[`.2E †>= C AW'a/>@kDCKڢQ)K5\VlpnH5SO]*z#co]Vlq2A s( 3"gm9 !䛅Kρg Pbt{zg[[V}VEwJY6)Bq#Xrk|6eqKiZb:+'XK{%KSa;6s18\Nɚ-˝q<+O'%uma$O}۞XM*po3NE>os]TRM8 &-mO:-OCe<8\a~$w롵{`A[p _s/M JquAwik_tPPEd[IaƐqm改܀U9iS fS]'rBj4?d( c뜠DpaB8:Hظ>0G0d۾a[l :~–ODQqiVYѧ٥I~˃3 pI0L)\ʪjЀFS]3?2,HߝLJeBAp3V֦nĒnCYWb|jͯ]ҢAzU;+Ƽ|H≞XlXAJ.MʧHEǧ"o#9n X~HfP9FQ>MR\S޻j0D+HBpVc&<esrw=ZKǸ9{md\_b&垪W uYoX95* :3]miY9bdyI}Ɇ*R3L]qrQ T& M1WER#-ou5:ׇ-#,%%6aF)n2 6{ ݚ GpΡ(AG?@s)x f)N xz\HdUw Q#qrZ0WY[99|wq[➧>Sӕ6&3ͷQ§t o͕h>oiE<ṙ-cVHh75hsP*xˀt,g3d3 W6ymz/<IHq+[`lh"\ςSII† p84 9\ ;KQ˱۩U6^;hnrtx/Aa <vuR<|Ja> x01|^vƖ>'tV/{JSr-% `61o/= 3ΤcDh0߮;d) ~eUWl F+N.+7|r9eXlCK}8?% aW-}&G&SN[Aq)pO \i&Pؠp܊ <" ^ë`8fș=>B~fiO  zyC7,)K!̳˞ڐJ?ڹSB=6lyZ||_)l͈|d|&Xb( vxBjb4zdírCm@ebUD$UU]~ۄN4o\Ȏ?ϯ16oXQ x1NkwNN[b`ig7qi v&S;7V-oaY?^o#LʺP+e('00# f_쩴>'.w깨ّtq{L\wI(c">=e("ٓ~Y,r&$1ѰI$%yXtNӍFQ+TRjBLr_HLBVPRb/Hϥw< md[ c#YF R>0>cdPZ;f[A B^7r( ,F5)z̘jBp4G˼O9c7JW4sMɋ NZnS sI-3w 06Hm. R}&Ko(ި2YM#ǞkdoxK㓗_>'`Q<6LJmpM3Ѡݍ.i~z_umqfdM?lx? Z;Y\%l9` 8lim=?ɌƲd_(oub՛[xJ;>.ǢS8XRNFN2'N[;^\oA20m?e Z'vEHNYeyxv%!8rh_,$WJBY* z/fO ~SM6 6M 6F:S2v˂?qE"tPZCW>\2'l BjN-?eCX sp DCg*=Jt!]  ͛duDkտS̿rGh onΙXx nЂ#=R ̴pt SX;F3sھ^fU l&BY +n—d}{NQ^}B'x ۇ'LcSqMI(!|fɻ܃浿% {eE&ҵ(v!&Ѕ緗&MCnuprmQoY7U-$Da: +*;c0K+"{~F|}زX|x];RLg38{+mp UzC#}1Lꌟ@] vj ?(wxKUhNOC.T-D[ܴU./Q(Dߞ0t[.lU?;7g}f]ь;tS[ m}O9ULZ3_ "i#Q&3*[9G()8xzFbHg+?Q3Lla\k^i>K#ܫwu+5] $z?GxTJq_~aOVo>9u  aWԏp 6;Gpy=V:EñȮz*#h7Q3dGFDW!BoOr?7+ӧx>R dd%Xv;\<Ό?UL8,\$ύҟ$tŲD V@.'J|Di H,;͔/DߏE܋+h(yvdRQDKc)paf|^ g=CV$lL[n `^&/,Fpmïy_*M.#h-lS׾5.w5$Q%ZBw;7<$I҇5:THXKsk=*s"bl>x<#0*|"UN~/XEdi)aj,Y FFt.dN!Z?hOk{]ZɀfB)&d' PU{u["_ >?x8FF%ڧ$ SMPS+[ۮļ>xW9L-S52VM3Tv3iY JP EDǺ<  Ypt ۮXY P~0>lb7/.v,<+2?řsQad'9тDASҳ+g:NorP^\2h3"J*Wt R{H6Qs#4luC{I ZվWOËNXI!ݴ hYQoFs$Ƈ]51cu/Fxjߌ/۶,QXJߔQIt C%DEm G6a%4d73C'"Ph])Q%Kmʼnːzocp%GgX3( ޲;p+r|tᤗn,zAU"f32 WESQ?߲ dc,nJSq>a2~0I&݇NJqP;4GB/fD xm7:zUs0Gz5w2B؍o{ D(oPYC 5t֦y0*}c-_&N~u%b去ןeЅ хɘǧ*Hi.}W#{mķ^S`% EG--w`Fh4{-+ޕאï97ZHH4##j[ L W#mj^zp!_{~-]7o4T"mH5`|:azg>)1j&VԲ6]i!پ&W92ΦⰇ1գl")Rƣ'$=|“|,:K]A>;;K@24c ^bީxAsFA!߾Hʨ ,8s4ì<|D]P/ߺ? 4#7.6gߡ:VKN4>@QM/OI4ރ[Ct-bIF̅y#Q?F {kZ-4[ңrDw\.=UkZѢg7>psDDKhhlq˝+UMc0zD6Qfjyȟl+4gU%2Z7}AT}@SJ8zv{|E0UT:[4WH>4,2xv6cݖLGe8PϬqt %  {`œ=T_j'y9$ /?]GvxYE_y?f&socm} cs7o=~,u031oZ,km,^ddSȵ5ʁڊwm5R~ ]>pa^;KG݀ f%g֦HDC~>`&Sd wCĠ¨?AK&p:Q&8d硧ԢZy[ۄNhyggBBmjA;zhfu []t ո^r#)qu*i"|=;pUt/Z+!(\Cʑ[O30ߞeaU\z5+hv ~6"_CaK4BJP ޥp'\ĭzkHf9vJOW\7?or;kCr=$02*UihXm$?{tKIk|$?6ƣ.l7R&"SRÞQKLDzXSu;Rn?(_9)pW-3xn(p\XV9Fz{ޝF^U~]#d/,jhNz& |EZfͳeW$pL9pb vѧg%5HVbk&_M65=jE ]+enP.Ѷ?*QS7X)x/\ԁpЏLV N3N"Ź=:KQj v$RJKd*^՝hJKQi,Ǚ~V9\mh"iDchׅr<ݼvSab2lV_u q19G =E:)WaIv<Ġ9{xD]Rc1}9B'$KEGZrݽEL}+f4g&I5jR_e~E"Gavlq\ ϯcȟY[ⵆaxLV4|n˝v=*86tj_9͗f (dQoh!#Xf,58c>+S4NEe35ɩDçOw.f~2s6'r6%`Ik_* 0xwR Sx8S$]9\{-> GEoBdRH1?7$`rVIQhv٦~.QazEEV;(ځF,Yp';xʯ4JdA[eXˍt5M! 嫭p](}$x)/e'EHn3tgK(=8tn`AׂM>3$8%ZȘY\^l{oMΥ),z 4$8e'5%&(`tvak6B٪ꐐ}\TL$>E1׸aWIOÕ . s ڋ{ij`ZB;g3`(Z 1հ pgt켦R҅ƣf%.B#3uORPQ]y*HV%29 KKSz98q Cۻv\GCW%7bycr؂kc h{(]B"%U156xv%B:J?"_> HPQͧWGUq'+'erxLV'ρEWEȴ55q V$8E n.R I@+q՞%BXE`烾 =5'G!: IAMɺ6wj=T~"0𤱼#íO ϋzSnMלt?8tE>Q;}6edcܷLȯ8[?ü! \"zLJ> ׈Ig߾\~xt;:<&@v4~ aolU `J X?2hD'X{ayώZDU.P>̢mb2hŇ} \>3HWFp {lG5q=VA[3SE# Ymi='`|ld :pvFpk<|؉ӪIr ׵i`z\heR|{3;`$!&|0iZY8[CH {+vf\Yk@hoyfnkPp,?=Y# Dx(qK="N6K"n.  MJZYS;g<Ԫ3aA|vr mK :z_ j1yqUHY0CNfrtbZ-X` {mvX s.ʼnuZ y*7d[B0녰5t4P l [cmjsAt|,cֽc?&|i.$oerD=VU!j!]W5| t;SX<ۚ0UrO ۼmF]xdD? Xʓ/.N'0ƺM*ɕgW+=e˿Qw'C> +:k]3CrK>c 7|>0x6RULئ=DRaZ˞o3-D! ]Mxj6UwpxV4p-HuW7EjR|`~U(z4֭ UcS v I~K=fږ2]+Ȝ}1[;W^ LY; 4Ȳ_#Xݨn9.1ɺb5T=B4S01L'!& %Q.()6.U@,i/Yԅ+H̥D߁ݜcm8Jޭ lѓ;f^'KV= IilAV% `? <5u}ͯO(؏oƒbG$N?o܅EEW]0#'X/;n64v P(qɎ:ݳ78cdGg9{odt mpE[ؽUC -d/G '"ż  (T 3@$b{܍ynfP=g{۝]`ry'jSܦ0hPd mŁ@V ⋦S)Gu!6];[~u陕ߔbǰolu$֋k@4j@5֬dk gVLH甌c~kw} 9ӷvWeCq=KϘhG&{`#MGw"s~zUx):jF6SwD/fȅeuz>=W}P8MLJ4ypJc?}ҽcIhMq̀]krRFT8 INKkBH:jc)挂Ҩw O|F;@3, iMlΙ ՘Tyr}+\g_)<O$AG,BgaltMr`|A_8XˌMgV.i4LW1KMύ2 D`^~lQsWYEd7iY GSqH*ܾ$IMC%Ϣ[{;y+T񽽠~ 7ޱCasת$dTln x^:>sd#m,گBFܾH44/0e'j@l!N(;\aq16@ӌ:V¿w RzAF.O螾JP@_\l<ܒfA 'F]Cx嘟Q+BB*sYZee)u3,KݤCPZfQ_FN&? XGo7Jck^4%wѠ}eyᷴ#$%gh.W"/mqOrtx=Ϊ,hHXO+6[(hwE|L寃hC3#`p}DkS{O3^'G'|#G]0xê_վab.ґ?裎Y)sC |9 #rq] k|j bha &T0N;ԁb 1YELBd jVZL)!XPV;hGڇ9ỸuES1PYY'/g$7̴Ö#x|!G{,0;YT<(Mt W/p Ez07EA'=-5jƖP-Ɂ $.n+@Yp'$!nQ9>8nFQ5٬n^)D"70E`*VGϢ|j v,7Aɡzƫ՗s  "r]}PwCV؞J]aD%h^Qqd(Ia?8" e3BЎJݓԬ,jOG2@pf]K$gj= OST4d,ȹa\17豎rBsC!* @d<,[U&?L چ"GL'?yO1+gC)!^G ݫh%~>;}50V Jr*߀#CkO,&%ndu;9 r Dsˈ ʖRIwH4R;\ut2d <†&.&dl:ꤘh*c%QQ^`2uLWt*5\Ԝ efOy"q'.]g#moVd8j2>⛮#'=)$Ktd^`zd斒YcNҷb8sS(PDjηl.D9}T-$M[`x)ɨi Jٟ>!hO;p4 AZ}MSVH  ^)XO&n}S'6QvWeUŔrϺX41*6\0Uk }o}#s7^"+ejRLԬTD|NYvxYP?[nel†6qY[/H+~h/tPw<\l~ZXҊ4&j7s٭]+Yp!f#(Ѳoŷ4#Uj\ނw@kބܺ٨#dv d`.dY2qw8sIF`QQT1@e`*C 9hi3qT̲ive0>XUOHd=xDj;V&[wڡܕBOgKRwlc_<44,o~bρi̼$aJDk(CN7 )mboK7ed;K@:'(6KYYI5-xhkk|I 4e1Y#e s{E_H%U ܘV컔V&51> C;rrR,be MQIu Qʽ" |ZvzYH{[rÖ\>8Ńxb#]4<(3#FYP(oU i@8" ttɮ@'Zī,&*W)NGfZ'̉iօl;]N>e~ AR.n?&YJIιP !]wߧSw׼呛L}BPh8 9L7 kd{Ut Cs(';^Dݕ_^.)BkqK]DCkd{[o+WI &C_}d/y]Lo= $q6{bi 7MJ梡+D Lggt佈]^:RL1VcF-ҁ"7_ry8Q!׹[p5F{b*l1GOGfd0ݭj8*2em|Yx6sOiêI:]Ӿ6Ѱ9+ş)\hxT޴S`%KYk{n s{bxHsEd~UJ4FD͓>{` z2y0C\ɑk Q~PF kik<>C]]rixr`Ĥ9 gPX9EGipHKi3A~ ך[_Qg$;3DЮcG|pIvG ;ëJQehyV[z.Pj=1wyNߡOd`8q‚Op]0a( @҉.EiIw.30ynbCrKJ67LcV3 5EudhҌ.ຒHJË<@ufqiݐ =Izր:F7X5lPGjh_;O<7.>$yh?¡ ͫD:ЬE]~$o·rR{.wf"EHz $C's8!z\KULS//!W騃M<ɫ?;QcwZ(Sj_'S%i:q8Z`H3ʃ_}'ǐ}H"=u괦rb> Wn܅ĭWv wDllٸZLEa U- 'eֽW=L/~ɣV͝ =[E5҃d /~ܩAU_P{ Q]Ai7Ba)?|x(V9%R?w9Y=c\+`!r|⤟q#YQrHfzai)%ck9Q8V|]cT +s:1[XVGkv?"Ye.b܈2ѐL><_G$<1~HNGOty~lѻ@¼)7B7:r蘢/oBӆG? d,LuUȥ#)JpӖ֔n‚.ܺ!HT.*.M1kUNU5jw+o{5Elpbg f} P< ]<<n•oe[.xnv7&&֌p"PdѽV\1: cT /N#3Lڟl/!m U;΅d6QwʔT 5@6Tj*&״t.5DG.}Nlfpzw,) +CvxŹS{5ڑbQK* ?|;j NgaAē﫷 o<%HML,Jp%bJ :aw%kLgs;_d.o6qFWrz)Vcˠǭأ2k(_B6s{E{i_Oö?8EN*FFVL9&E;ꇶI*;q7lWAϸ%)t)6hɫ񀣓H 8sب CP`,ΣTp%ajmG F 5׎ 6%d}t* !udMX☤s/5ٔ+xpRz_%'t7Ep~ V (]Z!C=B$A#艅DYfDOrw}q@`ZК~dC @?sΞ:ǺbqNqL Pxlkle9U`4e¡*M'Ш%IF_2i5  7;A21hh21ZJ˗Jؚ)!0Y`ߡ2{U`̹'i6SR,68oMJ>r?tSuy> 7J8fVtܩn%],4Q#T(MQ'>ó턽BC |#j{i9,I-)eSNV), 8tC8db̌vA[vb!|*w/yBEBba"('Lylf7S1tL&6 CʴfST{K ?>֒~zKW \LGBV6J!J B19twnkTAvT7=*+Q*#23˔:q5ixfV?@h|}۹*܏2rjxbzԑri䁠9苶p[aNawIA6qYo"QfPwKd,((" K O{W|}Q]R:j7q-!Qs;:j38Z켧9?s\&C‹ylNw+;XU]<ĺ */5cP_/V\]候Uz/ 8ax*n/ץTZ~Y [jkNk&:G)K1X?/(?t.\lcR{ϊvY2"Qfa7ZBW CUNKpd"ZMW,oR`ZnmͰ̬*~\p,YAΠU]R&L6`|P?rxV[lڙLNp~G ͯ0{>wBbG`y-W`ګ`z:"z3mZ41/M#hgot -p~7`S]4.(+$#h+:&]hN E^KT2-^ܳ/ Qj MM!>PX? 0B7NpFɮbv/9jjL8N~79%S2HGJecdabj3(,ʙ5 E';wZ~;Qgy cFpZ1s߶ ".[z8ER>'*.+`-_ܩ72hs0) U(zSulgsR(vf{b^a1 =6 հ6lJWPOplw~RIAW_6@&cB-֒Y-^0sdyr+88 dƧ"*4DȦfŷp1#C}Nw@*G[ V9D1'e1+hH'b)8%+DdE{R/V{O;5ܬ´*`;=_DPX b9jV+ [TlȼYrU^u 43?^yo5w;qm}+Jhl "o7 D2Sp=VmԐ`)$ ؂+a 8jۅq_RH0M8=͖yg1S?dj *}a} L3j_J}/ BK&1矍x8|!T)ջ7ye|"Xًbص Q<Ԋ"/y&\2P!ڛ|-4 ?ǹD8*?lDPyȦmc"JvoAW%9z D3HS;셌uʋNz\7?G*Ƣ++Ū La09?~@qDhFDb+gׂFc=8%/ ;=%la_! 궬j"d27ߛ 7Q36 .a'bn_#uGȜHŀ o}ù)sԼA _HN_o3wxc}[k@pJy[;J̛rb*a^ۏp>fDB}!2n ﮯQ6 3YXO]+Wtv$t$-$rdk3i bu,ͱ6:x"H)[#𷺜T^ N ļz>q{bغ"}RYՑ IS5BMWg3OVүV2'_9wk/CgTh !P'!_#8 witG|I4RaFhef̜ՠ+\gJ_x\MO1$Mm @,\Θ/)%>kیc]цgCsұc\5L?t'➦oTmlbt9{BntcV)vzdD*紨RߵDL&uzuGiYTC||g}ojjPc8χ-+U;H> pfMaFe&gPAzzCoɏ}%ڑz?+` I I rby[oL 9e(y|L=Ny[VoWgΊ{ )xcO{&9;{,M-my5g 0 AQ`Q(yڭefnmNP\/o#^0Lk}i%u( :\\Ѭf:%w觐-hcw;X8 %[o^NS>קGh0٦Qdd)"Z7z_=bThhG̔Wmy5e4Iw "K^W쑪 \U#MWQF.ɢmQdX6K =J+X޹OWg/VÌH)Jچ@nL "fsG>G䌈s^e.'0 h=/e{8ovYC O@oCC>Z3z #vY(M= Cx¹+ 7N>D9 Yuk\vXyIP#>Xrxt鑂xש|-R`wCA-0'ӆPj-d1-3)%}$VB) i۞V'z49R{3B^+oUot0W;;j2?Ga`" Ox933gM15R^Ekm}t)D[ g\7,a|?1Qӡu*§=u϶:]aJfd(q%ݡ?&' -\9c݆m+~ FlC" AQHW3Jxc3bz7p  qc]s\/X22L$te>3:M39RX$b{-k5Jԁߕ&Gc0h%;P9M@1Ov)xeNk}!GHѨ}X_}pSabDI,r]b]C{q̃7=.ק!{{WMuޟwOt4@ߡF Dz9vT$Q^Q@' ŴBt]ls]yy8X;ctB;il֪i9SMh[l=K a/ t?k xcx.jA%>r?Okq{lII!S곶![^??Ge]\3;:c5QRuc-}ˌo>6TИ6Hz]`U+@2J7΢6[:~japH+GK*rſN ^ٙ`> ޕT-^4um:VHIhٟe,-bue>,/:;dɦqpXcWR5"LN4ݽyDtg=@'dW# ]JvwK L-P ~; |n(*S2u؆|\cmrgXֱ㦩ƣCNW^Ȧl]33Fpw`Q%ȌP;b["R1!< 5iLPcauSmGXShtC 8i߰&rZ2/ӧ 4{xŀt1yhPTQhR1Ͻ!`Y\p;!c| OhV wdJ* m-dBXH.hկn.5k4? ,bYg8YzE^7 r&H6;vx]O Sr B(?3ݨ0PskɊW "[%T:ce&> ՛Vl2g飗|ĉX6t')EW7\KeM 0΋UUҥ"xi_ j3=3 ajzGwgo _EMZ.Å_3({©vi#3 tsB y䈃ӎ,UŅYߞvQ_p~˛rsiĺξB.3 nSn,M'Q#k2jLcO{%ˢ0n>V éz^2?[y֛*x #SH;XhP_0#=sk{D~s,I!EV&g`=spc+C^x_1h@]},.Y#[s'P=6ډjd ~QgXPG|5AP<*ȼ`7kvٺ"BV@d9[֕{PJ8i&?T0HT|aZ?|27i8?ZXmĚKθ6zhvA_wꂴ;RNV~y8WlmJ!='[$#`vT@XУ" &1Bpml0CSpB䘠i3']]O5BXΚUA{«52]\*-3ǣUb!͍ۊ[[AulCߤgdĝZ 2Şఈ!5@N]^z4d 4kl鄻+(\ò+2 Ap }ۊ(0cJ,diE9INr#Gh[,[:A|2jn"r\ S=&dFW#BobضcO{2eU=$t|T4/g̑ 9ؽ6PddXIQ~ew-@^y.#A172*?Q뜤~ Xa^@^}zqxS +M,e{s0E8:rtҖ0/1Aq]Q)^,1η)6e<([$~)G}Bkw\U|lroRA[?>?WfԴyxlb߅=άwٰ>T%nU^_vF:˲蝤'9MnдV*=J10]dkJXep޴=ԕo-VܜئQwIGRݮ:q0x-EQs7x|# J+#0D#Wo3 SN!JPRb ̝zbq2@Es"nS$g)67^`.4mJ{y\^x6C~u0^HPvug൞2Mxhq6 ML:q(^.q*%I 29ޏrk/m$ʋ6 mfh"?9@Bп: -R>rn)oJ2t o!j='1z\ҌiJBMWP>Dh(VA@CXkglj+ >ܧJy zX%0JІ0W4ؐJ+@ebQ]; a+W kIV.QFay.u|GfB(ڴЫK~]BÙd"\9*JJ}@v Cf8~nzEY:+>Ampʕ|F5|ZLɥi9PonZ7ᤑ4 MG^tB<>P78؋bA;Ys4cagwXyutaC)iJ]JhY/ 2ν *aS~Y͝xM Vhp{pnXUl[G?Ͼ:3=7#|&˭ Va`v)DLR +o# L O?lV-n~wԼOd.Tצּ.۫p^S@ŗ(j؊7W~ҲEY 2cpyc8 QF%z|ȄcXO1_,6D$ZRL.mTUHuڸ:ph3M+E%[ӌNy}2iQ],VYcݵFeLw)@tyA{֝+-U'#u0VGisoڥU(DRb]ƭ՞SIQl7Y v:wOˣyF-LT@87잌MK-~?L9u|q WQ(a5d80%VVm=3 M>COPe'Wwlv֣Y5Vpk߭HJ6'uJ5!efEN5]9jTbrj# D%8ve/qT R'J29EҺSO# 0SA$۩!@mֺyUBR2HYNk{wLj՛0Z #E.dގVp82рd<>a~WYRɺr\..+3hP}'E*]€y<10I>ͫ a_a93>a ¿@'RhD{G@̔,.؎tq'>{cbXlb\*94 ʌo8r@W9Rzk%颰/Ā9՚Pv&Ϣ[R%־?|cvxmq@ y"TZoZ \di'Jō7c%)D k+1.i2dhR+m|XdZ;t|\AO𓯚b>GIQlZ# HMcn>pm>H]{8Z)b} GfmsK5C)8rxv tJQCc#Aw AG&J#p_$!3߱M9=׺shʡbxOU€7YIV | *$`JWJFw3w1Nj_+ƃ \5AdQlpM[q6}*;Yl6uQP$pDgE0D~ǧ$q1x }nW++/Y;t-.xXK11^y]z1jz.34!PbR2۫w0W1'iD1.Dlm+.جFnn Ymk:Jko0J,(ϺhP^FQߢ_& f9Fgu7{]ݜYQRe?IJrJ:fB*ѶU4*nuV&i4Į4 :IE!$bF0B9gMT aǂOK9-e <=ɻGaѳ~+z^& ; 8U*c BP6h_{~] {%3 hX|/k|CDw"P5:㆘y|B!{BO.ߍ!mBc)>2a2#![nuSUk[+C:AH3o|;/םBI, Z?(nlV_X ;؈RsupV#32)r1|^GEeSFkE5iJ' F/&{H0~c 7aCy"A*Ee{z'g_OfKW|p"rS01}-$]evIDRQ4IYiF,ISP$N97*}H$k_SJ-(L5gIfj/[GgqyE:z.ODnV*.^nTn0$)I}DwR4DAjo; e,]]4 +*#$ly"/Xeq9/cU*'X9Rp & v>*ukKj&>;eIX ywB3jL]qT{.wQ\OR<4%Jp!5zv,ib{[REA{JI) 7 6W'C%D !F&3R: Q٘sB˛MC7Gs+Ϥ|<5FBr1DwW8_Z}! >}'7,/S\7;E΍+d&"*dѦ}ׇ"I3IYvyH西0O`* X9"Ѓ i#[yǂBaϙ\ _b]QP{0c5nDn9ⓨy/2x1gU*pU+Ṇ)VI, ԅCMg<%Lϟ=|39O zXiaPO5Y'𞒒Q]_efF)߸m_텇1!k _2)ĐL%F~&="!.K%p݁ D'iImK4}mp>^Dh$ŌBZ8=fGg11TPo#:=Aέ˥80WbbQч98{HVC~qq˸L*&?? ;Yњ~SQ\'VGõ&\BVxy5ȍ~Evk_ަ!7z% 7oo`=[,@6mNJO+Y cbFOJ1uX?ܓ1GxJ6XVI_У[2'OC ,CH-w'}@?qhQ&ܝ3cZE_۹G^ L،`<]ݷ1TY\(q6+0YdQKghw,>9q1e|z7A-mwf X(nc=hXnNXEΞ% G@`c5@/˄Վp8c/\7Y6BC3xM.N:sUYmx iVXYȮ}ZY191З13Xw3:ͣl"S[`'V(h;ﰸ0Pl3`U3ne)os!Vb\ o5ւ[Nujrt ?)!nN4쥞U^*׳P=+N˨ ]"LΥ DUTOg1 :ڐ$GswfhÁ|!EO 3N#e\{{Y[ C3B/U6JaHwHUN_^2/s]ٷlE̸Q}âD!Kcft.]+{"iFĭ. X6%>ғ3͜xMTSU< uk%9G]*'[3н/\8:7%K,ԁ4#$#3I]oReYۣF ?$SoD^"yޢu2A_R3 ll+Y&d/er8..^fyWGyOح7֠ 3<رxB vbL˗S1oO-ջQ_3ak<8T8=]07P$Sih]/Ȋ_5*hzWog. 1HLsSL#"} }92t5'0zS$RK(}ST'2;btIr/RzݧaG8XoV>EM(RUb$"Iqy h {0>2S%A7Ԩ $.J4TS:nyNU\m.\-88@#Ux/y ԀG&E[eek$ |[d3oV9\Fj 0)Z%$٧V*^}iC1gz\Ű=}l\Wu$?H Jf)/z,C |GP{LH6p>Ck/ϫD92UlnxǴ:U@}XxFn/d0A|5CaTq#McoISsڝEY`\Gj`ˆs:T\s;_F[">F)iciBw +njﳛhD|ڐpiK$-G+?ۦ#Wiy>0]C5?'+m /^?~=8IN4^4M7B#f ט +n'dϷzFЧGIڕenx {=ęUKd Y,/E죁).aQk60o wa:`<"͍VkmMx.~a0 :% I9E#6$qs  j'@] :)!G.UZBna/,~+:TxlS<rw0)R1+)[ϣ߹up>wX%˂QgP0>A%B*H~O Z,ZJAՊrL}DK9nJ\V 6KԷaN:O7<ʏi۵ZS0:Uij=U18{$ߟbMq>^ωGK*!}5H!%, ԷTrw#Dh(e ɥ=ަ5 D\ d08`ocd>}=EVUhcLgȅQ'EL\,Ff:G%dxSP*̽b܁y/Jí[įgQRi$?fa.8l}oQ\v((u[[GnޯnJp;Bevc:>'%[ s{K|0M [0cԎ`>'f??hzOz3n~ cWh;$t1o)477g0ccX]J% RUHa`w.u^jGSwi!g1m|U6LY HUCve|q̙A< $~G,^:x&þoXq1k${(.U.c.֔x>C J xtn&@]U)*:,qYkƕ73P5vgeӷ +1=Vs op)@Y=n87Å+[ ϊZ*|e \@kӟlGg#%rI4ZJ;{ ]m.Ĉ Ho&SH=)yC *ޅ-}|O4kD=ja 9ixDB \~D~lp7[FKJ.CyI' \[{4ٻ+L#CWH:ryg Y?OO))vՄTe*!AU*"r骰=yW[)bA5Lr071%0.e^]r p}ڛq~JjhF-G) G2tYYD!P3@5Yt_4DeMqw1H.¼HsHkC{իHcq !,ǦSkr+|z lJes4ћ2;ʰC"SADL @o&6ha*~ a_pW5a 3nĕMF:VX/OX,cT#@&OA706o_{d 3>YL I@Y=Ez p!N<*!K{3$}bMpw w*?KVYR/GrrLTm Z@bn$Fr1m0mvl`'->1as(ݸ@s]3u{OLW*sTCKJ(FR4-ͲgW- 1߾v2YƄA.5`Y5X˃qK}m "[fnFd=Z~y L9@rGZvG 4ɜB1 *T̆`e]3$3==8-hje+ol/mV5\8YV.ƒ 23u3ց19.5EJR"6Ϙ=Kʛdv(ZM[>eK?ùSC2k!K8Й\ʼ!idd@ÚpU OCJ R^&˞p8otLjAҽl5JϽ M[޶'Ó?vN*k&OI>@"N~A}qML0v&pbW4q^7LA'-* aAZvFE z $rF6v r"TjHA5P)NRj|k5]R ƻ 2'B޼5/i xYݡ\[ K|BtYn<)`7BHCg{jJd15a#h207ɑ`OO.#YP-{:KM:v"aےBOTl녓PHvAI'brR%x %=*n'ܹ…zJF(_^v_cL"8>ɹ-׾&,;>rāE,Q7Rpi< BY>jpgoG)p;\$^^*܁ܛ<4}=߂Q;sFQ+nu'@ukWCtr2EE֮RG3,K_s޹5PIV:|N" oepح_'NuG-K V 2jӸ"rO4` f~"Pn)BM[FFg+ ooU #G"Ǘ+q5TNO L2͎Ǫ9uGߑØ.Sӿ&.\ĔEN0 7v^[,ȲOa&*y0 ^1Mj;VIGhEq" Ĕv%Q±$-|OrLEC]Y9ZF| FXrd~8EHùF w૔2x Q9_%AYYr?a~fگJzQ#^5I(9At-_H0lYa%B}Z{l: :}Qu8f'+J'wcc/y)|?v4WQbm6fuⰝ+uY} Z2_@t55Fq*ۙâ_ FZrVHRQ8_ rBBTJ>CiR6nyIH'zfmpGubmJk> K-{͉)cUoWI-Lay[&d8|[X enQҬRbYN񋯲zzu&}%I:V24MΧ'$Aicgp;Ќ@}BZXԗELmlv`|8X!*Wa̿^7Ȉ?w^1/zXd&3 `KXZ0_ gD=]SKjRy{_b]mhpMnm=&1g kmo%ڙCȬ^ĥfti ZTfEwдyȭa|Q/"uvb#2[ QI>xv2W(g*g[e$!:$-&TN"ffu8|Y6!48狵bPO!bء6֑LZRɂs `vA>Ju舰:+`i̞cpF>!~4 g"rmIbAaB\yվVG> i5:f-53'z!#$('#*n߾&f@w]3˞7qT`k>/(CC57`)SV臢&A!.=g`*hO->M¥2yEsV9:,iBK1" /T7) \߻C-[ib$3ǶHӨxfdy<`#xE7Pt߫: :)& ~#n+JCHr)bet\ZO="'_lX\羹wE04js\'QWS9kfXU n2U&j>ffڐqz9-_oSC+#n({^'X ZLPIھxGyQG~ʳP.Jc%1SOv>}61^Vh}Jk?J/-/>۳W8SEӫ퇩|1Eޱ~@7`{RdGVs{|_E+$\D=#]::E^dzy7+3lbǓUysӱd_HU"# nj҅2:gYu7H=rbWPM(x UysYϐH ڜӠebX[0!9Zl@|\sK9_ 4lOns.5s\ܪPܬ>ΨB4C/ 9ݺY4kTBL1uO'DI^Yڤ&Xwq->Ne,IT L"&>\π#ZW?u U#Q[ c%3%8s>5#-8y Y1NYPQQFz_JP$Ij}$ǨYa*8 S,^d@k@XƖ&p5(l +(44vy8ńQ#I8H5z 1Uu*Fs}q^*²xbHɘYoYw@0SE!\jo7m7.6Su,~2jXت%c7 +)io Y]IDF_'!v+_&j+xCnÚ4ˋlf"vW SFFNAYU$.l`REpTՖ`\J34o,1Iov (߳7nD(oCac1eLGe<[i"L\LFHHKxʑ;T Z`˖$]bMN3^*2ɉ75ql$r$ QtuZv2%(U,ncw!XU>&M}:,P6[Q\F$j_zxe7ҕK,q`L0MZœbtI}N}jD ?,Gx5DϟfERDW#Lcy.-Y?W37w~h^ݲZʿ7ػX@ 2=bNĕ%җT}1 2p>$P>p` aŊteet(D !t^E! 5o(D^%L&{>NLm)$Y>E}JZ޷dɯYB6Mk6+)!uzyM aT [ў' LՖ$c33 n84k/Ja\Τ)>ʌb[|Yr~dc1Y QMX[Hir"uA"ygVnXNlZRLwhg7u/4N>^!aofBx9>f?t[,c*GwXX[ά|0v2s/ R-CVm#s]&77ڱ_|8,Q@Cy9+㗪H*N:jq ^߸ oZu;wj:x&y_B;!x{ԗ 9DՔ5R PtȆƍO^ 5:Iѿ.Bq=(s7y5{I5M Oֱ$MGs`#ͷЧx":N|lr|kdG]ӘxgԗvѝN@w];GO/*MЯ;$d.brQWE`2?g:¸Ձڐg20<88$v^tXE3vb)T8zodq[48=TBж6ՈKW%OĴufR؅M`3X$&fgڳi߱yD:kcm,K+S1٥+ ٓ~E>" z'aHZ:.Dr-*N]G *U82M uWH3h)Hc\3ij DI"Z$V A,M숆̚fIxo4ţ;.KǓ À_l `ajr;%ȡ\[!&Y ,UL$ !PT؂2i<~qc%s_n&TJG!a!G|yƖ[aqEV^~gѥCYl$`UJ=ڋ#,iOƕgcwg'"l)Of $/!!ӬwV']DQqA;׊ExH h8GZ,rLy.5CZ+Q/Nyo01" oӠN1рw~p䭳ף]fE6>Gp0ĘH?Yg Ք#& k^OO=P4q^H?Z&Ȏ)C]E(ny%a>8*G8k=}DN yw_ɱ#n@PҙE8gz"!~bB 9\Pp?řŚf_tUNF;uڢ]wm(EݻJJMbQfGG eBO]5rekE#Bו1XeR^X(*w# *ٗ$) }QXq\#F(>}I㛟fnA3)auz$C{Ihv"Q(^C>?5fRom|PSR"v}[Jr_+\x(8quXI|ƫeʣ22ѓfd a9YdӐ#ud_ E^o aEe#gg-PP8CK^=j yuo{dHO9ZM@x`kJ(z 1ܴOU wϖ:8 lyAl n0+ZZk)o_ د4w;|GFl`bWm(y%JfW;&#>0˹\"mc͊4QOۭIQq&퐺_:iՁwjG%v'.L0э >c#<賷18δLhZwɶF-d@]&AהZ|@B9vǸr)ɢf!KEmp)$rYrzd舵wk}je| 14kl_e\n'e#nCts̎MUzeŕB aZ25OW0K~wBՒ;H d!Sf2{8icL9,W2 btٛbY:.MqօD6],[c~'9|N ரj#K$B:OSwEb {;,KՓ T$AҜ >3r6 hk  Mmm c"4E?{Շ^:ǐrmfnZ.mݥOlS~wezTr{S) Ջ}r.JiXLYYOB4҆JVX p-9pﯹX2LVR + WF)l<0ֈ{Kx2O>4HgV1W!dVǎ`7baƲ'E_9tE088w@-*5%~E1@M* fHS~Bx!X#cYngpM*2IUW4$w-L#R93*`,93"|i Eo5io9pM~92,P7W1&RIKw0U0pUfr5уӐWf^M 0NAS?r4R؁J*~7V(:O/+?sf@ml]?! eԺ-Cd%. ,_yܹ*maq6G*  u_34"B-1Z3ߊ`HlwI\ toCQ yql [*qhvXO6_\ZHJf*C)Ԩ_,+A)dEi1x9,eDg" U᾽kTxͩj?|HG0pbPȽbNk@nd:a-5 i񛺬%+Y:6e_2M_0 0zkgPە%׌-t{{>f^X:|3D.:|P_>ڴQp9U[ ʱ?UGQ&lWYbGUKF-0kRA͵o< ?4,Cy"NxNj`- c;۴")q|5H$7_p՚LREw+d.'ݝ~/`/ewM-w ,A3g ~f`:S2hZcrHzj+,q:PA8(C^ bYT*W' H[rgy}uQ?߲1o6kļK# bO}bq + h>,kvx.%Q 5vX4ف:f(mI }5IRbǮU ݪҩoiћNgȤ6{tگGcCk!w#A2Z/4 l]͂,x> `#&.s\h% yhNPwe.}&>K2HtN>5xSd8&Bֈ^b &`ɥD(n>5~=`\tjJ옶#[p5˳о)î O7GoP T(%ܛ"$h6EOB\ vZUǍd9Kvbby+J<оU*x_lgX;E0;)o@eCMRByU46իYE ;ܤf{]֑`B[[!ٸHtաJ@ Y@TPְTp,!Qюzꌓ ,{~5X!s`(MgBe!B%PҖ# LMp(DG(G3#1 Cx3#isTM458Ġ䥨"S:dߡOYA(6&;K Gh5ZV;QӍhwN\o(Z"@m] ow~i$K_bԊr{۟K>qz_ :H1 El{X7'P`?$t5`-M"b]wE9׍߄W&UFӃ`(Z:j\dwG=ͬ*h~hx+G,>Þ=n^- iC:ͷvSÃofUPY]TZ*9\w9TtUU/xzŝNbZ|U͐iҐdаtUb>fd8Fj4(b:$&7|=pl#nv҅&wUI5¿f{`0^&ԉ| @,:>@/n@)o|ss#'-?9MT,pv&vy+ $n {j^W?0mWUW(lzܶ{;|&OD{Xp|aMv@1E$O1VĢqK=H#"n\E󎏟P&)Y Ѳ/E!3IF'CVmt.A\WJõ*)˗-el5LGG@2"q.Jه\7 qnh zɈҿ/K>缷P)Y&5a#ym]QbD BxK(; Uĝ:J6XH(rDF6PHL7O;a;KwIi^GȺ1O~olŏCVk5HGż#@\"ÿ'sYC_h0WmƁVIrn#ˮHf,;r$E: :Ҫ&뀪H`2ݞ5tǒ MmFQ_HءZ>h"6>]E[˳[-@ ViS(~fU9J {C֤ޔIȪFuLȠCT4Cɳ]U~&]ƊAAnxߡUsB':A:WzO+ߌD66wM&jܾN@j<2מV9[,o;Sn ៅHfb9Z٪x*gDĥ@{0%TDo%]*Q_="wӿ{Qҝ<ܕ`sR;,oGe'hvB}DE@!_oo*U3_xӚtª=^3jjkp#)'tj:,/,b/Go"l 7f1 '4M݋vΆwiwPWR2*ziX&?,kqη&te̕?_Kfi½.!"BbtcjHP9̩ .;p#+\k() %ft/NUҍ5+;3\MvЃppT)+@UK-"PA!aXíJ3F';HcUPN[⽷-ݰ8L"e~i1CYq?p>IͰix:K3jJ G|{ y ϪRWM 9R5M+\]y4Gr^B\2h h DZūAkЉo40GvsٮH"4DJٽD-n+Ub#T+Z\b2#$lzNEh=B s&Uf҃:jBEQPŹ+5֩u emG:Jf܆w0)=?7>d-1=^gLϯ Eh~>B}O1 R㖱2xV"(%BU}m2*ʸM9cvuPn5ŻxpsY1Cv*?K0q<'6_P$ƛQ^J}+oe0iR_yHrrF+u :$"KtBbSM!zz]:P󾡧"`0R'+ekO ؃iBJL+wbNhbr,k5]h4ӣs%0̢Qy.ZwA8+m8Qu.Wa-<H 5[?q(ct2")mM 4mH;‰ Nh NA,|p=Yrp]_\Xk~X[t5+9 PN 6Z[bPߣ44rG==0Ö5 e:xgBzE %HZ XWQv DiSL@Jǿt3y5i gy%iBv^Bzʙ$rG.9|GLPzEVygps }ݜ樈.A:ILA*~fy.޵g*XКr&Il j<%:]LFp997g]A@g`;l{91^OZH9O8*iO&F=l"u+(Vc硠dgd׬_)/(x|/M4-eyz;Š41oO8NL2}D"eN *tbǍ*SyH|O/0}1ΓrKRGt45KZn&C~|i S;RqWeJY`gW5J1ę`O*z?AC˰,J*H-]EB[{ Ώ^09Ĩ6wWeaSHyoyH*p-Up +!7]&+E|p&䏅/l]+bnqb {ğiT>P)dWxhpڀvI7 -,+1,w"?Iqx#h 6CiӪM/ Vd$ӤLZ[ ٨ꓣWʐ ws [jlUOM>>?A(bV,hP8/ͯY-!zF/֨e\M"̤eFFI!?7'-}aG5q7/:>YDV1YI FY.=L9'SPCۣd$>sAi8Tk,_5"O_,Τ)E3t~>@~Z{YUX[81ɇHѩ(}83&x `>~sS50cI?dFr)&1qe?iK=1C%!A>RG 윔b|觴F D`h8s;Lz7x)QeeOo8{2[.A];v!gG2; !;s.$Bܟ 1~5O@9AnU#oa`̲Mo7jA%^YcB_$aSM˄Ö[4Tc[mdc|}\3W2P%Ogh|2̖{f`ճT1K{ؔf{kiʐA,#'XHˇ 0k^t)G(ĺI8H 8-r[DFއAߚ oO#T.hvi3hlnr΋YOJ-TOgJJ #,kWՇ7 U&̟L}~Fe|[wPb",grk# ]+=`=]ńg ZFN AݏUzͮ6@d‡]j'tn܄e}ߞ? Da_!#qD'no9 jk+d~f/h!9(C{ c;qo^v*zp-[Ǚ:'(1ZrGάkwyjo'`r§{{&ONG>es]~*elyglSߠ7Wx5ט>W⁳m\ax. ^-qI>ܗFt e~p);%*wJȰuS7@ ZjNN8u}=.cH~$*pD'BGxJ]W!pۄ"h_L?b jN?(KoC'$P{>8o%q7ڍvw2«[ w 'YD\4Ʌ'ts{|hM3V<|t/K%Z+y[af 4ӾР$$])&< -֚k?35wL&hI׮O`Sc ؓ{J ;9綮^fP`jKBDOd ?Vt>&p&*;q5Ҟ pvtϗ3Lݡǣ1*/H.C]Uڤ#Yix>M`i@if0Xo4 8yMf]D21 SY޳کqTD&("D"eI\$vsJnؠoAt|'߈ -gSݠ!ޘ3&gCrNԛ%Zd% ddLqd)0CP}(o?a!~lr9KzP~3іuU۫Z'2u&b.wa]]С@C$ޛ 3%u|( q#z9E |#9v~ύ d~'a>HJU=&煪*uY+*?&^?RtMq⟀kLUYp?`I9ScaYqBC؈r:MjoU@ @ζ8~ʽA=4cI 'vÜ k$fW02F<Pr[g"VGQ#Qk+oWcǂi?p% ͜9`AzZrc/RJE"~DcY%~3"'$E͗sBUЋto1bD @|QD=O2! PL8Ī:Q6{ŐJ]4퉃Et ZA()ݫ L)!nJu*9CExN,>]8k)@ a OAڲDod]oMȩhWhp(UpnϑYmh .٫\!AsQU# bOKQQrb&wLo>B(9aaIw^~@([O*|Ѩ~?W=]i*KlZAUr{~c+|ug ^yBGxbNC23ae3 E8yGۜwsP/{6J?/Oej00DɗJ &&,ކ޶ vҁ$Mkϙ\GֈƉXd³#`!aDN8ߵ[nҰ#1x;(ܲS1WF]ߺ zd 3<:߿b ]d:wpGcWgPS5G rSv% HObmL$8jrpZF(b| >u8ܟu\jzC앵`nRv%rDz5$??[NJ韰< oZ=6HQ{Zmb海"2p v"˪J7n\YAVpH6 :tSvѝZ;O*f#|q1FNk7D%8l5$nߒk\eB nD\&%V6\9&cN|W_]-ϛ=P6@E=~)TA[k`P`MԛIyZ=]0!e֬df-kgT!nqQ- {ȓcHSše/$/ g5o'jM4D9J GȄKnȬ"DXY' 6s'yO*]z &ݭͱMmA|k);l7Uė^/Қ5G*šSUɂ Pf 2!G? jMUeeʻ2f]?ݠWT_~lRGyT{EKk:x]{M'ާO;ӓhxO>s:0}^J.;߽ W Ebt70IRԚD5Qf꺾tv t:-ӿ!8\Mǀܠ &CO0]6 eܙٜj$ }sԼWFrZXnq$bCg wY;8d/#/*gm*/lBʭłS0+GB;BU u'Qq* {a?v18 .leB38; ]^b*mڝE Jzdu4d4SKs&ʵj+Z_$QJ~5U7U~`G24ۋ>\7 ">QjUT |F3[YռtO߉g,ʑ?Q38C\<*X(R$zA`Ŷ+#a^4ϭ{RR+U>` la۸ Mb/ɵ4uj|Mơ@VGǺfmʴ9y0ؓrwx%̙yTxX*(gqo^~T'­FX iܷQ!,sh R&(xtf 9=L!0k~)wnE_^&͋Ekz!h&]Ufm},`Oo)L)'ҋ <ߘХT/g?Ɵ['B&5nBbPdK/6w؆.OV[G϶xǡ8 $RS'dgS$ z82lft~#~HnU ur/pQ9ܦ>pJ7[~}z*"^Ry!wcвkD 695,yJ )4 0ߛIIYںv9V+vШS}c%YU=->5C$ eWRخqMrC6@r0|2/))Oy NL,$!v1V;k~a2| TMKyV<=4J@1d,lZ( 3;8eR%swL$M?٘F1<7W\'a &4aTnGde <ҬP3M1 m9[ЛDÈQj[GNP&ZKs3@3U0)e8uZٜ~ Swjҡ[YڃPirh7L:x{Z]5 >y&F:gc3l~Ork0F1|X_7mCu3̢.k9fp[ɱy "~J"u: n[cN/y}1N3/fXUrCe:Xm>~mW#(%QoQ-K䪍S ؚY,<ڴ j>ܸ/b>մA.ׁOUf-W089]e7QbՑ|e F>X4ifӳ-1c&ϗ HhR!*~ :G X7_W#^]|$nes)- aV KW㑷R̎Tzp1!NAq+Pٖa # K$ yLHT; ڰs٪OROFx̉Oo7ûJ&z(Lvc]5VxI"d 5Wjy$YoPTU-lšП05vLjVl1NƂ\*r}VΨT@FAzOY)~3hG;L~$^$f+3w'< FJkLƜmN=[X~FTV*4Iɭ̝sκ mu =LtȮX5oԓ#~כW`P4[RZ6+NQ1"DX'88ݫU0>V[c؝"OPT"SˡP!4?޼_Ouq_`ܖ0e]0o&4_# >}#=hN-uWБmVzwO,(4f(iP8uudO Ѡ2NZ(Zwvi۠V#z.tRi)Ԭ5~b a Զ S"WÑ||eAӕ*Spt<]n[-+wJ1J##ʚ}= 8NJB5vxcP͘q!.4(zK t2'5&. )evq+~ ­++OGeY bM?Ǘ?[M᜸$er-ۏD,5ax*eXѼKkږ6ǒ-Vj Aj]'FfD62W3T+A293pS2s4Y)홮o_w˶a]:fTY2-Po难{xz}<;Fg "9|OԷ& %_<+HP̀{a] P *U;HYt}DK_ʶE*o=N> KV3xX]'M= ͉ȳZ4+V G ǢF9G6WlˡCc6X7ځT6`&;qot DT7XXcaOhǯ˟Dgs 5ޗڡzuM!>O* ^(Bl,kyK"%^X7,uR|8T̑ћRL՜5e9aj?i|͝γ:Pg-|HX6&g\OH,|;V†Dݕ=)\Y7ܵ^]w)yfZ"OTe{ 9UB:?^{{N Tt7ln#jsCl9 jwn0OW0w8H. $aUϑ|wC9v=׹/l\ ea=NMettLv!i楮:6ʔ&_|Bd9LIyϬ?M QE Q$۝ $.Z _'_c0Lp{XJLhēaFhJx‰s;pSON}0H1{w9׺zcQ,Z0oprn;~6| }2v`-!^e:i=g|?+"rVQmLÙ)JxLc )~;kZ025aBy`7 @xm=Gǚ]b1wR(]yC:֟Wэ{ Poyc,%ث.B/?mw_U['%]nZV8橆[3y+GF @qLL 9zm咋EEĀb9Rb 6>,ӴW|mܨbQ͝ eE6L^Zβ8Tla~ bfJ;˷r=R-<%$GpI"Mq$Qgȏs-13qڹ y<-Z.ZTlQ85.~m{9EN5z aKx͜@ř?z̭gWJ 8@]107PS_1$] I|m 7 v^ptgJr9 ԗdnG6<ZxЉqp\/~){;>~y'?K LQu9:&iiE_M_Pjž%Pd[V_ z 꿠\SO|IL~vU?n5d$Fv|l{-\oujxBtyw' udy%P#>[#)΂KnYz_¨.9A\/(t19&//v޷L2 뮌P VEb$8290ߞf\(1;yګDND Sg g7 KrKs^ξ'ip6M .IV# ~8\-& :T-.v^? |?䇶/5PϨ)i!Az2NP➀*6*Ȟ?]j(L"$S J{:-WY'@;.} 2e5UgfsEM@} &|U"J3H;^SB W䫇f=RMVπuh":)&v«ɟi-o~8HĨ9s學 7v@0Lؙ`X@z*ͅ/>k&w#Ò# P!($,^r"E=wh<%gՋ1tݑom 2x̹<,WOKruz*kf =1+UC1ń9bI@oiaAsg*a!3L^Cqdr4;8+ Xs'(k _prA\ެR%8mp@ `iSO_JuRg*:pg_g@LUG0:LwY~ 3^hyaH,Rd%mn7D׋-aT&,sTSOYaBP6!,Jj+f sTumKT=WfT},SIIUwyK D#މhj$iyMeAw9A@3R¶ ^-~_'lϫbقzLN4 j29j hNMWjjJ5N^М"MPu:7{L@41$opy+¬%c)P@6 k;]vJt(G=5ͧaJk`).!'jF` z+ g󊛴{/z81f $f+aq!j:E-|Pwq\"ն"!6m ]yÓJ_wy8M9}tC:#m-qҶq&L?Qtqp -"_F&6,?Y.?0v@%#Sb=aꬁMSqcc)t^yFc}fۢ%s.nR*yYGqnXh&ꐕؾ?VJ??t) ge>4}uyFFm Ԇ\ڀߏ LNP%)WFNv*\ӏR%mux\{&bL"^3"8uNՁA+O8C\ LuB0GD}t8_mznO0T>tY}wHIqsTt?9:u%VxQ.*6EN7Q!9x50w"5e jZ(SYRSwP1٠fuM蠫'2s͊:P ZAEDqk/ }o < _5QVPEu\Xy'U֤d` uJSK6wz })IO_,Еhv`I}FQg_}sb<Lj NxJ sZy`Vdl޽rb\䬯~8F?l,z?C(\*~|^[@ na.B"J4Rݛ8? ???j<.䐗辋Siq/i+ӽ:^;lY0uO乷FFd8Əfu]::;vZ0˜"-%Wk1 ɭC5,ai݄{Pt̹i}н47qWt-VoKhq,ZK<҈5DYw#cg/h0Z&a X>`{/ ١6:/lSÐ%klr85=0Ռ?"tE7@ҪI]{oZ$\bS["[FX15(>nR oN-EA~MZ)?)$m=GE/FlVp޴eP;f?kb1vX Tgމ OAQ[ԯሩOuSrjP]4⃖]lUlO5KjL[WM"Y`M1[M;\Z ݻzg [,*ҟ}u8JFX&J'IQk}Q[r5} 9\CTU2jxQ`X/A/$§:`{)FvI`';k+wZ > ĘjM%F'19өr!fH0S{f'hU߾\x!'Iz=Ηi="v'W <HhSn^1')d3NYVWhlϪ2%)U2ݶ eYnBྶ e$8ux@MXKb{[dnٽz..Mg,.XU8e8jiٓlpJ]^rTML+Gwڠ@(rԽ5ycoHd uYKՉ6EGiAµ:A>pRsz:rHGѦemh)P OSC&wT TC ~aH߲H!т·tNUy)ޖ3q>4!\f\w/zi!.`BĚbWݲ,4aym촮ch!$|_] f aI0zy_`6؀ ڶ}9T#t74\9>^^KVFYv n)_$h0XioBNg,ht3ҁt7HQ7i%ۍdϱ}~mmZ%&\Kg&mRg`(0GsyRjN飊&"0RbqlpۛTy:2wD䒄IW}GAC7i`tmHg[9u | gJw=<"cN'oBfV""XWgu8(즟v62}\9wD4brY5Y?dRN=@YxUByZ-(B!]^7NXNNK8:5 qwR9Oҫ<@SS%wB>>, {qy셿NOxcV`ę؏I`w 4nz$zRR&W2ȩLud/Ldv: 4yav:ĦrPN$6l^RP\oe߸ XOk=TEǺ)4~6^§ROwŀ׭RKG(`;Z6Feá|l3Gbt}凱y'toMYáy$8 C@C.L<΍p! %X>\S6[ZUp4JؤI[͕煞Ry>QQs[c> Q)B|Ul)$#tV4HCǚr)J8T>$+F5`4f{>T O%y 6Fܬ^MAS2w 8f+UBpvZQC:f7Ck'V0N^#"j>#@N늬5>H4Cc6?=Jk~ r{H"">{ETg< -8 eJ]AC#^# $q;jU w4$u ıoG,~5BcMJwQҪy<BXkqLJ'0 wAA w[ѩ Hs%'j i_@7U:rh~`M29>w/4U`Q1c LX zùA7_oO JBIXL慻hNgT9c#9=MHlsaiFx'-/")1 `L_*Ko}gIrJDA߷13Դ&wa1- JXd601;ኪJ0gU~|ׄ&C0C{OyF9&0DW8T>ȮdG_,M)YϭJS{’ +W6TRHIi@#Iƚwnn Y0Qr`HZs\HQ}c1Lei -;iDxMw'ӫѶVWH }܇<βRUiz=&|jQaogb#UgK薄W fΦ4F.񁔝7?kƷl3q@-T軵qTK_:XG#mMWaRAwt rSHaK/fI~]b"R$abԋ"FhlRFN㸿W-ܮ$E°ԎW#"n}_PFj ZmO-_Ő-,cn"݄;cI_ tAy3z}BS`JԞ[ N01.4冹l+n+I%vT/aH{?a5R|iBtj=RNG "ܽ*H""0ٲ#Mhdߦ#W ᫭ኑ &dIJw!ɺ#"0"G"}w_ш4E/9*(DIgZ(6!1gvYreaŒ#p~W,s o|.mUKg_7ɋ!owXλ"Q&X(H- 1UOSk760z9:5V1U?a`1 Ze{ I+m/Gqh!aW(F|Bou(0vʚg7 rvw쮇"%=xLAB+h W%, s~t#zq3U3(J;ɖ̓ "51?]YߧH;8EBTl.}as ~^$ֱnqYG<뤄 'P߿C!kdR%j)Kd-kGI)CK@ e0\c*WwCSƦhAL)/M̾~VV ,-ɵ~s&;D?;pL+;NҜr49 )HjaY` |K *"jW!:AɛxNAHMjsÎVT[p ?kL3 "^K3. iTG$Zs(ur: =|mqndB;pN38}M:B35`ojoؼ>%wT#d1[3RO 2d4A]n(}&e6!'`A,6 rO˗lT} $KZ )idZپv~+ilc' $M?-\8pΓm&^6 cX^$}=_\Inxʞ�@Ⱥx(rtK3ۢFqB=:]/iRa_zQcw:db:}PHXkȵi֖+LtB7]o b~t阱Z)ؚtzx0S;W?շۻRῦt\2GѠVlO(CF<̈j}}Æ_̱@pi4)ŏͿ(lsxD(SK'Su>ԙVf\rJѸ{sM[PcKwsjrȢ iigyX_1<K-c3|_eϊϼ3$oAs1P܍'h/3Wl(pڲd Z.!jܨtHރjGt!/*[dC9׎1qd&~0unZ#â#awtC!n쑜SD\g/%Mˉp`r%ד=QhzRgc~ =AW`52^gF#N Ãr{Fj@ZoNݒ>Jݵ]tLa84CqFzm8z#Z#L~F5LwY#m>udS\{_rmqH_8S6WGݘAuVP}o/yұ~-E1aFv.%XaLR|/{˳?  QHd{[ ~UqHt% byM}0+{sȨ,+w5]Q[nmm"e6|7~]&\q.'XOqGes /\-}keљf1mmA/̆sYhOstITNz)lFŹ4w-+y& bFqliv)[qґP"rK\/phަu(TQR cWӚMO?ٗpXς/pۺj|Y7_+bB@H:{7ˁT7WmYiXAuJ;ʹMK_;8\iXK-H B"\ؚtfz9f |.E# h_\މ{4WQkp)}z`+k3w"<ʯU;1wM@Ȫq@*8ٴП5p✓ZD~ON0u&?ܿ;{EM.Y3)Tk y"?"Ȇ=Mio.1wp~>5?o4 vE񹕞Dϓ 7*FQg5DVH|)=36; 6gU+>uFj_z6NfTpیϕO[23&bIW]=wGАG}s4a2\FKoF"Ji0>1?s1C@fz-Xu>`FezjMn֥)~X@3neS9( ֻryiubEc{GyNwD]~u>Qf4R{A:䙜$۸R`8fĩ. .l۞~[FWT:۾#x$C5 {m~X_6b&B*(n{a;Hy['/2b4~N Y&|ʍ‰Ee1:M7oՔ\ظz[zOA|DhNFvJ/B7 n(.ik]G>PSUkX?(D#>݊!vlqL?'>DlDU Y W?ي%Բ>3ow'=53{, Wc@.9YhrC(]/XWs(g$3n >d(jew&!X_ibixH"V+OwŠ.Ԁ,ְ5ǠJFĨr mtu yQJ|gr[s7i֫ ,|(s67n#WEGuT?_+GEtW!/"Y ڱŠ#Xh[}`w5)DL>)U`%mL*s.vĊlG^LN* ƪ A屜2jpT:)ݚ#Z*IӾ0tE5Qۃe\Jrh$?טxGvFg NpW\+#tvd݅d6">~(EP#iؙ ΐu Yig|p95tu)78{k{+-'06g-iZnWޤL1"i%e.2 xԞy`8"Sca\-/1O3]AbkzF3[mBq}HDv }\#]vm Bi0qr 7i27)ˊcuwq(<2yq4\BzSIQA20/͉"mT&S~ ny@|Kxakj~<$u_46¹qIc\<^ @*  }Z?^ oTqIdJOަ n!y\BM2u׏o|Z0/ųNj]s$6Kg䂚e `?펧|7eۥӟzJ-0Sy#n78RfR83 }b4&R|q_K똭ЉU=Wgi)#Y/ _:8MnZDA%A /ÇEVlVУ;! MŨz62 h54Ӷrz<&I7_״ TRMPMKMx;3fIСs3L(}JehZ6e4vxZ,%f}ڞQH&,~f^*Yf[SmBi|aw,E4z 6gn?@A_yAɬm\) ݘ$ d%!tHnI]qUlXY1s o'DNzgve2@QwM@ QGe~\cW&6x?5ZY$6y&:1rxn>g$!q l/E f}Ó,VCH͒7W\5JԶ?oVnX0v}(Bsrm/ E8d:j4Q& 9F"~2-W$ ݢ(W` gA m!|9cG 8%ȁB %1Sk 4+V]!YRApf|:XݝNi 0rӞp!;472:oa<ixӭK-pc} = n~Od`kF'Kzb}ldT`-BlvӱH#6=W'H8U?LevR:zPy"rlk.ki ؠ!_XZ{47[#ĹaV>]@Jyd(mT‹_X>~AC^)tNDT$.+\wN4»)-8Pc;KXWdw! ővE$J-WM&.([¨XbiN)S'Oês5d-:,ћ]BW6"x*40yhMf0{5B}:?I-N-BD3)? P3eQz~c |PsdkUJW>Pa?vasȖV.G#]WOHU0xǝ)| v8{SR?rLnշ@.=ÒI郴K]/EM.qwu^)A>`vzGP%T)EKY޿-XFѰ[ʛ(>k )>*aZy- hV>c\=g٪Ƚ`iZCfKI#iLϧxu̦tʷzJw .!:5zBCWXۘ *ꖓ 4\C۳(GgHD Zm*rlD/OUT۾Kb]|LJ} fS=+hU F'[hE `*uN T~0u$_?ޒ1tY-Dc?Q4>X2zv5pVⓠ #}ٷ2-9ڣ4?RFЬ||2k_mF!'Ns+="ԿF6hVF)²<2yyJw k]S٣|g_O,V'f,[o ީ5v ҁ&un]ₒ쮹-z ACc"]Nn/G*ie+)v8{$l`I"w̋wSBK~HP%+l! %"gi]AzʖJ*wxea`W :8޿Kʓ)1]Ԛ ʕ mFu\D<ŭcz'6/13߈**_!j^JJF' Ky}AJ 'NGu a|m% kI>fڏ2?*f bģmF|[p %j??fT?lͶACYr.b2H4~E<!A hfeӲ{W@]([9Cye`ĻJ~tWxiܖCX aIケUZTwq,@J*YdDWWˣ,)Mlc»_ʒFc"W*@}Gck S^1vT;<@٫ĊX =MVF|R]x%GnCNԧToe% 6P |\"Mۡ\D.0T9yx.Ri mgRw>\z L10N>y`i+ܪz*.}D")U. (K*}+cmS:Q6PӍUM<aVA&Fcٕ AwpF!ɏ }SRE˃Ƙ(_DZ:?N\A!(> M0 F$/ƿV`4iŠJ8AMs+!ldp 5YRzXwɜPσċZr_tA,&[H`vz?Qd#((}{7-RRT^ iµEXFŃz5غBWvӆKK~)QA׋z^1 s!QU6n7al^M_*|ˠk~?<ϒ~-(+p[wdW?ܚ&?'Fkhrk/ MvT5nN>1((L,QJ)6FY`+⌇Nbxl7mHjPj}Us)&[?ǣ5'Dֶt&͐phujM6004̳})${RɈ=oje$1|an[Ɍk+> 7V}YUFAg,8??Qzߍuu t'< iPg켉4ͷX.?a|tg/7%# B ;'hv⎹lJ->K6jҼF7 n]Ddsads&tlI޸gU! b[ Wcd3تDBǟn䏁?C[IV &qhZSY,'D,P8m3z:+ğq xlRZGM lIJ9? 1q"쎗9Yv H!oG]U, \sQ&xϤ w+?y-)R;>DҐ%bU44:Q>@#L2ok3_vWXRK' E blNsCm}{C{u~_P7}QA"nW6ւb\*vg*]5f1sϧt\W5ƨ# cckx]c5!J)t"`WE7W)*ĶD @1~nghx ઐr˞JqNڮ%Ȯ^B!^` hϾH گV-mh/E:3!A8ƫ.ʾ3ZpI^GqI&y|Co_C4nK}$Uah?{2>~'{kwn'h>+z"Pf/2.7yl:m($̐kA8g۾O"J-&&}) kjk V4cOo~_YoX(3KAKcDG$]Qjk;K]gN:CXY*!ʪ܉:>}]k37|%%tFuǷpBX_n= +D욦mLZ 999y e}q&fo5 %23ד2:Ƃ l5T 7Zmޛz@pL?݉Ǡ IG*pgi]ΏQH7>J1 tȟ&77@~Z=t{?''dJᢩ/myF s{!M& >n)2QɒfBIZ?wZf=[nÊH-lvM^4G.'FSti&'m\/J{kO2,͇[sV3vJx(b\n賍ju.*rieODz!ܸ+Bi?1 fN(s@ل)/Dyƣr9K:ꂲ-|V{/ϐ]@RvJB*Pr'AtE~˞OgrRdyz[,>.Yiα?5D޴/> BKK;#x"O^|xHua5LPƳ[T_ChNW kEY=5+ܮKx(RTnQg1>Q[v"f<犎@uAVh}Ș{ɚbȥu$雞c4BjD_%1J̎I`! ΔVx95oHzZjXa_+BY7OBjdC=هNV" /x^xij(kOůTPż+_gpg;]R"cCoFQgaCa2=$xmy-#8/SLMޒKvsWԐ\)d6*PV`} `? dIq ,7vV-I^Prs[H4=VkpP8Rx_,vZȔ:wi⳴c-#(%-sUʓ:J0lm UGhL@`PW˅oJlQgpD, Gпd.Ɯ,ؾnU@4Pݧ&[=$4TZ0hgO-{Z^r5'gGB|7gx|L3u4mKJ:85,AĆ3R}l>I !e@>C[RvmpZ;HCv.(^pRt< Rz tn <&Y6 _X½ۅoNO3ƕysRJ!wb~|b@t1=VS`}ChϜsB7nir:}/AttK~sIC:׺Y3qYKWk<_}!S;ߪU[ 9 P=_OR$ۑٴ` p:gsddFոzNݠ̲Mt-uYT^sXϽi?Zu 3TUI|?a`9=n1Oa'qkGoC va1˺cr/ʝ n8c>$ԓZK/~8"wʍ3BH]I7bTB`1S'G,=)X[%2E;_W?. _bm)s#F,4aRBNƨ鸻|Y z@chC2B?}9GݞCl;T6D:)GY*}>RV(Otf\s=/-K[df @E6$"@‰#p, 0fQ%}blE߸;C%U3=QWtFkIb9ҹ.c,WyU,9*zʀ+C7KRl< uX 4A-Y*<殮mAv>kdÑ?ɓ!>8 UQ{jL5R|ҋ";q@ci4 hg60}ztb;_/ԍ",I覸jAњG\Z։bPG&W|Bƶ{AxN<2]w@(׸ŗ ݔ&B`fZ,|)k(x+UcD=6}tlfEam&S+-ih\!RMTfܫenKI"=__D2lwdC;YA5iУ1^YB!uw_SB+L"nw [BVmD59%wi|nG_o]-,hyBjX{QaΚn y3jmeS'h =]ES2iKŵNj.Հhz*hsop3d ǹw29Ȣ}Ö!_8r0cFn>|ACl,X&(zr8^c7Bo4=0=n%<wK:Gip$<rp=x]z!Cq9{m}lp'&^j_|D1JbͯI+o[O4 6 iy%-ѽ -ݺkV͚RlG6ȥ_?]Diʇ瓺&YKVGZǺZ.N{d߸1DVmoR$?9orap4F}w)2:jekLuY_ C$Fznd}K A lTgpu}wœlzh2}[ ]!0aBhd  qHC ^CcUpL]χ. pD vI: S_ה>; -ڦAE[6J#t`Ӑ )\uÖ7L1`R] e\Psk[Tk 8|7H[@Nv8!ʍ,zH\ ˤ(+'qt*id웰u1#.*"I̅I]:$N0ɿz-b:YCr+Jf9_i x[lr2v0ONr $ZqJR @CTGۆ894H4eKgo'㠙}1%\wLi:pWT dCcEU:0!ܼ5-~aW=.5(l h+GmrIqMDZ˯0t[{ЪH ٿFo*LVMUdz{GxS3@mBq+娚 UJ9&Rz CdԚ$dBȀq@1$ŀ= -H9cդ7) u_xЉW-:"Bv~{+_E`^NE :4 My[u%)ێ}ـ6ގ H['{..zlBvn`8?VZa98@O64ADD\ŒRW c_ݴ|JA@b]\+@˲Ű& PQ= aZb &@UiL2Qvhz.AvVSg2֓>'SppO>~"7ȜGpInyJR32Qka|d?Cߘ/PUgYwf:уͷ7F&H0{_6 ×ڵ3yOoT N)Z0|ۇ6</! Z]{H&r@kRce=zvxTIIJ~lwm9d1(Bno\ V]ktO `ځ><{F G3BPVLw,@ 0>zlw jqe&-5<㤊L@dc(~_PtdO74@X"|  WH,aF];jL}zi_]>wwFQ+d?PſX@>}]4J BwB ډS[~ #&TkqիdQފèeh\rZpЊOڌ9fARW|< hD`FNزr/!R0 0yN٘99b%M.*xEW>SZFċ0/GY" W7C'6Jދ>N/lSJDQU1OƇ=DM-&TCփΩu6MP&iܞyїjU%gr9l,EmX׏oQ1 ;!zN5aY˯Zі*c~*|C2Kޯ?*/Gޥ YMJtc x;ThIQ|;^ABB%2х B?40 |؈՜ KLqvt ŵ{,.T@fzq;fuOʅ4BSt5wE.uy6\$x)uc0*5DE%La'[`->'~Q jwUKbi"gm[}KRd@햴 dc/_Z떹$J]#EWZaOyf'٭j&N9Ijm'9Q[߼b/R^U1=PI7$O:bJo@bGӇɑI`{Mu2AlWEm:?.{/ZmF⹞E^EHA|}R) &bֿ8p&ǡ= @D@|Ayx~i ݳO;WXѾ) b]f񦗜?6#b!܂Ar\0v%oIcHhk>.]n̨҆7/4ҞGO%4xg/'WLY ۤC  Bp Kk(&H1VXFE*R/f=zO˧b\RaB^;ƸCaаdG?gɭ7G3戠kaTA8#(CN;cҎ)wQU־a#.2PoƂiGSby@&)uuW}&t}gA {(Hsނ!Q_ oWfM/#֚^(v=!J\v1 %{V9yܵ]<.RdV*dP RMzY\K=Eԝ}y(hu "sY:Zi%o#C4ۀYqK6H7X(r#aYZ T9S$E4* cw?$4o_ʁ옠qUoةkܟ?K׋WlOzᬄ!#] :[KYIaCД2pMiHź>.Y^ 3#15G$[\ņm1pXn7‘핢LT4)IotV=^߳ffmу ʢX?"w~{G{ )O"߈KI7᐀RhbTV3Y y+"5 "3jfu-y4␠Dqdfw`|F[0'ceAev|39rx$; JM-&B^& D;r.ji+@Fx8v0t紼ñQb\} {v29\e_D)N \5"5 M?SZtQD)^B@@O%doSuHS"~MsZ1ދBU|_sO4Q'LύY2f5,ahH<*({g})gz/uib-:I^_ :)Q\@^vtym_j{J=_B9c=1*p]oou(b^7 />Ms=Em7ceTHߣ=]}#٦rY} #)alcv,dJ7zKwV2$`!69 #{*d5 ku VʎS[`izF>nfu:)ݻ 8EnjZp\4a>m-'b+(ڗ rCC.,5c̑չH06@uφ%'G\3ɠDV!.e^ ^6Š5}hc.0_HW \٘MUw@-tWVlvrus;$,8ThFH$,S- B(4 Im:肹mOy6;M +c<^QsD<]i`deKbI[7J,I;lQ8"*4&( "kn5.OR #v;w0 | _҃(4:W)`-xM9@WÓ*6KD ϖ%=a̍.i{vBGKUW>|>g+LK Nh?[Jr]ZM\N#6ȨJYm_p,JͭO͞fN80)4{ۗkJwUWmϵ|ƜJI[Ԁj')!zߝ߀u\~=p-+NB_N>Z༣G4fsIN4j[ uq jE]GvvDE[i}=.SJOjRPn{$(ϝ<&͖cdAfCW$!:N4`;QN˽Gש.oED0@78g}$}Om y.9־*ZQ% s@qfLJoĨZS{VM:tUU`H ;rOw\~дE%? r JTY10/v@Bym3aGT Y&j~,b*5JR-yO>MGSM ɢS|ę*Ylw4VilBymF*!N}O?h`VQPL !3_hv5̿lS0(uZN>4 u^`luJ `G z=Chchvd*Ӑ̪ !PꄁG9@=!)Y ,^l̿_H|NaL l);SIe*r4Iϥ(!#^u'YTp4wG&!~X/dev/null rdup-1.1.15/testsuite/rdup/rdup.fuzzing2.exp000066400000000000000000000003111303430127500210120ustar00rootroot00000000000000set test "Fuzzing test with rdup-up. Should fail without output" if { [catch { exec ./testsuite/rdup/rdup.fuzzing2.helper } msg] } { pass "$test" } else { puts stderr "$msg" fail "$test" } rdup-1.1.15/testsuite/rdup/rdup.fuzzing2.helper000077500000000000000000000001141303430127500215010ustar00rootroot00000000000000#!/bin/bash cat testsuite/rdup/rdup.fuzzing1.data | ./rdup-up -T >/dev/null rdup-1.1.15/testsuite/rdup/rdup.hardlink-strip.exp000066400000000000000000000003231303430127500221720ustar00rootroot00000000000000set test "Run rdup | rdup-up -s 1 on a dir with a hardlink" # we expect NO output at all spawn ./testsuite/rdup/rdup.hardlink-strip.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.hardlink-strip.helper000077500000000000000000000003501303430127500226600ustar00rootroot00000000000000( cd testsuite/rdup ; rm rdup.hardlink.link 2>/dev/null; ln rdup.hardlink.helper rdup.hardlink.link ) ./rdup /dev/null testsuite | ./rdup-up -s 1 -t /tmp/test.$$ rm testsuite/rdup/rdup.hardlink.link 2>/dev/null rm -rf /tmp/test.$$ rdup-1.1.15/testsuite/rdup/rdup.hardlink-strip2.exp000066400000000000000000000003241303430127500222550ustar00rootroot00000000000000set test "Run rdup | rdup-up -s 2 on a dir with a hardlink" # we expect NO output at all spawn ./testsuite/rdup/rdup.hardlink-strip2.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.hardlink-strip2.helper000077500000000000000000000003501303430127500227420ustar00rootroot00000000000000( cd testsuite/rdup ; rm rdup.hardlink.link 2>/dev/null; ln rdup.hardlink.helper rdup.hardlink.link ) ./rdup /dev/null testsuite | ./rdup-up -s 2 -t /tmp/test.$$ rm testsuite/rdup/rdup.hardlink.link 2>/dev/null rm -rf /tmp/test.$$ rdup-1.1.15/testsuite/rdup/rdup.hardlink.exp000066400000000000000000000003101303430127500210270ustar00rootroot00000000000000set test "Run rdup | rdup-up on a dir with a hardlink" # we expect NO output at all spawn ./testsuite/rdup/rdup.hardlink.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.hardlink.helper000077500000000000000000000003431303430127500215230ustar00rootroot00000000000000( cd testsuite/rdup ; rm rdup.hardlink.link 2>/dev/null; ln rdup.hardlink.helper rdup.hardlink.link ) ./rdup /dev/null testsuite | ./rdup-up -t /tmp/test.$$ rm testsuite/rdup/rdup.hardlink.link 2>/dev/null rm -rf /tmp/test.$$ rdup-1.1.15/testsuite/rdup/rdup.incr-readonly-dir.exp000066400000000000000000000003731303430127500225660ustar00rootroot00000000000000set test "Incremental backup with readonly directory" # should not yield any output spawn ./testsuite/rdup/rdup.incr-readonly-dir.helper expect { -re "fail on the first" { xfail "$test" } -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.incr-readonly-dir.helper000077500000000000000000000015121303430127500232500ustar00rootroot00000000000000#!/bin/bash # this takes place in the rdup source tree # make sure the executables used are also # these PATH=`pwd`:.:$PATH #this test fails on the first, because we move #the current backup to 01 if [ $(date +%d) -eq "01" ]; then echo fail on the first exit fi # test rdup-simple with mcrypt and path enryption rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp # create doc2 dir, which is readonly if [ -d doc2 ]; then echo "Dir exists"; # makes test fail exit fi cp -rap doc doc2 chmod a-w doc2 # setup rdup-simple with doc2 ./rdup-simple doc doc2 tmp # fails on the first ( cd tmp; cd *; mv [0-9][0-9] 01 ) # without doc2 ./rdup-simple doc doc2 tmp sleep 1 chmod -R a+w tmp rm -rf tmp rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp chmod a+w doc2 rm -rf doc2 rdup-1.1.15/testsuite/rdup/rdup.incr-rm-file.exp000066400000000000000000000003021303430127500215200ustar00rootroot00000000000000set test "Do a incr rdup dump when a file is removed" if { [catch { exec ./testsuite/rdup/rdup.incr-rm-file.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.incr-rm-file.helper000077500000000000000000000005741303430127500222210ustar00rootroot00000000000000#!/bin/bash rm LIJST TIMESTAMP 2>/dev/null cp -rap doc doc-test ./rdup -N TIMESTAMP LIJST doc-test | ./rdup-up -t /tmp/doc-backup # deleting a file and redo the backup rm doc-test/rdup-backups.7 ./rdup -N TIMESTAMP LIJST doc-test | ./rdup-up -t doc-backup EXIT=$? rm LIJST TIMESTAMP 2>/dev/null rm -rf doc-test /tmp/doc-backup 2>/dev/null rm -rf doc-test 2>/dev/null exit $EXIT rdup-1.1.15/testsuite/rdup/rdup.incr-rm-link.exp000066400000000000000000000003051303430127500215410ustar00rootroot00000000000000set test "Do a incr rdup dump when a symlink is removed" if { [catch { exec ./testsuite/rdup/rdup.incr-rm-link.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.incr-rm-link.helper000077500000000000000000000005641303430127500222360ustar00rootroot00000000000000#!/bin/bash rm LIJST TIMESTAMP 2>/dev/null cp -rap doc doc-test ( cd doc-test; ln -s rdup-backups.7 symlink ) ./rdup -N TIMESTAMP LIJST doc | ./rdup-up -t doc-backup # deleting the link and redo the backup rm doc-test/symlink ./rdup -N TIMESTAMP LIJST doc | ./rdup-up -t doc-backup EXIT=$? rm LIJST TIMESTAMP 2>/dev/null rm -rf doc-test doc-backup 2>/dev/null exit $EXIT rdup-1.1.15/testsuite/rdup/rdup.incr.exp000066400000000000000000000002431303430127500201730ustar00rootroot00000000000000set test "Do a incr rdup dump" if { [catch { exec ./testsuite/rdup/rdup.incr.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.incr.helper000077500000000000000000000011031303430127500206550ustar00rootroot00000000000000#!/bin/bash rm -rf A rm -f $$.timestamp $$.lijst # some some bogus dirs mkdir -p A/a A/b A/d touch A/a/1 A/a/2 A/a/3 touch A/b/1 A/b/2 A/b/3 touch A/d/1 A/d/2 A/d/3 for i in e f g h i k l m n; do touch A/$i ; done sleep 1 # otherwise timestamp is equal to just created files ./rdup -F '%p%n\n' -N $$.timestamp $$.lijst A > /dev/null # incr dump, expect only the dirs diff -u <(\ ./rdup -F '%p%n\n' -N $$.timestamp $$.lijst A |\ sed -n -e '\m/A/mp' | sed -re 's|(^.).*(/[a-z].*)|\1\2|' ) \ <(cat < /dev/null ( cd A mv a c # swap mv b a mv c b ) # we expect a b to be included in the backup # dont you love shell scripting diff -u <(\ ./rdup -F '%p%n\n' -N $$.timestamp $$.lijst A |\ sed -n -e '\m/A/mp' |\ sed -re 's/(^.).*([ab].*)/\1\2/') \ <(cat < /dev/null # this is why new_dir has been removed from crawler.c ( cd A mkdir j ) # files to expect to be included in the backup diff -u <(\ ./rdup -F '%p%n\n' -N $$.timestamp $$.lijst A |\ sed -n -e '\m/A/mp' | sed -re 's/.*(\/.)$/\1/') \ <(cat < /dev/null | grep "`pwd`/nobackup-symlink" | wc -l) dev_null_present=$(./rdup -v /dev/null nobackup-symlink 2> /dev/null | grep "`pwd`/nobackup-symlink" | grep /dev/null | wc -l) if [ $total -ne 5 ];then echo FOUT fi if [ $dev_null_present -ne 1 ];then echo FOUT fi rm -Rf nobackup-symlink rdup-1.1.15/testsuite/rdup/rdup.nobackup1.exp000066400000000000000000000002501303430127500211210ustar00rootroot00000000000000set test "Create a backup of a dir with .nobackup" spawn ./testsuite/rdup/rdup.nobackup1.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.nobackup1.helper000077500000000000000000000003211303430127500216060ustar00rootroot00000000000000#!/bin/bash touch doc/.nobackup total=$(./rdup -v /dev/null doc 2> /dev/null | grep 'doc/' | wc -l) # total should be 1 doc/.nobackup + zero content if [ $total -ne 1 ];then echo FOUT fi rm doc/.nobackup rdup-1.1.15/testsuite/rdup/rdup.nobackup2.exp000066400000000000000000000002721303430127500211260ustar00rootroot00000000000000set test "Create a backup of a dir with .nobackup, but with -n flag" spawn ./testsuite/rdup/rdup.nobackup1.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.nobackup2.helper000077500000000000000000000002771303430127500216210ustar00rootroot00000000000000#!/bin/bash touch doc/.nobackup total=$(./rdup -nv /dev/null doc 2> /dev/null | grep 'doc/' | wc -l) # total should be more than 1 if [ $total -lt 2 ];then echo FOUT fi rm doc/.nobackup rdup-1.1.15/testsuite/rdup/rdup.nonwritedir.exp000066400000000000000000000002571303430127500216110ustar00rootroot00000000000000set test "rdup-up with non writeable dir must yield no errors" spawn ./testsuite/rdup/rdup.nonwritedir.helper expect { -re "" { pass "$test" } default { fail "$test" } } rdup-1.1.15/testsuite/rdup/rdup.nonwritedir.helper000077500000000000000000000003211303430127500222670ustar00rootroot00000000000000#!/bin/bash mkdir A mkdir A/a touch A/a/1 touch A/a/2 # tada chmod a-w A/a ./rdup /dev/null A | ./rdup-up -t /tmp/rdup.test$$ chmod a+w A/a && rm -rf A chmod -R a+w /tmp/rdup.test$$/ rm -rf /tmp/rdup.test$$ rdup-1.1.15/testsuite/rdup/rdup.nonzero.exp000066400000000000000000000002261303430127500207330ustar00rootroot00000000000000set test "Run rdup -X which should fail" if { [catch { exec ./rdup -X } msg] } { #puts stderr "$msg" pass "$test" } else { fail "$test" } rdup-1.1.15/testsuite/rdup/rdup.pipeline.exp000066400000000000000000000003741303430127500210520ustar00rootroot00000000000000# run rdup in a complete pipeline # probably depends on GNU tar - fine for now set test "Run rdup | rdup-tr -Otar | tar" spawn ./testsuite/rdup/rdup.pipeline.helper expect { -re "^tar: Removing leading" { pass "$test" } default { fail "$test" } } rdup-1.1.15/testsuite/rdup/rdup.pipeline.helper000077500000000000000000000001141303430127500215300ustar00rootroot00000000000000./rdup -Pcat -Pgzip -Pcat /dev/null testsuite | ./rdup-tr -Otar | tar tvf - rdup-1.1.15/testsuite/rdup/rdup.r-flag.exp000066400000000000000000000002201303430127500204030ustar00rootroot00000000000000set test "rdup -r /dev/null . must be empty" spawn ./rdup -c -r /dev/null . expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.rdup-hash.exp000066400000000000000000000002571303430127500211400ustar00rootroot00000000000000set test "Run rdup with file hashing" if { [catch { exec ./testsuite/rdup/rdup.rdup-hash.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.rdup-hash.helper000077500000000000000000000000641303430127500216220ustar00rootroot00000000000000#!/bin/bash ./rdup -F '%n %H\n' /dev/null testsuite rdup-1.1.15/testsuite/rdup/rdup.rdup-tr-crypt.exp000066400000000000000000000002541303430127500217760ustar00rootroot00000000000000set test "Run rdup-tr -X test" if { [catch { exec ./testsuite/rdup/rdup.rdup-tr-crypt.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.rdup-tr-crypt.helper000077500000000000000000000003621303430127500224640ustar00rootroot00000000000000#!/bin/bash # do we have encryption if cat /dev/null | ./rdup-tr -X<(echo Boe1234567890123) -c; then : else exit 0; fi # shoud give zero exit code ./rdup /dev/null testsuite | ./rdup-tr -X<(echo Boe1234567890123) | ./rdup-up -T > /dev/null rdup-1.1.15/testsuite/rdup/rdup.rdup-tr-decrypt.exp000066400000000000000000000002561303430127500223110ustar00rootroot00000000000000set test "Run rdup-tr -Y test" if { [catch { exec ./testsuite/rdup/rdup.rdup-tr-decrypt.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.rdup-tr-decrypt.helper000077500000000000000000000004331303430127500227740ustar00rootroot00000000000000#!/bin/bash # do we have encryption if cat /dev/null | ./rdup-tr -X<(echo Boe1234567890123) -c; then : else exit 0; fi # shoud give zero exit code ./rdup /dev/null testsuite | ./rdup-tr -X<(echo Boe1234567890123) | \ ./rdup-tr -Y<(echo Boe1234567890123) | ./rdup-up -T > /dev/null rdup-1.1.15/testsuite/rdup/rdup.rdup-tr-encrypt.exp000066400000000000000000000002701303430127500223170ustar00rootroot00000000000000set test "Run rdup-tr -X pipeline tests" if { [catch { exec ./testsuite/rdup/rdup.rdup-tr-encrypt.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.rdup-tr-encrypt.helper000077500000000000000000000004401303430127500230040ustar00rootroot00000000000000#!/bin/bash # do we have encryption if cat /dev/null | ./rdup-tr -X<(echo Boe1234567890123) -c; then : else exit 0; fi # shoud give zero exit code ./rdup /dev/null testsuite | ./rdup-tr -X<(echo Boe1234567890123) | \ ./rdup-tr -Y<(echo Boe1234567890123) | ./rdup-up -T | grep testsuite rdup-1.1.15/testsuite/rdup/rdup.rdup-up-n.exp000066400000000000000000000002571303430127500210740ustar00rootroot00000000000000set test "Run rdup-up -n dryrun test" if { [catch { exec ./testsuite/rdup/rdup.rdup-up-n.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.rdup-up-n.helper000077500000000000000000000001301303430127500215500ustar00rootroot00000000000000#!/bin/bash # should not crash ./rdup /dev/null testsuite | ./rdup-up -nt /tmp/test.$$ rdup-1.1.15/testsuite/rdup/rdup.rdup-up-s.exp000066400000000000000000000002521303430127500210740ustar00rootroot00000000000000set test "Run rdup-up -s 2 test" if { [catch { exec ./testsuite/rdup/rdup.rdup-up-s.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.rdup-up-s.helper000077500000000000000000000001651303430127500215650ustar00rootroot00000000000000#!/bin/bash # should give no output ./rdup /dev/null testsuite | ./rdup-up -s 2 -t /tmp/test.$$ rm -rf /tmp/test.$$ rdup-1.1.15/testsuite/rdup/rdup.rdup-up-t-with-file.exp000066400000000000000000000003561303430127500227700ustar00rootroot00000000000000set test "Run rdup-up -t file - should fail" file copy /bin/cat testsuite/rdup/b if { [catch { exec ./rdup-up -t testsuite/rdup/b } msg] } { pass "$test" } else { puts stderr "$msg" fail "$test" } file delete testsuite/rdup/b rdup-1.1.15/testsuite/rdup/rdup.rdup-up.data000066400000000000000000001533061303430127500207620ustar00rootroot00000000000000+d 0755 0 0 5 0 /home+d 0755 1000 1000 11 0 /home/miekg+d 0755 1000 1000 15 0 /home/miekg/bin+- 0755 1000 1000 39 889 /home/miekg/bin/apache2-ssl-certificate01BLOCK00889 #!/bin/sh -e if [ "$1" != "--force" -a -f /etc/apache2/ssl/apache.pem ]; then echo "/etc/apache2/ssl/apache.pem exists! Use \"$0 --force.\"" exit 0 fi if [ "$1" = "--force" ]; then shift fi echo echo creating selfsigned certificate echo "replace it with one signed by a certification authority (CA)" echo echo enter your ServerName at the Common Name prompt echo echo If you want your certificate to expire after x days call this programm echo with "-days x" # use special .cnf, because with normal one no valid selfsigned # certificate is created export RANDFILE=/dev/random openssl req $@ -config /etc/ssleay.cnf \ -new -x509 -nodes -out /etc/apache2/ssl/apache.pem \ -keyout /etc/apache2/ssl/apache.pem chmod 600 /etc/apache2/ssl/apache.pem ln -sf /etc/apache2/ssl/apache.pem \ /etc/apache2/ssl/`/usr/bin/openssl \ x509 -noout -hash < /etc/apache2/ssl/apache.pem`.0 01BLOCK00000 +- 0755 1000 1000 18 14 /home/miekg/bin/cx01BLOCK00014 chmod +x "$@" 01BLOCK00000 +- 0755 1000 1000 21 1651 /home/miekg/bin/diary01BLOCK01651 #!/bin/bash # default maak notitie EDITOR=vim # git kan niet overweg met een absolute padnaam # gpg encrypt de entries. We laten dit doen door VIM # die snapt gewoon .gpg extensies DOCDIR=docs/.diary CMD=$(basename $0) if [ "$1" = "-h" ]; then echo "Gebruik: diary cat [YYYY-[MM-[DD]]] | ls N | wc" echo " diary [yesterday|gisteren]" exit 0 fi if [ ! -d ~/$DOCDIR ]; then echo $CMD: ~/$DOCDIR moet een directory zijn >&2 exit 1 fi case $1 in cat) #2 heeft jaar 2008, maand 2008-04 of dag 2008-04-15 P=$2 case $P in yest*|gist*) P=$(date --date '1 day ago' +%Y-%m-%d) ;; la*) P=$(ls -tr ~/$DOCDIR | tail -1) ;; esac for i in ~/$DOCDIR/$P*; do # with zero files * does not expand if [ -f $i ]; then echo $i if echo $i | grep -q '.gpg$'; then # gpg extension gpg -d $i else cat $i fi echo \$ fi done exit 0 ;; ls) # $2 heeft aantal ls ~/$DOCDIR | sort -n | tail -$2 exit 0 ;; wc) ls ~/$DOCDIR | wc -l exit 0 ;; *) # een argument als yesterday of gisteren snappen we wel case $1 in yest*|gist*) DIARY=$(date --date '1 day ago' +%Y-%m-%d_%H:%M).$$.gpg ;; *) DIARY=$(date +%Y-%m-%d_%H:%M).$$.gpg ;; esac DIARY=$DOCDIR/$DIARY if $EDITOR -c 'set ft=mkd' ~/$DIARY; then if ! [ -s ~/$DIARY ]; then echo $CMD: lege notitie >&2 rm -f ~/$DIARY exit 0 else ( cd ; git add -- $DIARY ) if [ $? -ne 0 ]; then echo $CMD: git add faalde >&2 else echo $CMD: commiting >&2 ( cd ; git commit -m"commit dagboek" $DIARY ) fi fi fi ;; esac 01BLOCK00000 +- 0755 1000 1000 24 152 /home/miekg/bin/docpurge01BLOCK00152 #!/bin/bash # delete stuff in /usr/share/doc DOCDIR=/usr/share/doc for i in $DOCDIR/*; do rm -rf $i done echo $0: Removed docs from /usr/share/doc 01BLOCK00000 +- 0755 1000 1000 19 207 /home/miekg/bin/eee01BLOCK00207 #!/bin/zsh case $1 in off) xrandr --output LVDS --mode 800x480 xrandr --output VGA --off ;; 12*) xrandr --output VGA --mode 1280x1024 ;; 10*|*) xrandr --output VGA --mode 1024x768 ;; esac 01BLOCK00000 +- 0755 1000 1000 21 4543 /home/miekg/bin/gb.pl01BLOCK04543 #!/usr/bin/perl use DBI; use strict; my $dbh; my $dryrun = 0; my %genre = ( 'none', 'none', 'Misc', 'Misc', 'Comics & Graphic Novels', 'Comics', 'Games', 'Comics', 'Language Arts & Disciplines', 'Art', 'Art', 'Art', 'Music', 'Art', 'Sports & Recreation', 'Recreation', 'Cooking', 'Cooking', 'Literature', 'Literature', 'Mathematics', 'Science', 'Technology', 'Science', 'Science', 'Science', 'Political Science', 'Science', 'Social Science', 'Science', 'Business & Economics', 'Science', 'Psychology', 'Science', 'Computer viruses', 'Computer', 'Computers', 'Computer', 'Computer programming', 'Computer', 'Juvenile Fiction', 'Fiction', 'Fiction', 'Fiction', 'Humor', 'Fiction', 'Science Fiction', 'Science Fiction', 'Fantasy', 'Fantasy', 'dictionary', 'Encyclopedia', 'Travel', 'Travel' ); sub normalize_genre { my $g = shift; if ($genre{$g}) { print "** Genre genormaliseerd naar $genre{$g}\n"; return $genre{$g}; } else { return $g; } } # title:author:genre:year of first publication sub details { my @html = @_; my @author = (); my @details = (); my $i = 0; my $j = 0; my $s = 0; # read ISBN numbers foreach (@html) { next if /^[ \t]*$/; s/^[ \t]+//; # print; # 3 of 3 on 9780201541991. (0.01 seconds) if (/(\d) of (\d) on/) { my $aantal = $2; if ($aantal gt 1) { print "** Meer dan 1 boek gevonden, neem de eerste hit\n"; # return (); } } if ($i) { if (/sponsored links/i) { print "** Sponsered link, continue\n"; $s = 1; next; } if ($s == 1) { # reclame is altijd van bol.com... dit veranderd nog wel eens dus! if (/www.bol.com/) { $s = 0; } next; } if ($j == 0) { # title chomp; s/[ \t]+$//; s/^ ?//; # may some times contain - Page xxx s/ - Page.*$//; push @details, $_; } elsif ($j == 1) { chomp; s/[ \t]+$//; s/^by //; @author = split /[ \t]+-[ \t]+/; # it happens that there is no genre, in that case we find the year in the genre # fix this if ($author[1] =~ /^\d+$/) { ($author[2], $author[1]) = ($author[1], ""); } if ($author[1] eq "") { # no genre $author[1] = "none"; } push @details, @author[0..2]; } $j++; } if (/list.*view.*cover.*view/i) { $i = 1; } return @details if $j > 1; } return (); } sub retrieve { my $isbn = shift; my $sth = $dbh->prepare('SELECT * FROM books WHERE isbn = ?') or die "Couldn't prepare statement: " . $dbh->errstr; $sth->execute($isbn); while (my @data = $sth->fetchrow_array()) { #print "@data" . "\n"; } # ... We have to do this after the while loop that fetches whatever rows were available, because with some # databases you don't know how many rows there were until after you've gotten them all. my $row = $sth->rows; $sth->finish; if ($dryrun == 0) { return ($row == 0); } else { return 1; } } sub insert { my ($isbn, $title, $author, $genre, $year, $epoch) = @_; $genre = lc normalize_genre $genre; print join "|", $title, $author, $genre, $year, $epoch . "\n"; if ($dryrun == 0) { my $sth = $dbh->prepare('INSERT INTO books VALUES (?, ?, ?, ?, ?, ?, ?, ?)') or die "Couldn't prepare statement: " . $dbh->errstr; $sth->execute(undef, $isbn, "$title", "$author", "$genre", $year, $epoch, undef) or die "Couldn't insert book: " . $dbh->errstr; $sth->finish; } else { print "** No commit\n"; } } $dbh = DBI->connect("dbi:SQLite:dbname=biblio.db", "", ""); # optional argument if ($ARGV[0] eq "-n") { print "** Dryrun, geen DB commits\n"; $dryrun = 1; shift; } if ($ARGV[0] eq "-g") { # print genres my %uniq; foreach (values %genre) { $uniq{lc $_} = 1; } print join "\n", keys %uniq; #print "\n"; exit 0; } # read isbn numbers while(<>) { chomp; if (! /^\d+$/) { print "** Ongeldig\n"; next; } my @html = `links -width 200 -dump "http://books.google.com/books?q=+$_&btnG=Search+Books"`; # title,author,genre,year of first publication my @det = details(@html); if (scalar @det == 0) { print "** Onbekend\n"; } else { my $epoch = time(); # genre if ($det[2] =~ /pages/) { # problably couldn't fetch it $det[2] = "none"; } # first published, if empty, make it up if ($det[3] eq "") { $det[3] = "0"; } if (retrieve $_) { insert $_, $det[0], $det[1], $det[2], $det[3], $epoch; } else { print "** Boek al aanwezig: $_: $det[0]\n"; } } } 01BLOCK00000 +- 0755 1000 1000 21 1556 /home/miekg/bin/gconf01BLOCK01556 #!/bin/zsh # set gnome specific settings GC=gconftool-2 for type keyname value in \ string /desktop/gnome/background/picture_filename ~/.themes/eunight2_pv_big.jpg \ string /apps/metacity/general/focus_mode sloppy \ string /apps/metacity/general/action_double_click_tittlebar toggle_shade \ bool /apps/metacity/general/visual_bell True \ string /apps/metacity/general/theme Metabox \ string /apps/metacity/general/visual_bell_type frame_flash \ string /apps/metacity/global_keybindings/switch_to_workspace_left "Left" \ string /apps/metacity/global_keybindings/switch_to_workspace_right "Right" \ string /apps/metacity/global_keybindings/run_command_1 "Return" \ string /apps/metacity/keybinding_commands/command_1 ~/bin/xterm \ integer /apps/metacity/general/num_workspaces 4 \ string /apps/gnome-terminal/keybindings/prev_tab "Left" \ string /apps/gnome-terminal/keybindings/next_tab "Right" \ bool /apps/gnome-terminal/profiles/Default/default_show_menubar False \ bool /apps/gnome-terminal/profiles/Default/login_shell True \ string /apps/gnome-terminal/profiles/Default/background_type transparant \ string /apps/gnome-terminal/profiles/Default/scrollbar_position hidden \ string /apps/gnome-terminal/profiles/Default/font "Terminus 9" \ float /apps/gnome-terminal/profiles/Default/background_darkness 0.85 \ bool /apps/gnome/interface/cursor_blink False;\ do gconftool-2 -t $type -s $keyname $value done 01BLOCK00000 +- 0755 1000 1000 25 504 /home/miekg/bin/htmlwdiff01BLOCK00504 #!/bin/sh # # htmlwdiff # Requires: wdiff from ftp://ftp.gnu.org/gnu/wdiff/ # $Id: htmlwdiff,v 1.1 2004/01/05 09:39:55 leinen Exp leinen $ # : ${TMPDIR:=/tmp} a1=$TMPDIR/htmlwdiff1.$$ a2=$TMPDIR/htmlwdiff2.$$ sed -e 's/&/&/g' -e 's//\>/g' $1 > $a1 sed -e 's/&/&/g' -e 's//\>/g' $2 > $a2 echo "
"
wdiff -w "" -x "" -y "" -z "" $a1 $a2
echo "
" rm -f $a1 rm -f $a2 01BLOCK00000 +- 0775 1000 1000 24 300 /home/miekg/bin/mencoder01BLOCK00300 mencoder -oac lavc -ovc lavc -of mpeg -mpegopts format=dvd:tsaf \ -vf scale=presize=pal,harddup -srate 48000 -af lavcresample=48000 -lavcopts \ vcodec=mpeg2video:vrc_buf_size=1835:vrc_maxrate=9800:vbitrate=5000:keyint=15:vstrict=0:acodec=mp2:abitrate=256:aspect=16/9 \ -ofps 25 -o "$1".mpeg "$1".avi 01BLOCK00000 +- 0755 1000 1000 23 2633 /home/miekg/bin/nbadmin01BLOCK02633 #!/bin/bash COM_BASE="/home/miekg/miek.nl/blog/comments" NB_BASE="/home/miekg/miek.nl/blog" # a clone of listadmin, but then for acking comments in my site # get a list of all mail subscribers to these thread # give the current comment dir as arg function subscribers { SUB= for i in $@; do if [ "$(basename $i)" = "*" ]; then shift; continue; fi mailline=$(sed -n '2p' < $i) mailyesno=${mailline:0:2} mailaddr=${mailline:2} if [[ $mailaddr == "nobody@example.net" ]]; then mailyesno="N " fi case $mailyesno in "Y ") uniq=yes for j in $SUB; do if [[ $j = $mailaddr ]]; then uniq=no fi done [[ $uniq == "yes" ]] && SUB="$SUB $mailaddr" ;; esac done echo $SUB } # send mail to the subscribers # args: comment file and subscriber list function mail { comfile=$1; shift comtitle=$1; shift for addr in $@; do ( echo -e "Hello,\n\nThis is an email to inform you of a new comment\nat http://miek.nl ." echo -e "It is posted under the blog entry titled \`${comtitle:0:20}'\n" sed -n '1p' < $comfile | sed -e 's/^/ /' # newline between url and body echo # clean the message up somewhat sed -n '3,10p' < $comfile | sed 's/ //' | sed 's/
//' | \ fmt -u -w 60 | sed -e 's/^/ /' echo -e "\n\n--\nComment notify sent by http://miek.nl - $(date)" echo -e "Notifies will be sent until commenting is closed" ) | /usr/bin/mail -s "Comment notify miek.nl: \`${comtitle:0:20}'" $addr echo "Sending notify to $addr" done } for art in $COM_BASE/*.txt; do com=$art/new/* bart=$(basename $art) title=$(grep '^TITLE' $NB_BASE/data/${bart//e/} | head -1) sub=$(subscribers $com) set -- $com # turn $com in $@ while (($# > 0)); do if [[ "$(basename $1)" = "*" ]]; then # empty dir shift continue fi echo "> ${title//TITLE: /}" echo "> $(basename $art)" echo " >> Comment: $(basename $1)" cat $1 | sed -e 's/^/ /' -e '2,/^.*@.*\..*$/G' echo read -p "(A)approve (D)discard (N)skip [E]edit: [N] " reply [[ -z $reply ]] && reply="N" case $reply in A*|a*) # send notifies, do this before the mv! mail $1 "${title//TITLE: /}" "$sub" echo "new/$(basename $1) -> ok/$(basename $1)" if ! mv $1 $art/ok ; then echo "$0: mv failed!" >&2 fi shift ;; D*|d*) echo rm "new/$(basename $1)" if ! rm -f $1; then echo "$0: rm failed!" >&2 fi shift ;; N*|n*) echo "Skipping" shift ;; E*|e*) ${EDITOR} $1 # no shift ;; *) echo "$0: invalid choice $reply" >&2 ;; esac echo done done 01BLOCK00000 +- 0755 1000 1000 23 279 /home/miekg/bin/nbemail01BLOCK00279 #!/bin/bash # gather all email addresses of all comments # tijdspanne, 30 dagen NB_COM_BASE=/home/miekg/miek.nl/blog/comments com=$(find $NB_COM_BASE -type f -mtime -30 -regex '.*\.txt/ok/[0-9]+_.*') set -- $com while (($# > 0)); do sed -n 2p < $1 shift done | sort -u 01BLOCK00000 +- 0775 1000 1000 24 777 /home/miekg/bin/nbnotify01BLOCK00777 #!/bin/bash # send email for the comments that are found in my website COM_BASE="/home/miekg/miek.nl/blog/comments" NB_BASE="/home/miekg/miek.nl/blog" BODY="" let i=0 for art in $COM_BASE/*.txt; do bart=$(basename $art) title=$(grep '^TITLE' $NB_BASE/data/${bart//e/} | head -1) j=0 for com in $art/new/*; do [[ "$com" = "$art/new/*" ]] && continue [[ $j -eq 0 ]] && BODY="$BODY\n$art" firstline=$(sed -n 3p < $com) BODY="$BODY\n o \"${title//TITLE: /}\" ${com//$art\/}" BODY="$BODY\n\t\"${firstline:0:65}\" ..." let i=i+1 let j=j+1 done done if [[ ! -z "$BODY" ]]; then if [[ $i -eq 1 ]]; then echo "$i new comment found for miek.nl, in" else echo "$i new comments found for miek.nl, in" fi echo -e ${BODY} fi 01BLOCK00000 +- 0755 1000 1000 27 1655 /home/miekg/bin/post-commit01BLOCK01655 #!/bin/bash PATH=$PATH:/usr/local/bin:/usr/local/sbin:. TPKG=/home/miekg/bin/tpkg SVN_BAR="------------------------------------------------------------------------" REPOS="$1" REV="$2" START=`date +%s` export BUILD_DIR=`mktemp -d /tmp/XXXXXX` export MAIL_FILE=`mktemp /tmp/XXXXXXX` # if svnlook does not return a full path with a file # this will fail BRANCH="none" LOOK=`/usr/bin/svnlook changed -r$REV $REPOS | /usr/bin/awk '{ print $2 }' | head -1` if [[ $LOOK =~ 'trunk/' ]]; then BRANCH="trunk" fi if [[ $LOOK =~ 'branches/' ]]; then BRANCH=`echo $LOOK | cut -f1,2 -d /` fi if [[ $LOOK =~ 'tags/' ]]; then BRANCH=`echo $LOOK | cut -f1,2 -d /` fi # checkout to $BUILD_DIR /usr/bin/svn co -r$REV file://$REPOS/$BRANCH $BUILD_DIR ( cd $BUILD_DIR ; svn log -r$REV > $MAIL_FILE ) svnlook changed -r$REV $REPOS >> $MAIL_FILE echo $SVN_BAR >> $MAIL_FILE echo "PATH=$PATH" > $BUILD_DIR/test/.tpkg.var.master echo "TPKG_BUILD=$BUILD_DIR" >> $BUILD_DIR/test/.tpkg.var.master # RUN THE TESTS for tests in $BUILD_DIR/test/*.tpkg do /usr/bin/nice /bin/bash \ $TPKG -q -b $BUILD_DIR/test -a $BUILD_DIR exe `basename $tests` done END=`date +%s` echo ELAPSED: $((END - START)) s >> $MAIL_FILE echo $SVN_BAR >> $MAIL_FILE /bin/bash $TPKG -b $BUILD_DIR/test report >> $MAIL_FILE /bin/bash $TPKG -b $BUILD_DIR/test clean # END # SVN STUFF echo $SVN_BAR >> $MAIL_FILE ( cd $BUILD_DIR ; svn diff -rPREV:$REV | diffstat >> $MAIL_FILE ) echo >> $MAIL_FILE ( cd $BUILD_DIR ; svn diff -rPREV:$REV >> $MAIL_FILE ) rm -rf $BUILD_DIR cat $MAIL_FILE | \ mail -s "[svn: rdup/$BRANCH] r$REV status" miek@atoom.net rm -f $MAIL_FILE 01BLOCK00000 +- 0755 1000 1000 22 33 /home/miekg/bin/svnexe01BLOCK00033 svn propset svn:executable on $@ 01BLOCK00000 +- 0755 1000 1000 21 31 /home/miekg/bin/svnid01BLOCK00031 svn propset svn:keywords Id $@ 01BLOCK00000 +- 0755 1000 1000 22 528 /home/miekg/bin/svnlog01BLOCK00528 #!/bin/sh # give some more logging # syn: svnlog [linestart] [lineend] file(s) # nothing is optional - todo if [ "x$1" = "x" ]; then echo "svnlog [linestart] [lineend] file(s)" exit fi start=$1 end=$2 showdiff=yes shift shift for file in $@; do if [ -f $file ]; then echo -e " lineno revision userid\t" svn ann $file | awk "NR >= $start && NR <= $end" | nl -ba -v$start | tee $$.repo for rev in `cat $$.repo | awk '{ print $2 }' | sort -n | uniq`; do svn -r$rev log $file done rm -f $$.repo fi done 01BLOCK00000 +- 0755 1000 1000 21 163 /home/miekg/bin/svnrm01BLOCK00163 #!/bin/zsh if [[ `pwd` = "/home/miekg" ]]; then exit fi svn st --no-ignore | grep '^[I\?]' | sed 's/^[I\?] *//' | \ tr '\n' '\0' | xargs -i -0 rm "{}" 01BLOCK00000 +- 0755 1000 1000 17 2947 /home/miekg/bin/t01BLOCK02947 #!/usr/bin/perl # # Dit scriptje laat de NOS teletext zien # # (c) 2001, 2002, 2003 by Bas Zoetekouw # All rights reserved. # # Naar een idee van Wouter Bergmann-Tiest # # 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 and this list of conditions. # 2. Redistributions in binary form must reproduce the above copyright # notice and this list of conditions in the # documentation and/or other materials provided with the distribution. # # ## 2003-01-06: niew teletekst format ## 2003-01-06: kleurtjes ## 2003-01-06: meer html entities toegevoegd (dank Richard) ## 2003-01-22: VRT support ## 2003-02-07: kleur support aangepast #use strict; #my $SOURCE = "VRT"; my $SOURCE = "NOS"; my $LYNX; foreach my $l (qw|/usr/bin/links /usr/bin/lynx lynx|) { if (-x $l) { $LYNX=$l; last; } } my $color = 1; if ((scalar @ARGV > 0) && ($ARGV[0] eq "-m")) { $color = 0; shift @ARGV; } my %COLORS = ( "000000" => "\e[30m", #black "black" => "\e[30m", #black "ff0000" => "\e[31m", #red "red" => "\e[31m", #red "00ff00" => "\e[32m", #green "lime" => "\e[32m", #green "0000ff" => "\e[34m", #blue "blue" => "\e[34m", #blue "ffff00" => "\e[33m", #yellow "yellow" => "\e[33m", #yellow "ff00ff" => "\e[35m", #magenta "fuchsia"=> "\e[35m", #magenta "00ffff" => "\e[36m", #cyan "aqua" => "\e[36m", #cyan "ffffff" => "\e[37m", #white "white" => "\e[37m", #white "reset" => "\e[0m"); #reset color my %HTML = ( """ => '"', "­" => "", "<" => '<', "&" => '&', ">" => '>'); sub display(\@) { my @Output=@{(shift)}; my ($print, $last) = (0, 0); foreach my $line (@Output) { # print "--> $line"; ($print = 1) if ($line =~ s/^.*
//i);
	($last  = 1) if ($line =~ s/<\/pre>.*$//i);

	next unless ($print==1);

	if ($color==1) { 
	    foreach (keys %COLORS) {
		$line =~ s/COLOR=$_[^>]*>/>$COLORS{"$_"}/ig;
	    } 
	}
	foreach (keys %HTML) {
	    $line =~ s/$_/$HTML{"$_"}/ig;
	} 
	$line =~ s,<[^>]+>,,g;

	last if ($last == 1);

	print $line;

    } 
    print $COLORS{"reset"};
}

my ($Pagina, $SubPagina) = @ARGV;

$Pagina    = "100"  if  (scalar @ARGV == 0);
$SubPagina = "1"    if  (scalar @ARGV <= 1);  

my @Output = ("");
if ($SOURCE eq "NOS") {
    $SubPagina = sprintf("%02i", $SubPagina);
    @Output = `$LYNX -source 'http://teletekst.nos.nl/tekst/${Pagina}-${SubPagina}.html'`;
} elsif ($SOURCE eq "VRT") {
    @Output = `$LYNX -source 'http://193.121.55.225/tt/tt.php?p=${Pagina}/${SubPagina}&g=0&s=0&r=0&x=1'`
}

display @Output;
01BLOCK00000
+- 0775 1000 1000 20 190
/home/miekg/bin/term01BLOCK00190
#!/bin/zsh

EXE=/usr/bin/xfce4-terminal

# xterm wrapper
case $HOST in
    foton)
	geom="100x40"
	;;
    elektron)
	geom="80x25"
	;;
    charm)
	geom="80x25"
	;;
esac

$EXE --geometry $geom
01BLOCK00000
+- 0755 1000 1000 20 28303
/home/miekg/bin/tpkg01BLOCK08192
#!/bin/bash

# a utlity to run a shar test archive (aka tpkg)
# Created by Miek Gieben, NLnetLabs, (c) 2005, 2006
# Licensed under GPL version 2

export TPKG_VAR_MASTER="../.tpkg.var.master"
export TPKG_VAR_TEST=".tpkg.var.test"
export TPKG_VERSION="1.11";
export SHELL="/bin/sh"
TPKG_LOGGER=/usr/bin/logger
TPKG_BASE="."
TPKG_ARGS=""
TPKG_CURRENT=`pwd`
TPKG_QUIET=0   # only output err() msgs
TPKG_KEEP=0    # tpkg create doesn't remove dir/
TPKG_PASS=0    # how much must succeed
TPKG_LOG=0     # don't log
TPKG_PRI=""    # log facility

_DESC_WIDTH=${COLUMNS:-55}
if [ $_DESC_WIDTH -ge 70 ]; then
        _DESC_WIDTH=70
fi

### Helper functions
function cleanup() {
        out "[log] Cleaning up"
	if [[ $TPKG_BASE = "." ]]; then
        	[[ -f result.$dsc_basename ]] && cp result.$dsc_basename ../
	else
	        [[ -f result.$dsc_basename ]] && cp result.$dsc_basename $TPKG_BASE
	fi
        cd ..
	if [[ ! -z "$dir" ]]; then
		rm -rf `basename $dir`
	fi
	cd $TPKG_CURRENT
}

function cleanup_and_exit() {
        cleanup; exit 1
}

function err() {
        if [[ -z $testname ]]; then
                echo -e "  $1" 
        else
                echo -e "[$testname]  $1" 
        fi
}

function tpkg_log() {
        if [[ $TPKG_LOG -eq 0 ]]; then
                return
        fi

        if [[ -e $TPKG_LOGGER ]]; then
                if [[ -z $TPKG_PRI ]]; then
                        $TPKG_LOGGER "$1"
                else
                        $TPKG_LOGGER -p "$TPKG_PRI" "$1"
                fi
        fi
}

function out() {
        if [[ $TPKG_QUIET -eq 1 ]]; then
                return
        fi
        if [[ -z $testname ]]; then
                echo -e "  $1"
        else
                echo -e "[$testname]  $1"
        fi
}

function epoch() {
        # make this sorta portable allthough not needed now
        epoch=0
        case $OSTYPE in
                linux*)
                epoch=`date +%s`
                ;;
                freebsd*)
                epoch=`date +%s`
                ;;
        esac
}

function post() {
        if [ -f "${dsc_post}" ]; then 
                err "[log] Executing post script: ${dsc_post} ${TPKG_ARGS}"
                echo "--------- Start Post Output ------------------ " >> result.$dsc_basename
                ${SHELL} ${dsc_post} ${TPKG_ARGS} >> result.$dsc_basename
                echo "----------- End Post Output ------------------ " >> result.$dsc_basename
                result=$?
                if [ $result -ne 0 ]; then
                        err "[warning] Post-script executed with errors: $result."
                fi
        fi
}

function pre() {
        if [ -f "${dsc_pre}" ]; then 
                err "[log] Executing pre script: ${dsc_pre} ${TPKG_ARGS}"
                echo "--------- Start Pre Output ------------------- " >> result.$dsc_basename
                ${SHELL} ${dsc_pre} ${TPKG_ARGS} >> result.$dsc_basename
                echo "----------- End Pre Output ------------------- " >> result.$dsc_basename
                result=$?
                if [ $result -ne 0 ]; then
                        err "[warning] Pre-script executed with errors: $result."
                fi
        fi
}
 
function write_done() {
        # we are executing in a subdir
        if [ -f "../.done-${testname}" ]; then
                err "[warning] Overwriting .done-${testname}"
        fi
        > ../.done-${testname}
}

# write done file in current dir
function write_fake_done() {
        if [ -f ".done-${testname}" ]; then
                err "[warning] Overwriting .done-${testname}"
        fi
        > .done-${testname}
}

function mktempdir() {
        # check if mktemp is there, if not use plain mkdir with $$
        # as a side effect set $dir
        dir=
        case $OSTYPE in
                solaris*)
                # use mkdir
                dir="$1.$$"
                mkdir "$dir"
                return
                ;;
                *)
                dir=`mktemp -d "$1"`
                return
                ;;
        esac
}

function usage() {
        out "Usage:"
        out "$0 [OPTIONS] [exe|create|extract|tmpl|fake] test.tpkg"
        out "or:"
        out "$0 [OPTIONS] [report|clean|list|desc|help] test.tpkg"
        out "or:"
        out "$0 [OPTIONS] clone test1.tpkg test2.tpkg"
        out
        out "Testing"
        out " exe.........:\texecute a test, safe the result result.testname"
        out " c | create..:\tcreate a .tpkg out of the test.{pre, post, test} files"
        out " e | extract.:\textract a .tpkg to tmp. dir"
        out " t | tmpl....:\tcreate empty template files for a new test"
        out " f | fake....:\tfake the running of test, but do create a .done file"
        out 
        out "When no action is given a test is executed"
        out
        out "Reporting/Cleanup"
        out " clean........:\tremove all the result files"
        out " cd | cleandir:\tremove all .dir directories"
        out " r  | report..:\tcreate a nice report from all the result files"
        out " cl | clone...:\tclone test1.tpkg to test2.tkpg"
        out " l  | list....:\tprint the files of the test to stdout"
        out " d  | desc....:\tprint the test's description to stdout"
        out " h  | help....:\tprint the help message for this test, if available"
        out
        out " When multiple tests depend on a single other test, this"
        out " other test is only executed once."
	out
	out "OPTIONS"
	out " -h\t\tshow this help"
	out " -v\t\tshow version"
        out " -q\t\tonly print errors"
        out " -l\t\tlog test name to syslog when starting the test (using logger)"
        out " -p PRI\tlog using PRI as priority"
        out " -k\t\tdon't remove test directory when creating/executing a tpkg package"
        out " -n NUM\tif less than NUM of the tests are passed exit with 1"
        out " \t\tOtherwise exit with 0. Only valid when running tpkg report"
	out " -b DIR\tuse DIR is a base directory in stead of ."
	out " -a ARGS\tpass the string ARGS through to the test scripts"
        out 
        out " (C) NLnetLabs, Miek Gieben. Licensed under the GPL version 2."
}

function version() {
	out "tpkg (test package), version $TPKG_VERSION"
	out "Written by Miek Gieben, NLnet Labs"
	out
	out "Copyright (C) 2005, 2006 NLnet Labs"
	out
	out "This is free software; see the source for copying conditions. There is no"
	out "warranty; even not for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE"
}

function cleanreport() {
        # cleanup all the result. files
        for result in `ls result.* 2>/dev/null`; do 
                err "[log] rm $result"
                rm $result
        done
        # rm any .var files
        out "[log] rm `basename $TPKG_VAR_MASTER`"
        rm -f `basename $TPKG_VAR_MASTER`
        rm -f $TPKG_VAR_TEST
        out "[log] rm .done files"
        rm -f .done*
	cd $TPKG_CURRENT
}

function cleandirs() {
        for result in `ls -d *.dir 2> /dev/null`; do
                err "[log] rm -rf $result"
                rm -rf $result
        done
}

function report() {
        # generate a report from the result. files.
        passed=0
        failed=0
        unknown=0
        first=0

        tp="passed"
        tf="failed"
        tu="unknown"
        for result in `ls result.* 2>/dev/null` ; do 
                passfailed=`head -1 $result | awk ' { print $2 }'`
                basename=`head -3 $result | grep BaseName | awk -F': ?' ' { print $2 }'`
                description=`head -4 $result | grep Description | awk -F': ?' ' { print $2 }'`
                runend=`head -2 $result | grep DateRunEnd | awk -F': ?' ' { print $2 }'`
                runstart=`head -5 $result | grep DateRunStart | awk -F': ?' ' { print $2 }'`

                # truncate the description to 35 chars
                if [ ${#description} -gt $_DESC_WIDTH ]; then
                        description=${description:0:$_DESC_WIDTH}
                        description=$description"..."
                fi

                if [ -z $runend ]; then
                        runend=0
                fi
                if [ -z $runstart ]; then
                     01BLOCK08192
   runstart=0
                fi

                ((period=$runend - $runstart))
                # prefix period if < 9
                if [ $period -lt 10 ]; then
                        period="0$period"
                fi

                case $passfailed in
                "FAILED")
                        if [ $first -eq 0 ]; then
                                echo "   STATUS    : ELAPSED : TESTNAME : TESTDESCRIPTION"
                                first=1
                        fi
                        echo -e "!! $passfailed !! : $period s : $basename : $description"
                        ((failed=$failed + 1)) 
                        failed_tests="$failed_tests $basename"
                        tf="FAILED"
                        ;;
                "PASSED")
                        if [ $TPKG_QUIET -eq 0 ]; then
                                if [ $first -eq 0 ]; then
                                        echo "   STATUS    : ELAPSED : TESTNAME : TESTDESCRIPTION"
                                        first=1
                                fi
                                echo -e "** $passfailed ** : $period s : $basename : $description"
                        fi
                        ((passed=$passed + 1)) 
                        tp="PASSED"
                        ;;
                *) 
                        if [ $first -eq 0 ]; then
                                echo "   STATUS    : ELAPSED : TESTNAME : TESTDESCRIPTION"
                                first=1
                        fi
                        echo -e "-- $passfailed -- : $period s : $basename : $description"
                        ((unknown=$unknown + 1)) 
                        failed_tests="$failed_tests $basename"
                        tu="UNKNOWN"
                        ;;
                esac
        done
        ((total=$passed + $failed + $unknown))
        if [[ $total -eq 0 ]]; then
                fper=0
                pper=0
                uper=0
        else
                fper=`echo -e "scale=4\n$failed/$total*100" | bc | sed 's/00$//'`
                pper=`echo -e "scale=4\n$passed/$total*100" | bc | sed 's/00$//'`
                uper=`echo -e "scale=4\n$unknown/$total*100" | bc | sed 's/00$//'`
        fi
        echo
        echo -e "$tp: $passed ($pper %)\t$tf: $failed ($fper %)\t$tu: $unknown ($uper %)"

        # for each failed test include the complete result file
        # $i is basename
        echo
        for i in $failed_tests; do 
                echo --------------- Start Output: $i ------------------
                cat result.$i
                echo ---------------   End Output: $i   ------------------
        done
	cd $NT
        if [[ $TPKG_PASS -gt 0 ]]; then
                if [[ $passed -lt $TPKG_PASS ]]; then
                        exit 1
                fi
        fi
        exit 0
}

# clone test1 to test2
function clone() {
        $0 extract $test1.tpkg
        if [ $? -ne 0 ]; then
                err "[fatal] Extract of $test1.tpkg failed. Abort."
                exit 1
        fi

        if [ ! -d "$test1.dir" ]; then
                err "[fatal] No $test1.dir directory? Abort."
                exit 1
        fi
        cd $test1.dir
        for i in $test1.* ; do 
                ext=`echo $i | sed s/$test1//`
                if [ ! -z "$ext" ]; then
                        # rename the content of the files too
                        sed  "s/$test1/$test2/g" < $i > $i.$$
                        mv $i.$$ $i
                        # rename
                        mv $i $test2$ext
                fi
        done
        # edit the dsc file too
        # update the date
        sed "s/^CreationDate:.*/CreationDate: `date`/"  < $test2.dsc > $test2.dsc.$$
        mv $test2.dsc.$$ $test2.dsc

        cd ..
        # rename the dir
        mv $test1.dir $test2.dir
        if [ $TPKG_KEEP -eq 0 ]; then
                $0 create $test2.tpkg
        else
                $0 -k create $test2.tpkg
        fi
        if [ $? -ne 0 ]; then
                err "[warning] Creating of $test2.tpkg failed."
        fi
	cd $TPKG_CURRENT
}

# try to find the specific cmd
function find_cmd {
        which "${i}" >/dev/null
        if [ $? -ne 0 ]; then                
                err "[fatal] CmdDepend \"$i\" could not be satisfied: not found. Abort."
                cleanup; exit 1  
        fi
}

# extract a tpkg to the given dir. The dir must exist already.
function extract_tpkg_to { # 
        out "[log] Extracting..."
        # tar xfz ${testname}.tpkg -C $1 2>/dev/null
	gzip -cd ${testname}.tpkg | (cd $1; tar xf -) 2>/dev/null
	if [ $? -ne 0 ]; then
		err "[fatal] Could not untar archive. Abort."
		cd $TPKG_CURRENT; exit 1
	fi
	# now stuff is in: $1/testname.dir/...
	mv $1/${testname}.dir $1/${testname}.dir.tmp$$
	mv $1/${testname}.dir.tmp$$/* $1/.
	rm -rf $1/${testname}.dir.tmp$$
}

### MAIN 
# check the arguments
while getopts ":vhkqb:a:n:lp:" o
do case "$o" in
	b) 	TPKG_BASE="$OPTARG";;
	h) 	usage; exit 0;;
	v) 	version; exit 0;;
        l)      TPKG_LOG=1;;
        p)      TPKG_PRI="$OPTARG";;
	a) 	TPKG_ARGS="$OPTARG";;
        q)      TPKG_QUIET=1;;
        k)      TPKG_KEEP=1;;
        n)      TPKG_PASS=$OPTARG
                if [ $TPKG_PASS -eq 0 ]; then
                        err "[fatal] A null or non numerical value is not valid. Abort."
                        exit 1
                fi
                ;;
        *)      err "[fatal] Unknown option. Abort."; exit 1;;
esac
done
shift $(($OPTIND - 1))

# go to the base dir
if [ ! -d $TPKG_BASE ]; then
	err "[fatal] Directory $TPKG_BASE does not exist. Abort"
	exit 1
else
	cd $TPKG_BASE
fi

# either create a tpkg (ie. call shar) or exe (do a test)
goal=$1
archive=$2
if [ -z "${goal}" ]; then
        usage
        cd $TPKG_CURRENT; exit 0
fi

# allow short goals
case $goal in
        # none for exe - short enough
        c)      goal="create";;
        e)      goal="extract";;
        t)      goal="tmpl";;
        f)      goal="fake";;
        cd)     goal="cleandir";;

        r)      goal="report";;
        # none for clean
        cl)     goal="clone";;
        l)      goal="list";;
        d)      goal="desc";;
        h)      goal="help";;
esac

### REPORT ###
# no extra args required
if [ "${goal}" = "report" ]; then
        report;
fi
if [ "${goal}" = "clean" ]; then
        cleanreport; exit 0
fi
if [ "${goal}" = "cleandir" ]; then
        cleandirs; exit 0
fi
if [ "${goal}" = "clone" ]; then
        test1=`basename $2 .tpkg`
        test2=`basename $3 .tpkg`;
        if [ -z "$test1" -o -z "$test2" ]; then
                usage; cd $TPKG_CURRENT; exit 0
        fi
        clone; exit 0
fi

if [ -z "${archive}" ]; then
        out "[log] Defaulting to \`execute'"
        archive=$1
        goal="exe"
fi

if [ -z $archive ]; then
        usage; cd $TPKG_CURRENT; exit 0
fi

testname=`basename $archive .tpkg`
testpath=`dirname $archive`
dsc_file=$testname.dsc                  
if  [ -z $testname ]; then
        err "[fatal] The test package should have a .tpkg extension. Abort."
	cd $TPKG_CURRENT; exit 1
fi

if [ "${goal}" = "fake" ]; then
        out "[log] Writing .done-$testname file."
        write_fake_done; exit 0
fi

if [ $goal = "create" ]; then
### CREATE ###
# get all files with the same basename except those that ends in .tpkg

        # check for shar
        which tar >/dev/null
        if [ $? -ne 0 ]; then
                err "[fatal] Tar command not found. Abort."
                cd $TPKG_CURRENT; exit 1
        fi

        # assume there is a dir named $testname.dir
        if [ ! -d "${testname}.dir" ]; then
                err "[fatal] No $testname.dir directory found. Abort."
        	cd $TPKG_CURRENT; exit 1
        fi
        cd $testname.dir

        # rm unwanted files
        cleanreport # this cd's to $TPKG_CURRENT
        cd - >/dev/null # jump back

        # tar is smart enough to handle this
        cd ../
        i=$( ls ${testname}.dir/$testname.* 2>/dev/null )
        if [ -z "${i}" ]; then
                err "[fatal] No $testname.* files found. Abort."
		cd $TPKG_CURRENT; exit 1
        fi01BLOCK08192



        # tar --create --file $testname.tpkg --gzip ${testname}.dir
	tar -cf - ${testname}.dir | gzip - > $testname.tpkg
	if [ $? -ne 0 ]; then
		err "[fatal] Tar create error. Abort."
		cd $TPKG_CURRENT; exit 1
	fi
        if [ $TPKG_KEEP -eq 0 ]; then
                out "[log] Removing member files"
                rm $i
        fi
        if [ $TPKG_KEEP -eq 0 ]; then
                out "[log] Removing directory"
                rmdir $testname.dir
        fi
	cd $TPKG_CURRENT; exit 0
fi

### TMPL ####
# write out a .dsc and touch a .pre/.post/.test
if [ $goal = "tmpl" ]; then
        if [ -f $testname.dsc ]; then
                err "[fatal] $testname.dsc already exists. Abort."
		cd $TPKG_CURRENT; exit 1
        fi
        
        # make tmp dir
        dir="$testname.dir"
        mkdir $dir
        if [ ! -d $dir ]; then 
                err "[fatal] Failure to create a temporary working directory. Abort."
		cd $TPKG_CURRENT; exit 1
        fi
        cd $dir
        
        cat < $testname.dsc
BaseName: $testname
Version: 1.0
Description: [Put something nice here]
CreationDate: `date`
Maintainer: `grep $LOGNAME /etc/passwd | awk -F: ' { print $5 }' | sed s/,//g`
Category: 
Component:
CmdDepends: 
Depends: 
Help: $testname.help
Pre: $testname.pre
Post: $testname.post
Test: $testname.test
AuxFiles: 
Passed:
Failure:
TMPL_EOF
        # .help file
        echo "Please describe how to use this test."  > $testname.help
        echo "i.e. tpkg -a ARG exe testname:"  >> $testname.help
        echo "   ARG is used to ..."  >> $testname.help

        # .test file
        echo "# #-- $testname.test --#" > $testname.test
        echo "# source the master var file when it's there" >> $testname.test
        echo "[ -f $TPKG_VAR_MASTER ] && source $TPKG_VAR_MASTER" >> $testname.test 
        echo "# use $TPKG_VAR_TEST for in test variable passing" >> $testname.test
        echo "[ -f $TPKG_VAR_TEST ] && source $TPKG_VAR_TEST" >> $testname.test

        # .post file
        echo "# #-- $testname.post --#" > $testname.post
        echo "# source the master var file when it's there" >> $testname.post
        echo "[ -f $TPKG_VAR_MASTER ] && source $TPKG_VAR_MASTER" >> $testname.post 
        echo "# source the test var file when it's there" >> $testname.post
        echo "[ -f $TPKG_VAR_TEST ] && source $TPKG_VAR_TEST" >> $testname.post 
        echo "#" >> $testname.post 
        echo "# do your teardown here" >> $testname.post

        # .pre file
        echo "# #-- $testname.pre--#" > $testname.pre
        echo "# source the master var file when it's there" >> $testname.pre
        echo "[ -f $TPKG_VAR_MASTER ] && source $TPKG_VAR_MASTER" >> $testname.pre
        echo "# use $TPKG_VAR_TEST for in test variable passing" >> $testname.pre
        echo "[ -f $TPKG_VAR_TEST ] && source $TPKG_VAR_TEST" >> $testname.pre

        out "[log] created $testname.{dsc, test, help, pre, post}"
        out "[log] please create the script(s) and then run: tpkg create $testname.tpkg"
        out "[log] created $testname in $dir."
	cd $TPKG_CURRENT; exit 0
fi

if [ ! -f $archive ]; then
        err "[fatal] Cannot find the test package: $archive. Abort."
        cd $TPKG_CURRENT; exit 1
fi

## EXTRACT
if [ $goal = "extract" ]; then
        dir="${testpath}/${testname}.dir"
        if [ -d $dir ]; then 
                err "[fatal] Directory $dir already exists. Abort."
		cd $TPKG_CURRENT; exit 1
        fi
        mkdir $dir
        if [ ! -d $dir ]; then 
                err "[fatal] Failure to create $dir directory. Abort."
		cd $TPKG_CURRENT; exit 1
        fi

	extract_tpkg_to $dir
        cd $dir
        trap cleanup_and_exit INT

        # stop here
        out "[log] extracted $testname.tpkg to $dir."
        cd $TPKG_CURRENT; exit 0
fi

## LIST OR DESC OR HELP
if [ $goal = "list" -o $goal = "desc" -o $goal = "help" ]; then
        $0 extract ${testname}.tpkg
        if [ $? -ne 0 ]; then
                cd $TPKG_CURRENT; exit 1
        fi

        cd ${testname}.dir/
        
        case $goal in
        list*)
                cat *
                ;;
        desc*)
                echo -n "$testname: "
                cat $testname.dsc | awk -F': ?' '/^Description/ { print $2 }'
                ;;
        help*)
                if [ -f $testname.help ]; then
                        cat $testname.help
                else
                        err "[warning] No help file found."
                fi
                ;;
        esac
        cd $TPKG_CURRENT
        # dir can go
        rm -rf ${testname}.dir; exit 0
fi

trap cleanup_and_exit INT

# make a tmp dir during execution
if [ "$goal" != "exe" ]; then
        err "[fatal] What do you mean with $goal?. Abort."
	cd $TPKG_CURRENT; exit 1
fi

mktempdir "${testpath}/${testname}.XXXXXX"
if [ ! -d $dir ]; then 
        err "[fatal] Failure to create a temporary working directory. Abort."
	cd $TPKG_CURRENT; exit 1
fi
## EXTRACT
extract_tpkg_to $dir
cd $dir

### EXE ###
# extract the information out of the *.dsc files
if [ ! -f $dsc_file ]; then
        err "[fatal] Can't locate the description file: $dsc_file. Abort."
        cleanup; exit 1
fi

SHELL=`which bash`
if [ -z ${SHELL} ]; then
       SHELL=/usr/local/bin/bash
       if [ ! -x $SHELL ]; then
               err "[fatal] Can't find the bash shell. Abort."
               cleanup; exit 1
       fi
fi

# check for a .done file
if [ -f "../.done-${testname}" ]; then
        out "[log] Found .done-${testname}. Not executing this test."
        cleanup; exit 0
fi

# this is the template for .dsc files
# we need to check if all these files also exist TODO
dsc_basename=$testname
function get_field_from_dsc() # fieldname
{
	grep "^$1: " $dsc_file | sed -e "s/^$1:[ 	]*//" -e "s/[ 	]*$//"
}
dsc_version=`get_field_from_dsc Version`
dsc_description=`get_field_from_dsc Description`
dsc_creationdate=`get_field_from_dsc CreationDate`
dsc_category=`get_field_from_dsc Category`
dsc_component=`get_field_from_dsc Component`
dsc_cmddepends=`get_field_from_dsc CmdDepends`
dsc_depends=`get_field_from_dsc Depends`
dsc_maintainer=`get_field_from_dsc Maintainer`
dsc_help=`get_field_from_dsc Help`
dsc_pre=`get_field_from_dsc Pre`
dsc_post=`get_field_from_dsc Post`
dsc_test=`get_field_from_dsc Test`
dsc_aux=`get_field_from_dsc AuxFiles`
dsc_passed=`get_field_from_dsc Passed`
dsc_failure=`get_field_from_dsc Failure`

# consistency check the lot
for i in $dsc_pre $dsc_post $dsc_test $dsc_help; do
        if [ ! -z ${i} ]; then
                if [ ! -f "${i}" ]; then
                        err "[fatal] File defined, but ${i} cannot be found. Abort."
                        cleanup; exit 1
                fi
        fi
done
for i in $dsc_pre $dsc_post $dsc_test $dsc_help; do
        if [ -z ${i} ]; then
                if [ -f "${i}" ]; then
                        err "[fatal] File not defined, but ${i} is included in the package. Abort."
                        cleanup; exit 1
                fi
        fi
done

# if we depend on another test to that one first and then return
for deptest in ${dsc_depends}; do
	cd ..  # go up one dir
        out "[log] executing dependency test: $deptest"
        ${SHELL} $0 "-b ${TPKG_BASE}" exe $deptest
        test_result=$?
        cd - > /dev/null  # back where we belong
        if [ $test_result -ne 0 ]; then
                err "[fatal] Test depends on $deptest which failed.  Abort."
                cleanup; exit 1
        fi
done

# this enhances the template from above
## Post Processing of some of these variables
# dsc_aux is a comma seperated list of files, max 8 files
i=$( echo $dsc_aux | awk -F', ?' '{ print $1 "\n" $2 "\n" $3 "\n" $4 "\n" \
$5 "\n" $6 "\n" $7 "\n" $8 }' )
dsc_aux_files=($i)
dsc_aux_files_total=${#dsc_aux_files[*]}
# cmd depends
i=$( echo $dsc_cmddepends | awk -F', ?' '{ print $1 "\n" $2 "\n" $3 "\n" $4 "\n" \
$5 "\n" $6 "\n" $7 "\n" $8 }' )
dsc_cmddepends_files=($i)
dsc_cmddepends_files_total=${#dsc_cmddepends_files[*]}

for i in ${dsc_cmddepends_files[*]}; do
        find_cmd $i
done
# depends can also be a comma seperated list of package
# TODO 

# check is the aux files are also really in 01BLOCK03727
the shar
for i in ${dsc_aux_files[*]}; do
        if [ ! -f $i ]; then
                err "[fatal] Aux. file $i must be in the archive. Abort."
                cleanup; exit 1
        fi
done

if [ ! -f $dsc_test ]; then
        err "[fatal] Can't locate the test script: $dsc_test. Abort."
        cleanup; exit 1
fi

### Actual executing of the scripts
tpkg_log "Starting test: '$dsc_basename'"

epoch  # run before pre()
echo "BaseName: $dsc_basename" > result.$dsc_basename
echo "Description: $dsc_description" >> result.$dsc_basename
echo "DateRunStart: $epoch " >> result.$dsc_basename
echo "--------------- Test Output ------------------" >> result.$dsc_basename

pre

out "[log] Executing test" 

( ${SHELL} $dsc_test ${TPKG_ARGS} 2>&1 ) >> result.$dsc_basename
test_result=$?
epoch   # would like to run after post, but that is not possible :-(
if [ $test_result -ne 0 ]; then
        err "[warning] Test executed with errors: $test_result." 
        echo "!! FAILED !!     !! FAILED !!" > result.$dsc_basename.tmp
        echo "DateRunEnd: $epoch" >> result.$dsc_basename.tmp
        err "[log] !! FAILED !!"
        cat result.$dsc_basename >> result.$dsc_basename.tmp
        echo "exit code: $test_result" >> result.$dsc_basename.tmp
        mv result.$dsc_basename.tmp result.$dsc_basename
        post;
        if [ $TPKG_KEEP -eq 0 ]; then
                out "[log] Removing temp directory $dir"
                cleanup
        else
        	out "[log] Keeping temp directory $dir"
        fi
        exit 1
fi
 
cp -f result.$dsc_basename result.$dsc_basename.$$

failed=-1  # -1 undef, 0 passed, 1 failed
## PASSED
[ ! -z "${dsc_passed}" ] && egrep "${dsc_passed}" result.$dsc_basename.$$ > /dev/null
if [ $? -eq 0 ]; then
        err "[log] ** PASSED **"
        echo "** PASSED **     ** PASSED **" > result.$dsc_basename.tmp
        echo "DateRunEnd: $epoch" >> result.$dsc_basename.tmp
        cat result.$dsc_basename >> result.$dsc_basename.tmp
        echo "exit code: $test_result" >> result.$dsc_basename.tmp
        mv result.$dsc_basename.tmp result.$dsc_basename
        write_done
        failed=0
fi 
## FAILED
[ ! -z "${dsc_failure}" ] && egrep "${dsc_failure}" result.$dsc_basename.$$ > /dev/null
# if not found this actually means PASSED
if [ $? -eq 0 ]; then
        err "[log] !! FAILED !!"
        echo "!! FAILED !!     !! FAILED !!" > result.$dsc_basename.tmp
        echo "DateRunEnd: $epoch" >> result.$dsc_basename.tmp
        cat result.$dsc_basename >> result.$dsc_basename.tmp
        echo "exit code: $test_result" >> result.$dsc_basename.tmp
        mv result.$dsc_basename.tmp result.$dsc_basename
        failed=1
else
        err "[log] ** PASSED **"
        echo "** PASSED **     ** PASSED **" > result.$dsc_basename.tmp
        echo "DateRunEnd: $epoch" >> result.$dsc_basename.tmp
        cat result.$dsc_basename >> result.$dsc_basename.tmp
        echo "exit code: $test_result" >> result.$dsc_basename.tmp
        mv result.$dsc_basename.tmp result.$dsc_basename
        write_done
        failed=0
fi

## UNKNOWN
if [ $failed -eq -1 ]; then
        # neither failed, not success, unknown
        err "[log] -- UNKNOWN --"
        echo "-- UNKNOWN --     -- UNKNOWN --" > result.$dsc_basename.tmp
        echo "DateRunEnd: $epoch" >> result.$dsc_basename.tmp
        cat result.$dsc_basename >> result.$dsc_basename.tmp
        echo "exit code: $test_result" >> result.$dsc_basename.tmp
        mv result.$dsc_basename.tmp result.$dsc_basename
        write_done
        failed=1 # not passed
fi
        
post
if [ $TPKG_KEEP -eq 0 ]; then
        out "[log] Removing temp directory $dir"
        cleanup
else
	out "[log] Keeping temp directory $dir"
fi
exit $failed
01BLOCK00000
+l 0777 1000 1000 23 18
/home/miekg/bin/tt -> t+- 0775 1000 1000 21 961
/home/miekg/bin/visit01BLOCK00961
#!/bin/zsh

# make a nice visitors page for use on miek.nl

( cat <
HEADER # create the content visitors -T -A -P http://www.miek.nl /var/log/apache2/miek.nl-access.log \ --exclude 'robots.txt' | sed -e 's/^//' -e 's/^//' \ -e 's/^//' -e 's|^||' -e 's|||' -e 's|||' -e 's/\[//' cat <
_footer FOOTER ) | perl -we ' # now fix the css style in the m5 file # remove it completely and replace it with my own my $printed = 0; while (<>) { if (m||) { system("cat /home/miekg/bin/visit.style") if ! $printed; $printed = 1; } else { print } }' > /home/miekg/miek.nl/server/visit.m5 # build the html, finally! ( cd /home/miekg/miek.nl; make -f m5.Makefile server/visit.html ) 01BLOCK00000 +- 0664 1000 1000 27 1977 /home/miekg/bin/visit.style01BLOCK01977 01BLOCK00000 +- 0775 1000 1000 19 1605 /home/miekg/bin/vit01BLOCK01605 #!/bin/zsh # a wrapper around git and vi # (c) Copyright Miek Gieben, 2009 # Licensed under GPL v3 # expands $[H]ash$ to $[H]ash: file short_hash date committer $ # block quotes are there to fool gitvi # $Hash: gitvi d0a11c5 2009-02-11 12:17:32 +0100 miekg $ [[ ! -x =git ]] && exit 1 who=${SUDO_USER:-$LOGNAME} full=$(getent passwd $who | awk -F: '{ gsub(/,*/, ""); print $5 }') author="$full <$who@atoom.net>" function usage { cat <<-EOF gitvi [-h] [-m MSG] FILE [FILE]... use git and vi together -m MSG use MSG as commit message -h this help EOF exit } zparseopts -D -K -- m:=o_msg h=o_help [[ $? != 0 || "$o_help" != "" ]] && usage o_msg=$o_msg[2] for file in "$@"; do dir=$(dirname "$file") if ! cd "$dir"; then continue; fi base=$(basename "$file") if [[ x"$(git rev-parse --git-dir 2>/dev/null)" = x"" ]]; then # make a new one in $PWD git init || exit 1 fi chmod +w "$base" 2> /dev/null if ${EDITOR:-/usr/bin/vi} "$base"; then [[ ! -e $base ]] && exit 0 git add $base # collapse $Hash: gitvi d0a11c5 2009-02-11 12:17:32 +0100 miekg $ line sed -i -e 's/\$[H]ash:.*\$/$H''ash$/' "$base" if [[ -z "$o_msg" ]]; then git commit --author "$author" "$base" else git commit -m "$o_msg" --author "$author" "$base" fi fi id=$(git show -s --pretty=format:$base\ %h\ %ci\ $who%n -- "$base") [[ -z $id ]] && exit 1 # re-add $Hash: gitvi d0a11c5 2009-02-11 12:17:32 +0100 miekg $ line sed -i -e 's/\$[H]ash\$'/\$H''ash:\ $id\ \$/ "$base" chmod a-w $base 2> /dev/null cd - >/dev/null done 01BLOCK00000 +- 0664 1000 1000 21 1133 /home/miekg/bin/vit.101BLOCK01133 '\" t .TH VIT 1 "27 Dec 2008" "0.1.0" "vit" .SH NAME vit \- a wrapper around git and vi(m) .SH SYNOPSIS vit [-m MSG] [-h] [\fIFILE\fR] .SH DESCRIPTION Edit files and commit them to a git repository. If FILE is not given nothing is done. All the directories from the current one up to the root are search for a .git directory. If no directory is found a new git repository is created in the directory where FILE is located. A new repository will never be created in the root directory. .PP The special sequence $Hash$ is expanded by \fBvit\fR to .RS $Hash: sha1hash filename date committer $ .RE .PP This expanded $Hash$ syntax is \fInot\fR commited to git, this is done after the commit has taken place. This means there will also be a diff between the file on disk and the one committed in git. .SH OPTIONS .TP .B \-h a short unhelpfull help message. .TP .B \-m MSG use MSG as a commit message, when editing multiple files \fIall\fR edits will get this a their commit message. .SH AUTHOR Miek Gieben .SH LICENSE Licensed under the GPL version 3. Copyright (c) Miek Gieben, 2009 .SH SEE ALSO vim(1), git(1). 01BLOCK00000 rdup-1.1.15/testsuite/rdup/rdup.rdup-up.exp000066400000000000000000000002621303430127500206350ustar00rootroot00000000000000set test "cat data | rdup-up -t /tmp/test must not yield any output" spawn ./testsuite/rdup/rdup.rdup-up.helper expect { -re "" { pass "$test" } default { fail "$test" } } rdup-1.1.15/testsuite/rdup/rdup.rdup-up.helper000077500000000000000000000001421303430127500213200ustar00rootroot00000000000000#!/bin/bash cat testsuite/rdup/rdup.rdup-up.data | ./rdup-up -t /tmp/test.$$ rm -rf /tmp/test.$$ rdup-1.1.15/testsuite/rdup/rdup.root-symlink.exp000066400000000000000000000003061303430127500217070ustar00rootroot00000000000000set test "Run rdup /dev/null | rdup-tr -Otar | tar vtf -" if { [catch { exec ./testsuite/rdup/rdup.root-symlink.helper } msg] } { pass "$test" } else { puts stderr "$msg" fail "$test" } rdup-1.1.15/testsuite/rdup/rdup.root-symlink.helper000077500000000000000000000002041303430127500223720ustar00rootroot00000000000000#!/bin/bash ln -s doc doc2 ./rdup /dev/null doc2 | ./rdup-tr -Otar | tar tvf - >/dev/null EXIT=$? rm -f doc2 echo $EXIT exit $EXIT rdup-1.1.15/testsuite/rdup/rdup.run-tr.exp000066400000000000000000000001661303430127500204730ustar00rootroot00000000000000set test "Run rdup-tr -V" spawn ./rdup-tr -V expect { -re "^rdup-tr" { pass "$test" } default { fail "$test" } } rdup-1.1.15/testsuite/rdup/rdup.run-up.exp000066400000000000000000000001661303430127500204720ustar00rootroot00000000000000set test "Run rdup-up -V" spawn ./rdup-up -V expect { -re "^rdup-up" { pass "$test" } default { fail "$test" } } rdup-1.1.15/testsuite/rdup/rdup.run.exp000066400000000000000000000001551303430127500200460ustar00rootroot00000000000000set test "Run rdup -V" spawn ./rdup -V expect { -re "^rdup" { pass "$test" } default { fail "$test" } } rdup-1.1.15/testsuite/rdup/rdup.s-flag.exp000066400000000000000000000002511303430127500204100ustar00rootroot00000000000000set test "rdup -s1; only output files smaller than 1 byte" spawn ./testsuite/rdup/rdup.s-flag.helper expect { -re "..*" { fail "$test" } default { pass "$test" } } rdup-1.1.15/testsuite/rdup/rdup.s-flag.helper000077500000000000000000000001431303430127500210760ustar00rootroot00000000000000#!/bin/bash # should give no output ./rdup -F '%p%T %n\n' -s1 /dev/null testsuite | grep -v '^+d' rdup-1.1.15/testsuite/rdup/rdup.simple.exp000066400000000000000000000002731303430127500205340ustar00rootroot00000000000000set test "Run rdup-simple with gpg encryption" if { [catch { exec ./testsuite/rdup/rdup.simple.helper } msg] } { puts stderr "$msg" unresolved "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.simple.helper000077500000000000000000000007311303430127500212210ustar00rootroot00000000000000#!/bin/bash # this takes place in the rdup source tree # make sure the executables used are also # these PATH=$PWD:$PATH if ! which gpg 2>/dev/null 1>&2; then exit 0 fi if [ ! -d ~/.gnupg ]; then exit 0 fi # test rdup-simple with gpg rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp rm -rf tmp mkdir tmp ./rdup-simple -g doc tmp EXIT=$? rm -rf tmp rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp exit $EXIT rdup-1.1.15/testsuite/rdup/rdup.simple2.exp000066400000000000000000000004631303430127500206170ustar00rootroot00000000000000# probably depends on GNU tar - fine for now # if { [ catch { exec true } msg ] } { puts "OK" } else { puts "NOK" } # prints NOK set test "Run rdup-simple with encryption" if { [catch { exec ./testsuite/rdup/rdup.simple2.helper } msg] } { puts stderr "$msg" fail "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.simple2.helper000077500000000000000000000006651303430127500213110ustar00rootroot00000000000000#!/bin/bash # this takes place in the rdup source tree # make sure the executables used are also # these PATH=$PWD:$PATH # test rdup-simple with path enryption rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp rm -rf tmp mkdir tmp echo 0123456789abcdef > key ./rdup-simple -z -f -k key doc tmp EXIT=$? rm -rf tmp rm -f key rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp exit $EXIT rdup-1.1.15/testsuite/rdup/rdup.simple3.exp000066400000000000000000000005151303430127500206160ustar00rootroot00000000000000# probably depends on GNU tar - fine for now # if { [ catch { exec true } msg ] } { puts "OK" } else { puts "NOK" } # prints NOK set test "Run rdup-simple with gpg encryption and compression" if { [catch { exec ./testsuite/rdup/rdup.simple3.helper } msg] } { puts stderr "$msg" unresolved "$test" } else { pass "$test" } rdup-1.1.15/testsuite/rdup/rdup.simple3.helper000077500000000000000000000006021303430127500213010ustar00rootroot00000000000000#!/bin/bash PATH=$PWD:$PATH if ! which gpg 2>/dev/null 1>&2; then exit 0 fi if [ ! -d ~/.gnupg ]; then exit 0 fi # test rdup-simple with gpg rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp rm -rf tmp mkdir tmp ./rdup-simple -f -z -g doc tmp EXIT=$? rm -rf tmp rm -f ~/.rdup/list.$(uname -n).tmp rm -f ~/.rdup/timestamp.$(uname -n).tmp exit $EXIT rdup-1.1.15/todo000066400000000000000000000001221303430127500134320ustar00rootroot00000000000000TODO Rewrite in Go? Make a input format modifier for rdup-tr and rdup (one day?) rdup-1.1.15/usage-tr.c000066400000000000000000000016011303430127500144400ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup-tr.h" extern char *PROGNAME; void usage_tr(FILE * f) { fprintf(f, _("USAGE: %s [OPTION]... \n"), PROGNAME); fputs(_("\ Translate rdup output into something else.\n\ \n\ \n\ OPTIONS:\n\ -c\t\tforce output to tty\n\ -X FILE\t\tencrypt all paths with AES and the key from FILE\n\ -Y FILE\t\tdecrypt all paths with AES and the key from FILE\n\ -h\t\tthis help\n\ -V\t\tprint version\n\ -O FMT\t\toutput format: pax, cpio, tar or rdup* (* = default)\n\ \t\trdup uses format: \"%p%T %b %u %g %l %s\\n%n%C\"\n\ -L\t\tset input format to a list of pathnames\n\ -v\t\tbe more verbose and print processed files to stderr\n\ \n\ Report bugs to \n\ Licensed under the GPL version 3.\n\ See the file LICENSE in the source distribution of rdup.\n"), f); } rdup-1.1.15/usage-up.c000066400000000000000000000017401303430127500144430ustar00rootroot00000000000000/* * Copyright (c) 2009 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup-up.h" extern char *PROGNAME; void usage_up(FILE * f) { fprintf(f, _("USAGE: %s [OPTION]... DIRECTORY\n"), PROGNAME); fputs(_("\ Update a directory tree with an rdup archive.\n\ \n\ DIRECTORY\twhere to unpack the archive\n\ \n\ \n\ OPTIONS:\n\ -t\t\tcreate DIRECTORY if it does not exist\n\ -s NUM\t\tstrip NUM leading path components\n\ -r PATH\t\tstrip PATH from each pathname\n\ -n\t\tdry run, do not touch the filesystem\n\ -V\t\tprint version\n\ -T\t\tshow table of contents. DIRECTORY is optional\n\ -u\t\tdo not create ._rdup_. with user/group information\n\ -q\t\tsilence \'chown\' failures even when \'root\'\n\ -h\t\tthis help\n\ -v\t\tbe more verbose and print processed files to stdout\n\ \n\ Report bugs to \n\ Licensed under the GPL version 3.\n\ See the file LICENSE in the source distribution of rdup.\n"), f); } rdup-1.1.15/usage.c000066400000000000000000000046141303430127500140240ustar00rootroot00000000000000/* * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details */ #include "rdup.h" extern char *PROGNAME; void usage(FILE * f) { fprintf(f, _("USAGE: %s [OPTION]... FILELIST [ DIR | FILE ]...\n"), PROGNAME); fputs(_("\ Generate a full or incremental file list. This list can be used to\n\ implement a (incremental) backup scheme.\n\ \n\ FILELIST\tfile to store filenames\n\ DIR\t\tdirectory or directories to dump, defaults to .\n\ \n\ \n\ OPTIONS:\n\ -N FILE\t\tuse the (c_time) timestamp of FILE for incremental dumps\n\ \t\tif FILE does not exist, a full dump is performed\n\ -M FILE\t\tas -N, but use the m_time\n\ -F FORMAT\tuse specified format string\n\ \t\tdefaults to: \"%p%T %b %u %g %l %s %n\\n\"\n\ -R\t\treverse the output (depth first, first the dirs then the files)\n\ -E FILE\t\tuse FILE as an exclude list\n\ -P CMD\n\ \t\tfilter file contents through CMD, will be called with 'sh -c CMD'\n\ \t\tmay be repeated, output will be filtered through all commands\n\ -V\t\tprint version\n"), f); fputs(_("\ -a\t\treset atime\n\ -c\t\tforce output to tty\n\ -m\t\tonly print new/modified files (unsets -r)\n\ -n\t\tignore .nobackup files\n\ -r\t\tonly print removed files (unsets -m)\n\ -s SIZE\t\tonly output files smaller then SIZE bytes\n\ -u\t\tdisable the special handling of ._rdup_. files\n\ -x\t\tstay in local file system\n\ -v\t\tbe more verbose\n\ -h\t\tthis help\n\ \n\ FORMAT:\n\ The following escape sequences are recognized:\n\ \'%p\': '+' if new, '-' if removed\n\ \'%b\': permission bits\n\ \'%m\': file mode bits\n\ \'%u\': uid\n\ \'%g\': gid\n\ \'%l\': path length (for links: length of \'path -> target\')\n\ \'%s\': original file size\n\ \'%n\': path (for links: \'path -> target\')\n\ \'%N\': path (for links: \'path')\n\ \'%t\': time of modification (epoch)\n\ \'%H\': the sha1 hash of the file's contents\n\ \'%T\': \'type\' (d, l, h, -, c, b, p or s: dir, symlink, hardlink, file, \n\ character device, block device, named pipe or socket)\n\ \'%C\': file contents\n\ \n\ Report bugs to \n\ Licensed under the GPL version 3.\n\ See the file LICENSE in the source distribution of rdup.\n"), f); } rdup-1.1.15/xattr.c000066400000000000000000000046741303430127500140700ustar00rootroot00000000000000/** * Copyright (c) 2005 - 2011 Miek Gieben * License: GPLv3(+), see LICENSE for details * * Not used anymore - this is a hack that I don't want to * support anymore. It stinks * * It was used in saving the uid/gid information when doing * a remote dump as a no root user. * * All xattr functions are grouped here */ #include "rdup.h" extern gint opt_verbose; uid_t read_attr_uid( __attribute__ ((unused)) char *path, uid_t u) { #ifdef HAVE_ATTR_XATTR_H /* linux */ char buf[ATTR_SIZE + 1]; uid_t x; int r; if ((r = lgetxattr(path, "user.r_uid", buf, ATTR_SIZE)) > 0) { x = (uid_t) atoi(buf); buf[r - 1] = '\0'; if (x > R_MAX_ID) { msg(_("Too large uid `%zd\' for `%s\', truncating"), (size_t) x, path); return R_MAX_ID; } return x; } else { if (opt_verbose > 0) { msg(_("No uid xattr for `%s\'"), path); } return u; } #elif HAVE_ATTROPEN /* solaris */ char buf[ATTR_SIZE + 1]; uid_t x; int attfd; int r; if ((attfd = attropen(path, "r_uid", O_RDONLY)) == -1) { if (opt_verbose > 0) { msg(_("No uid xattr for `%s\'"), path); } return u; } if ((r = read(attfd, buf, ATTR_SIZE)) == -1) { return u; } close(attfd); buf[r - 1] = '\0'; x = (uid_t) atoi(buf); if (x > R_MAX_ID) { msg(_("Too large gid `%zd\' for `%s\', truncating"), (size_t) x, path); return R_MAX_ID; } return x; #else return u; #endif /* HAVE_ATTR_XATTR_H, HAVE_ATTROPEN */ } gid_t read_attr_gid( __attribute__ ((unused)) char *path, gid_t g) { #ifdef HAVE_ATTR_XATTR_H char buf[ATTR_SIZE + 1]; gid_t x; int r; if ((r = lgetxattr(path, "user.r_gid", buf, ATTR_SIZE)) > 0) { buf[r - 1] = '\0'; x = (gid_t) atoi(buf); if (x > R_MAX_ID) { msg(_("Too large gid `%zd\' for `%s\', truncating"), (size_t) x, path); return R_MAX_ID; } return x; } else { if (opt_verbose > 0) { msg(_("No gid xattr for `%s\'"), path); } return g; } #elif HAVE_ATTROPEN /* solaris */ char buf[ATTR_SIZE + 1]; gid_t x; int attfd; int r; if ((attfd = attropen(path, "r_gid", O_RDONLY)) == -1) { if (opt_verbose > 0) { msg(_("No gid xattr for `%s\'"), path); } return g; } if ((r = read(attfd, buf, ATTR_SIZE)) == -1) { return g; } close(attfd); buf[r - 1] = '\0'; x = (uid_t) atoi(buf); if (x > R_MAX_ID) { msg(_("Too large gid `%zd\' for `%s\', truncating"), (size_t) x, path); return R_MAX_ID; } return x; #else return g; #endif /* HAVE_ATTR_XATTR_H, HAVE_ATTROPEN */ }