aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilly Tarreau <willy@wtap.(none)>2006-07-26 10:46:55 +0200
committerWilly Tarreau <willy@wtap.(none)>2006-07-26 10:46:55 +0200
commitfcb250efba23ae522c4c8cb03c47dd40edcf9603 (patch)
tree3756bd1748842a3f1049d857e8412f148a8741b9
parentInitial commit (diff)
downloadflxutils-fcb250efba23ae522c4c8cb03c47dd40edcf9603.tar.gz
[RELEASE] flxutils-0.1.4.2v0.1.4.2
-rw-r--r--README20
-rw-r--r--findcdrom/Makefile3
-rwxr-xr-xfindcdrom/findcdrombin0 -> 924 bytes
-rwxr-xr-xfindcdrom/findcdrom-debugbin0 -> 6340 bytes
-rw-r--r--findcdrom/findcdrom.c73
-rw-r--r--flx/AUTHORS1
l---------flx/COPYING1
-rw-r--r--flx/ChangeLog9
-rw-r--r--flx/LICENCE340
-rw-r--r--flx/Makefile215
-rw-r--r--flx/NOTES143
-rw-r--r--flx/README20
-rw-r--r--flx/TODO14
-rw-r--r--flx/arg.c106
-rw-r--r--flx/arg.h49
-rw-r--r--flx/check.c556
-rw-r--r--flx/check.h27
-rw-r--r--flx/ctrl132
-rw-r--r--flx/fct1.c452
-rw-r--r--flx/flx.c115
-rw-r--r--flx/flx.h264
-rw-r--r--flx/flx_fcntl.h14
l---------flx/flxcheck1
l---------flx/flxsign1
-rw-r--r--flx/input.c114
-rw-r--r--flx/input.h24
-rw-r--r--flx/input_file.c462
-rw-r--r--flx/input_file.h34
-rw-r--r--flx/input_fs.c332
-rw-r--r--flx/input_fs.h29
-rw-r--r--flx/main.c79
-rw-r--r--flx/md5.c261
-rw-r--r--flx/md5.h55
-rw-r--r--flx/output.c157
-rw-r--r--flx/output.h33
-rw-r--r--flx/output_file.c267
-rw-r--r--flx/output_file.h20
-rw-r--r--flx/sign.c117
-rw-r--r--flx/sign.h14
-rw-r--r--flx/source_type.h29
-rw-r--r--flx/utils.c147
-rw-r--r--flx/utils.h187
-rw-r--r--ifenslave/Makefile16
-rw-r--r--ifenslave/ifenslave.c652
-rw-r--r--include/rules.make20
-rw-r--r--init/Makefile3
-rw-r--r--init/README99
-rwxr-xr-xinit/examples/cd_nofloppy58
-rwxr-xr-xinit/examples/cd_preinit63
-rwxr-xr-xinit/examples/cd_ramonly66
-rwxr-xr-xinit/examples/hd_preinit60
-rwxr-xr-xinit/initbin0 -> 5620 bytes
-rw-r--r--init/init.c1274
-rwxr-xr-xinit/mkdevbin0 -> 3156 bytes
-rw-r--r--init/mkdev.c516
-rwxr-xr-xlcd/lcdteebin0 -> 684 bytes
-rwxr-xr-xlcd/lcdwritebin0 -> 812 bytes
-rw-r--r--mii/Makefile16
-rw-r--r--mii/libmii.c526
-rw-r--r--mii/mii-diag.c457
-rw-r--r--mii/starfire-diag.c640
-rw-r--r--mii/tulip-diag.c1656
-rw-r--r--mktmp/Makefile9
-rwxr-xr-xmktmp/mktmpbin0 -> 1692 bytes
-rw-r--r--mktmp/mktmp.c136
-rw-r--r--remount/Makefile12
-rwxr-xr-xremount/remountrbin0 -> 436 bytes
-rw-r--r--remount/remountr.c25
l---------remount/remountw1
-rwxr-xr-xscripts/flxadd350
-rwxr-xr-xscripts/flxfix85
-rwxr-xr-xscripts/noctrlaltdel20
-rwxr-xr-xscripts/pci-listall2
-rwxr-xr-xscripts/pcidev141
-rwxr-xr-xscripts/pkg505
-rwxr-xr-xscripts/reset3
-rwxr-xr-xsignfs/signfsbin0 -> 17596 bytes
-rw-r--r--uname/Makefile3
-rwxr-xr-xuname/unamebin0 -> 787 bytes
-rw-r--r--uname/uname.c109
-rw-r--r--wd/Makefile9
-rwxr-xr-xwd/wddbin0 -> 431 bytes
-rw-r--r--wd/wdd.c38
83 files changed, 12387 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..61fa0cb
--- /dev/null
+++ b/README
@@ -0,0 +1,20 @@
+Warning !!!
+
+ 1) this package should be compiled with the "pkg" command distributed with Formilux
+ 2) dietlibc and sstrip are needed for most small utilities. Since they're not available
+ everywhere, a pre-compiled version of these utilities is provided. To avoid unexpected
+ cleanups, "pkg clean" only cleans the minimum, and you have to use "pkg distclean" to
+ clean everything. Don't do it if you don't have all the tools to rebuild ! In this case,
+ proceed this way :
+
+ # pkg compile ; pkg prepack ; pkg strip ; pkg pack ; pkg clean
+
+Note: the "pkg" command uses several special variables which can be defined in
+the pkg file :
+ - PATCH_LIST is a list of patches to apply with "pkg patch" or revert with
+ "pkg unpatch" ;
+ - FILE_LIST contains the name of a file (.flxfiles) which contains a listing
+ of all files of the current directory to be archived in the package,
+ instead of making a tar of .flxdisk. Note that do_prepack() and do_strip()
+ should be redefined in this case (at least to do nothing).
+
diff --git a/findcdrom/Makefile b/findcdrom/Makefile
new file mode 100644
index 0000000..dd663c6
--- /dev/null
+++ b/findcdrom/Makefile
@@ -0,0 +1,3 @@
+OBJS=findcdrom findcdrom-debug
+include ../include/rules.make
+CFLAGS+=-fomit-frame-pointer
diff --git a/findcdrom/findcdrom b/findcdrom/findcdrom
new file mode 100755
index 0000000..ca03e7d
--- /dev/null
+++ b/findcdrom/findcdrom
Binary files differ
diff --git a/findcdrom/findcdrom-debug b/findcdrom/findcdrom-debug
new file mode 100755
index 0000000..116ad95
--- /dev/null
+++ b/findcdrom/findcdrom-debug
Binary files differ
diff --git a/findcdrom/findcdrom.c b/findcdrom/findcdrom.c
new file mode 100644
index 0000000..3c99b34
--- /dev/null
+++ b/findcdrom/findcdrom.c
@@ -0,0 +1,73 @@
+#include <fcntl.h>
+
+#ifdef DEBUG
+# define PRINTF printf
+#else
+# define PRINTF(...)
+#endif
+
+// RETURN VALUE:
+// 0 : ok
+// 1 : no file /proc/sys/dev/cdrom
+// 2 : failed to chdir /dev
+// 3 : cdrom found but cannot creat /dev/cdrom
+// 4 : no cdrom data found
+
+
+int main() {
+ int fd,fd2,s,t=0;
+ char tmp[4096],buff[4096],*p,*f;
+ static const char nocdrom[]="No CDROM found\n";
+
+ // find CDROM detection in /proc/sys/dev/cdrom/info
+ if ((fd=open("/proc/sys/dev/cdrom/info",O_RDONLY)) < 0) {
+ write(2,nocdrom,sizeof(nocdrom));
+ exit(1);
+ }
+ if (chdir("/dev")) {
+ PRINTF("Cannot chdir to /dev\n");
+ exit(2);
+ }
+ // looking for "driver name:"
+ while ((s=read(fd,tmp+t,4096-t)) > 0) {
+ t+=s;
+ if ((p=(char*)strstr(tmp,"\ndrive name:")) && strchr(p+=13,'\n')) {
+ // have found it, looking for drive name(s)
+ while (*p != '\n') {
+ while (*p == ' ' || *p == '\t') p++;
+ for (f=p;*f > ' ' ; f++) ;
+ if (*f == '\n') *f=0; else *f++=0;
+ // found and now try
+ PRINTF("Trying [%s]\n",p);
+ if ((fd2=open(p,O_RDONLY)) >= 0) {
+ // read a small packet to detect valid iso9660
+ if (read(fd2,buff,4096) > 0) {
+ close(fd2);
+ close(fd);
+ // creat the symbolic link to /dev/cdrom
+ if (symlink(p,"cdrom") == 0) {
+#ifdef DEBUG
+ write(2," ",2);
+#endif
+ write(2,"Found CDROM: ",13);
+ write(2,p,strlen(p));
+ write(2,"\n",1);
+ exit(0);
+ }
+ exit(3);
+ }
+ PRINTF(" read failed\n");
+ close(fd2);
+ } else {
+ PRINTF(" open failed\n");
+ }
+ p=f;
+ }
+ break;
+ }
+ }
+ if (s >= 0) close(fd);
+ write(2,nocdrom,sizeof(nocdrom));
+ return (4);
+}
+
diff --git a/flx/AUTHORS b/flx/AUTHORS
new file mode 100644
index 0000000..0e11609
--- /dev/null
+++ b/flx/AUTHORS
@@ -0,0 +1 @@
+Benoit Dolez <benoit@ant-computing.com>
diff --git a/flx/COPYING b/flx/COPYING
new file mode 120000
index 0000000..97ea633
--- /dev/null
+++ b/flx/COPYING
@@ -0,0 +1 @@
+LICENCE \ No newline at end of file
diff --git a/flx/ChangeLog b/flx/ChangeLog
new file mode 100644
index 0000000..50da2b5
--- /dev/null
+++ b/flx/ChangeLog
@@ -0,0 +1,9 @@
+2003/01/04 : Version 0.6.6c
+- Before a crash disk, I
+2001/12/23 : Version 0.3
+- add checking routing
+2001/12/16 : Version 0.2
+- add -x flag to restrict to one filesystem
+2001/10/29 : Version 0.1
+- first release
+
diff --git a/flx/LICENCE b/flx/LICENCE
new file mode 100644
index 0000000..d60c31a
--- /dev/null
+++ b/flx/LICENCE
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) 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
+this service 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 make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. 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.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+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
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the 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 a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE 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.
+
+ 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
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision 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, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This 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 Library General
+Public License instead of this License.
diff --git a/flx/Makefile b/flx/Makefile
new file mode 100644
index 0000000..37e878b
--- /dev/null
+++ b/flx/Makefile
@@ -0,0 +1,215 @@
+#
+# SignFS : Tool to have an image of the filesystem
+#
+# Copyright (C) 1999-2001, Benoit Dolez <benoit@meta-x.org>
+#
+# 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 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+
+#
+# File: Makefile
+# Version: 0.6
+# Date: Sun Dec 23 14:21:50 CET 2001
+#
+
+
+NAME=flx
+VERSION=0.6.6d
+COPYRIGHT="Copyright 2002, Benoit DOLEZ <bdolez@ant-computing.com>"
+SRC=main.c arg.c utils.c md5.c flx.c fct1.c check.c sign.c \
+ input.c input_fs.c input_file.c \
+ output.c output_file.c
+OBJ=$(SRC:.c=.o)
+CFLAGS= -Wall -O2 -DMEM_OPTIM -DPROGRAM_NAME=\"$(NAME)\" -DPROGRAM_VERSION=\"$(VERSION)\" -DCOPYRIGHT=\"$(COPYRIGHT)\"
+LDFLAGS=-L.
+
+$(NAME): $(OBJ)
+ $(CC) -o $(NAME) $(OBJ) $(LDFLAGS)
+# strip -R .note -R .comment signfs
+
+clean:
+ @$(RM) -vf $(NAME) $(OBJ) $(LIBTOOLS:.c=.o) *~ core *.bak
+
+bkup:
+ (cd .. ; tar zcvf $(NAME)-$(VERSION).tgz $(NAME)-$(VERSION)/*.{c,h} $(NAME)-$(VERSION)/[A-Z]* )
+
+
+# DO NOT DELETE
+
+arg.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
+arg.o: /usr/include/gnu/stubs.h /usr/include/bits/types.h
+arg.o: /usr/include/libio.h /usr/include/_G_config.h
+arg.o: /usr/include/bits/stdio_lim.h /usr/include/string.h arg.h
+check.o: /usr/include/string.h /usr/include/features.h
+check.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+check.o: /usr/include/stdio.h /usr/include/bits/types.h /usr/include/libio.h
+check.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h flx.h
+check.o: /usr/include/sys/stat.h /usr/include/bits/stat.h
+check.o: /usr/include/sys/types.h /usr/include/time.h
+check.o: /usr/include/netinet/in.h /usr/include/limits.h
+check.o: /usr/include/stdint.h /usr/include/bits/wordsize.h
+check.o: /usr/include/bits/socket.h /usr/include/bits/sockaddr.h
+check.o: /usr/include/asm/socket.h /usr/include/asm/sockios.h
+check.o: /usr/include/bits/in.h /usr/include/endian.h
+check.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h utils.h
+check.o: /usr/include/malloc.h md5.h check.h arg.h input.h source_type.h
+check.o: output.h output_file.h input_file.h flx_fcntl.h input_fs.h
+fct1.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
+fct1.o: /usr/include/gnu/stubs.h /usr/include/bits/types.h
+fct1.o: /usr/include/libio.h /usr/include/_G_config.h
+fct1.o: /usr/include/bits/stdio_lim.h /usr/include/unistd.h
+fct1.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
+fct1.o: /usr/include/sys/stat.h /usr/include/bits/stat.h
+fct1.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/fcntl.h
+fct1.o: /usr/include/bits/fcntl.h /usr/include/dirent.h
+fct1.o: /usr/include/bits/dirent.h /usr/include/string.h
+fct1.o: /usr/include/stdlib.h flx.h /usr/include/netinet/in.h
+fct1.o: /usr/include/limits.h /usr/include/stdint.h
+fct1.o: /usr/include/bits/wordsize.h /usr/include/bits/socket.h
+fct1.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+fct1.o: /usr/include/asm/sockios.h /usr/include/bits/in.h
+fct1.o: /usr/include/endian.h /usr/include/bits/endian.h
+fct1.o: /usr/include/bits/byteswap.h utils.h /usr/include/malloc.h md5.h
+flx.o: /usr/include/string.h /usr/include/features.h /usr/include/sys/cdefs.h
+flx.o: /usr/include/gnu/stubs.h utils.h /usr/include/sys/stat.h
+flx.o: /usr/include/bits/types.h /usr/include/bits/stat.h
+flx.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/malloc.h
+flx.o: /usr/include/stdio.h /usr/include/libio.h /usr/include/_G_config.h
+flx.o: /usr/include/bits/stdio_lim.h flx.h /usr/include/netinet/in.h
+flx.o: /usr/include/limits.h /usr/include/stdint.h
+flx.o: /usr/include/bits/wordsize.h /usr/include/bits/socket.h
+flx.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+flx.o: /usr/include/asm/sockios.h /usr/include/bits/in.h
+flx.o: /usr/include/endian.h /usr/include/bits/endian.h
+flx.o: /usr/include/bits/byteswap.h md5.h
+input.o: /usr/include/string.h /usr/include/features.h
+input.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h utils.h
+input.o: /usr/include/sys/stat.h /usr/include/bits/types.h
+input.o: /usr/include/bits/stat.h /usr/include/sys/types.h
+input.o: /usr/include/time.h /usr/include/malloc.h /usr/include/stdio.h
+input.o: /usr/include/libio.h /usr/include/_G_config.h
+input.o: /usr/include/bits/stdio_lim.h source_type.h flx.h
+input.o: /usr/include/netinet/in.h /usr/include/limits.h
+input.o: /usr/include/stdint.h /usr/include/bits/wordsize.h
+input.o: /usr/include/bits/socket.h /usr/include/bits/sockaddr.h
+input.o: /usr/include/asm/socket.h /usr/include/asm/sockios.h
+input.o: /usr/include/bits/in.h /usr/include/endian.h
+input.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h md5.h
+input.o: input.h flx_fcntl.h
+input_file.o: /usr/include/stdio.h /usr/include/features.h
+input_file.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+input_file.o: /usr/include/bits/types.h /usr/include/libio.h
+input_file.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h
+input_file.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+input_file.o: /usr/include/bits/confname.h /usr/include/string.h
+input_file.o: /usr/include/sys/types.h /usr/include/time.h
+input_file.o: /usr/include/stdlib.h /usr/include/dirent.h
+input_file.o: /usr/include/bits/dirent.h input_file.h utils.h
+input_file.o: /usr/include/sys/stat.h /usr/include/bits/stat.h
+input_file.o: /usr/include/malloc.h flx.h /usr/include/netinet/in.h
+input_file.o: /usr/include/limits.h /usr/include/stdint.h
+input_file.o: /usr/include/bits/wordsize.h /usr/include/bits/socket.h
+input_file.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+input_file.o: /usr/include/asm/sockios.h /usr/include/bits/in.h
+input_file.o: /usr/include/endian.h /usr/include/bits/endian.h
+input_file.o: /usr/include/bits/byteswap.h md5.h flx_fcntl.h
+input_fs.o: /usr/include/stdio.h /usr/include/features.h
+input_fs.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+input_fs.o: /usr/include/bits/types.h /usr/include/libio.h
+input_fs.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h
+input_fs.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+input_fs.o: /usr/include/bits/confname.h /usr/include/string.h
+input_fs.o: /usr/include/sys/types.h /usr/include/time.h
+input_fs.o: /usr/include/dirent.h /usr/include/bits/dirent.h input_fs.h
+input_fs.o: utils.h /usr/include/sys/stat.h /usr/include/bits/stat.h
+input_fs.o: /usr/include/malloc.h flx.h /usr/include/netinet/in.h
+input_fs.o: /usr/include/limits.h /usr/include/stdint.h
+input_fs.o: /usr/include/bits/wordsize.h /usr/include/bits/socket.h
+input_fs.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+input_fs.o: /usr/include/asm/sockios.h /usr/include/bits/in.h
+input_fs.o: /usr/include/endian.h /usr/include/bits/endian.h
+input_fs.o: /usr/include/bits/byteswap.h md5.h flx_fcntl.h
+main.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
+main.o: /usr/include/gnu/stubs.h /usr/include/bits/types.h
+main.o: /usr/include/libio.h /usr/include/_G_config.h
+main.o: /usr/include/bits/stdio_lim.h /usr/include/unistd.h
+main.o: /usr/include/bits/posix_opt.h /usr/include/bits/confname.h
+main.o: /usr/include/sys/stat.h /usr/include/bits/stat.h
+main.o: /usr/include/sys/types.h /usr/include/time.h /usr/include/fcntl.h
+main.o: /usr/include/bits/fcntl.h /usr/include/dirent.h
+main.o: /usr/include/bits/dirent.h /usr/include/string.h
+main.o: /usr/include/stdlib.h flx.h /usr/include/netinet/in.h
+main.o: /usr/include/limits.h /usr/include/stdint.h
+main.o: /usr/include/bits/wordsize.h /usr/include/bits/socket.h
+main.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+main.o: /usr/include/asm/sockios.h /usr/include/bits/in.h
+main.o: /usr/include/endian.h /usr/include/bits/endian.h
+main.o: /usr/include/bits/byteswap.h utils.h /usr/include/malloc.h md5.h
+main.o: check.h arg.h sign.h
+md5.o: /usr/include/string.h /usr/include/features.h /usr/include/sys/cdefs.h
+md5.o: /usr/include/gnu/stubs.h md5.h
+output.o: /usr/include/string.h /usr/include/features.h
+output.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h utils.h
+output.o: /usr/include/sys/stat.h /usr/include/bits/types.h
+output.o: /usr/include/bits/stat.h /usr/include/sys/types.h
+output.o: /usr/include/time.h /usr/include/malloc.h /usr/include/stdio.h
+output.o: /usr/include/libio.h /usr/include/_G_config.h
+output.o: /usr/include/bits/stdio_lim.h flx.h /usr/include/netinet/in.h
+output.o: /usr/include/limits.h /usr/include/stdint.h
+output.o: /usr/include/bits/wordsize.h /usr/include/bits/socket.h
+output.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+output.o: /usr/include/asm/sockios.h /usr/include/bits/in.h
+output.o: /usr/include/endian.h /usr/include/bits/endian.h
+output.o: /usr/include/bits/byteswap.h md5.h output.h source_type.h
+output.o: flx_fcntl.h
+output_file.o: flx.h /usr/include/sys/stat.h /usr/include/features.h
+output_file.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+output_file.o: /usr/include/bits/types.h /usr/include/bits/stat.h
+output_file.o: /usr/include/sys/types.h /usr/include/time.h
+output_file.o: /usr/include/netinet/in.h /usr/include/limits.h
+output_file.o: /usr/include/stdint.h /usr/include/bits/wordsize.h
+output_file.o: /usr/include/bits/socket.h /usr/include/bits/sockaddr.h
+output_file.o: /usr/include/asm/socket.h /usr/include/asm/sockios.h
+output_file.o: /usr/include/bits/in.h /usr/include/endian.h
+output_file.o: /usr/include/bits/endian.h /usr/include/bits/byteswap.h
+output_file.o: utils.h /usr/include/malloc.h /usr/include/string.h
+output_file.o: /usr/include/stdio.h /usr/include/libio.h
+output_file.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h md5.h
+output_file.o: output_file.h input_file.h flx_fcntl.h check.h arg.h output.h
+output_file.o: source_type.h
+sign.o: /usr/include/stdio.h /usr/include/features.h /usr/include/sys/cdefs.h
+sign.o: /usr/include/gnu/stubs.h /usr/include/bits/types.h
+sign.o: /usr/include/libio.h /usr/include/_G_config.h
+sign.o: /usr/include/bits/stdio_lim.h input.h source_type.h flx.h
+sign.o: /usr/include/sys/stat.h /usr/include/bits/stat.h
+sign.o: /usr/include/sys/types.h /usr/include/time.h
+sign.o: /usr/include/netinet/in.h /usr/include/limits.h /usr/include/stdint.h
+sign.o: /usr/include/bits/wordsize.h /usr/include/bits/socket.h
+sign.o: /usr/include/bits/sockaddr.h /usr/include/asm/socket.h
+sign.o: /usr/include/asm/sockios.h /usr/include/bits/in.h
+sign.o: /usr/include/endian.h /usr/include/bits/endian.h
+sign.o: /usr/include/bits/byteswap.h utils.h /usr/include/malloc.h
+sign.o: /usr/include/string.h md5.h output.h arg.h input_fs.h flx_fcntl.h
+sign.o: input_file.h output_file.h
+utils.o: /usr/include/string.h /usr/include/features.h
+utils.o: /usr/include/sys/cdefs.h /usr/include/gnu/stubs.h
+utils.o: /usr/include/stdio.h /usr/include/bits/types.h /usr/include/libio.h
+utils.o: /usr/include/_G_config.h /usr/include/bits/stdio_lim.h
+utils.o: /usr/include/dirent.h /usr/include/bits/dirent.h
+utils.o: /usr/include/unistd.h /usr/include/bits/posix_opt.h
+utils.o: /usr/include/bits/confname.h /usr/include/sys/types.h
+utils.o: /usr/include/time.h /usr/include/fcntl.h /usr/include/bits/fcntl.h
+utils.o: utils.h /usr/include/sys/stat.h /usr/include/bits/stat.h
+utils.o: /usr/include/malloc.h
diff --git a/flx/NOTES b/flx/NOTES
new file mode 100644
index 0000000..aa9c010
--- /dev/null
+++ b/flx/NOTES
@@ -0,0 +1,143 @@
+Une fonction qui permet de completer la structure contenue dans ctxtree d'après la source qui lui est fournie. Le contexte doit conserver le niveau de descente le plus bas lors de la lecture des informations de manière à optimiser les accès lors de la comparaison.
+
+Une fonction qui permet de comparer 2 contextes d'arborescence. On compare les arborescences à partir du niveau commun le plus elevé (PGCD), et uniquement pour les parents marqués modifiés. Cette comparaison s'effectue sur chacun des éléments.
+
+Ces opérations s'effectuent en boucle jusqu'à la fin de la lecture des données dans chacune des sources.
+
+Opérations de signatures et de comparaison:
+/#flxsign etc
+ etc/.
+ etc/..
+ etc/X11
+ (...)
+ etc/zprofile
+
+#flxsign /etc
+ etc/.
+ etc/..
+ etc/X11
+ (...)
+ etc/zprofile
+
+#flxsign ../etc
+ etc/etc-cont
+
+/#flxsign ../../../../etc
+ etc/.
+ etc/..
+ etc/X11
+ (...)
+ etc/zprofile
+
+/#flxsign ./etc
+ etc/etc-cont
+
+/#flxsign ././././etc
+ etc/etc-cont
+
+#flxsign /usr/local/bin/../../etc
+ etc
+
+#flxsign /usr/local/bin/../../local/etc
+ local/etc
+
+/home/ben#flxsign usr/../../etc
+ etc
+
+#flxsign /etc/.
+ etc-cont
+
+* on supprime tout ce qui se trouve à gauche d'un '.' ou d'un '..'
+* on supprime le premier '/'
+
+#flxsign /
+ slash-cont
+
+#flxsign ../
+ ..-cont
+
+#flxsign /etc /usr/etc
+ etc/etc-cont
+ usr/etc/usr_etc-cont
+
+/usr#flxsign /etc ../etc
+ etc/etc-cont
+ etc/.._etc-cont (/etc)
+
+/usr/local#flxsign /etc ../etc
+ etc/etc-cont
+ etc/.._etc-cont (/usr/etc)
+
+/#flxsign /etc etc
+ etc/etc-cont
+ etc/etc-cont
+
+* par un flag, permettre faire correspondre avec le filesystem (résolution physique)
+
+/#flxsign /etc etc=old-etc
+ etc/etc-cont
+ old-etc/etc-cont
+
+/#flxsign /etc /save/etc=old-etc
+ etc/etc-cont
+ old-etc/save_etc-cont
+
+/#flxsign /etc /save/etc=old-etc stdout:=/backup/server1
+ /backup/server1/etc/etc-cont
+ /backup/server1/old-etc/save_etc-cont
+
+* la sortie travaille au niveau chaine contrairement à l'entrée qui travaille au niveau
+ de la signification de l'élément
+
+#flxsign /server1/./etc
+ etc/server1_etc-cont
+
+
+-------------------------------
+check
+
+/usr#flxcheck /usr/etc --diff /etc
+ usr/etc/usr_etc-cont <-> etc/etc-cont -> no
+
+/usr#flxcheck /usr/etc=/etc --diff /etc
+ etc/usr_etc-cont <-> etc/etc-cont -> ok
+
+/usr#flxcheck /usr/./etc --diff /etc
+ etc/usr_etc-cont <-> etc/etc-cont -> ok
+
+#flxcheck
+
+* option nettoyage des '/', supprimer debut, fin et multiples
+
+* (précision des 3 parametres d'output 1 pour src1 1 pour source 2 et un global)
+ pour chaque source, on peut préciser un préfixe aux résultats des sources
+ respectives.
+ le troisième paramêtre, pour l'output permet de globalement réécrire l'output.
+ --in1=/usr/local /usr/local/./etc --in2=/ /etc stdout:/server1
+ compare les répértoires /usr/local/etc et /etc, écrit sous la forme le répertoire
+ et les faits précéder de /server1 :
+ /server1/usr/local/etc/...
+ /server1/etc/...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/flx/README b/flx/README
new file mode 100644
index 0000000..8071296
--- /dev/null
+++ b/flx/README
@@ -0,0 +1,20 @@
+signfs-0.1, October, 29 2001
+Initial release
+----------------------------------------------------
+benoit@ant-computing.com
+
+INTRODUCTION
+------------
+This package is need for formilux future distrib.
+
+DESCRIPTION
+-----------
+
+REQUIREMENTS
+-------------
+
+USAGE
+-----
+signfs [filename ...]
+This command will show identity informations of any filenames or
+current directory recursively.
diff --git a/flx/TODO b/flx/TODO
new file mode 100644
index 0000000..8f7cb18
--- /dev/null
+++ b/flx/TODO
@@ -0,0 +1,14 @@
+2002/06/18:
+ completly change
+
+2002/01/20:
+ - '.' and '..' resolve?
+
+2001/12/24:
+ - need to correct all orthographic mistakes :-)
+ - make the binary capable to tell about its version
+ - clean the makefile and remove unused files
+
+2001/10/29:
+- Need a complet documentation and manual
+
diff --git a/flx/arg.c b/flx/arg.c
new file mode 100644
index 0000000..52ecfed
--- /dev/null
+++ b/flx/arg.c
@@ -0,0 +1,106 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "arg.h"
+
+
+#define TUNDEF 1
+#define TSHORT 2
+#define TLONG 4
+
+char *Progname ;
+
+
+/* show usage for program with ParamOptions global pointer
+ * message : message to see (stdarg form), NULL mean no message
+ * exit with value 1
+ */
+void arg_usage(t_param *p, char *message, ...) {
+ va_list argp;
+
+ if (message) {
+ va_start(argp, message);
+ fprintf(stderr, "Error: ");
+ vfprintf(stderr, message, argp);
+ fprintf(stderr, "\n");
+ va_end(argp);
+ }
+ fprintf(stderr, "%s %s, %s\n", PROGRAM_NAME, PROGRAM_VERSION, COPYRIGHT);
+ fprintf(stderr, "usage: %s [options] [...]\n", Progname);
+ while(p && p->optnum) {
+ fprintf(stderr, " %s\n", p->help);
+ p++;
+ }
+ exit(1);
+}
+
+/* return programme name
+ * pathprogname : argv[0]
+ * (return) pointer to the programme name in this string
+ */
+char *progname(char *pathprogname) {
+ if (Progname) return (Progname);
+ if ((Progname = strrchr(pathprogname, '/')))
+ Progname++;
+ else
+ Progname = pathprogname;
+ return (Progname);
+}
+
+/* argument checking
+ * argc, argv : main parameters
+ * (return): 1 if no error
+ */
+int arg_init(int argc, char **argv, t_param *paramoptions, int (*paramfct)()) {
+ char *flag;
+ int ft = TUNDEF, opt, ret, nbargc = 1;
+ t_param *p = NULL;
+
+ argc--; argv++; flag = *argv;
+ while (argc > 0) {
+
+ opt = -1;
+ // printf("%d,%d: %s -> %s\n", argc, ft, *argv, flag);
+ if (*flag == '-' && ft == TUNDEF) ft = TSHORT;
+ else if (*flag == '-' && ft == TSHORT) ft = TLONG;
+ else if (*flag == 0 && ft == TLONG) break;
+ else if (*flag == 0 && ft == TSHORT) break;
+ else if (ft == TSHORT) {
+ for (p = paramoptions; p->optnum && p->shortopt != *flag; p++);
+ opt = p->optnum;
+ }
+ else if (ft == TLONG) {
+ for (p = paramoptions; p->optnum &&
+ (!p->longopt || strcmp(flag, p->longopt)); p++);
+ opt = p->optnum;
+ }
+ if (opt == -1 && ft != TUNDEF ) { flag++; continue; }
+ if (opt == 0 && ft == TSHORT)
+ arg_usage(paramoptions, "Unkwnon short argument: -%c", *flag);
+ if (opt == 0 && ft == TLONG)
+ arg_usage(paramoptions, "Unkwnon long argument: --%s", flag);
+ if (opt > 0 && p && argc < p->minarg)
+ arg_usage(paramoptions, "Missing argument: %s", p->help);
+
+ if ((ret = paramfct(opt, p, &flag, argv)) == -1 && ft != TUNDEF)
+ arg_usage(paramoptions, "Bad argument: %s", p->help);
+ else if (ret == -1)
+ break;
+ else {
+ argc -= ret; argv += ret;
+ nbargc += ret;
+ }
+
+ if (!*(flag+1) || ft != TSHORT) {
+ argc--; argv++;
+ nbargc++;
+ ft = TUNDEF;
+ flag = *argv;
+ }
+ else
+ flag++;
+ }
+ return (nbargc);
+}
+
diff --git a/flx/arg.h b/flx/arg.h
new file mode 100644
index 0000000..d1180d2
--- /dev/null
+++ b/flx/arg.h
@@ -0,0 +1,49 @@
+#ifndef __ARG_H__
+#define __ARG_H__
+
+#include <stdio.h>
+
+typedef struct p_param t_param;
+
+struct p_param {
+ char shortopt;
+ char *longopt;
+ int optnum;
+ int minarg;
+ char *help;
+};
+
+extern char *Progname ;
+
+/* example: use of t_param
+t_param sample_poptions[] = {
+ { 'h', "help", 0xFFFF, 0, "this help" },
+ { 0, NULL, 0, 0}
+};
+
+int sample_pfct(int opt, t_param *param, char **flag, char **argv) {
+ if (opt == 0xFFFF) arg_usage(sample_poptions, NULL);
+ return (param ? param->minarg : 0);
+}
+
+int main(int argc, char **argv) {
+ int ret;
+
+ ret = arg_init(argc, argv, sample_poptions, sample_pfct);
+ if (ret <= 0) return (1);
+ argc -= ret; argv += ret;
+
+ ...
+}
+
+*/
+
+int arg_init(int argc, char **argv, t_param *paramoptions, int (*paramfct)()) ;
+char *progname(char *);
+void arg_usage(t_param *p, char *message, ...);
+
+
+#endif /* __ARG_H__ */
+
+
+
diff --git a/flx/check.c b/flx/check.c
new file mode 100644
index 0000000..cbc8639
--- /dev/null
+++ b/flx/check.c
@@ -0,0 +1,556 @@
+/*
+ * Signfs version 0.6, Copyright Benoit DOLEZ, 2002
+ */
+
+/* command line is:
+ * ./flx check [options] input1 input2
+ * ./flx check [options] [inputs1] , [inputs2]
+ * options are :
+ * -h,--help : this help
+ * --ignore-mode : ignore file mode
+ * --ignore-owner : ignore owner (user, group)
+ * --ignore-dev : ignore device type
+ * --ignore-size : ignore file size
+ * --ignore-sum : ignore checksum (md5)
+ * --ignore-date : ignore date
+ * --ignore-link : ignore link
+ * --ignore-ldate : ignore links date
+ * --show-new : show only new files
+ * --show-old : show only removed files
+ * --show-all : show all files (sames and differs)
+ */
+
+
+#include <string.h>
+#include <stdio.h>
+
+#include "flx.h"
+#include "check.h"
+#include "input.h"
+#include "output.h"
+#include "output_file.h"
+#include "input_file.h"
+#include "input_fs.h"
+
+static POOL_INIT(t_file_diff);
+
+#define O_HELP 1
+#define O_SH_HR 5
+#define O_SH_ALL 6
+#define O_SH_NEW 7
+#define O_SH_OLD 8
+#define O_IGN_MODE 9
+#define O_IGN_OWNER 10
+#define O_IGN_SUM 11
+#define O_IGN_SIZE 12
+#define O_IGN_DATE 13
+#define O_IGN_LINK 14
+#define O_IGN_LDATE 15
+#define O_REWRITE_SRC1 16
+#define O_REWRITE_SRC2 17
+#define O_OUTPUT 18
+#define O_IGN_DOT 19
+
+t_param flxcheck_poptions[] = {
+ { 'h', "help", O_HELP, 0,
+ "-h,--help show this help"},
+ { 0, "ignore-mode", O_IGN_MODE, 0,
+ "--ignore-mode ignore mode" },
+ { 0, "ignore-owner", O_IGN_OWNER, 0,
+ "--ignore-owner ignore uid/gid" },
+ { 0, "ignore-sum", O_IGN_SUM, 0,
+ "--ignore-sum ignore checksum" },
+ { 0, "ignore-size", O_IGN_SIZE, 0,
+ "--ignore-size ignore size" },
+ { 'd', "ignore-date", O_IGN_DATE, 0,
+ "--ignore-date ignore date" },
+ { 0, "ignore-link", O_IGN_LINK, 0,
+ "-d,--ignore-link ignore link" },
+ { 0, "ignore-ldate", O_IGN_LDATE, 0,
+ "--ignore-ldate ignore date on links" },
+ { 0, "ignore-dot", O_IGN_DOT, 0,
+ "--ignore-dot do not compare '.' and '..'" },
+ { 0, "show-all", O_SH_ALL, 0,
+ "--show-all show all files (same and differs)" },
+ { 0, "only-new", O_SH_NEW, 0,
+ "--only-new show only new files"},
+ { 0, "only-old", O_SH_OLD, 0,
+ "--only-old show only old files"},
+ { 0, "human-readable", O_SH_HR, 0,
+ "--human-readable show long format"},
+ { 0, "rw1", O_REWRITE_SRC1, 1,
+ "--rw1 <string> string before first source path"},
+ { 0, "rw2", O_REWRITE_SRC2, 1,
+ "--rw2 <string> string before second source path"},
+ { 0, "op", O_OUTPUT, 1,
+ "--op <string> all output prefix"},
+ { 0, NULL, 0 }
+} ;
+
+static int output_diff_fcntl(t_file_status *env, int cmd);
+static int output_diff_write(t_file_status *spec, t_ft *tree, int number);
+
+
+static t_source_type InputTypes[] = {
+ { "fs",
+ (void*)input_fs_open, (void*)input_fs_read, NULL, (void*)input_fs_close,
+ (void*)input_fs_fcntl },
+ { "file",
+ (void*)input_file_open, (void*)input_file_read, NULL, (void*)input_file_close,
+ (void*)input_file_fcntl },
+ { "stdin",
+ (void*)input_stdin_open, (void*)input_file_read, NULL, (void*)input_file_close,
+ (void*)input_file_fcntl },
+ { NULL }
+};
+
+static t_source_type OutputTypes[] = {
+ { "stdout",
+ (void*)output_stdout_open, NULL, (void*)output_diff_write, (void*)output_file_close,
+ (void*)output_diff_fcntl},
+ { NULL }
+};
+
+
+
+static void *InputSrc1, *InputSrc2, *Output;
+static char *Rewrite_Src1 = NULL, *Rewrite_Src2 = NULL, *Output_Str = NULL;
+
+
+/* cette fonction permet de repérer toutes les données communes à deux sources et de
+ * les inserer dans un autre arbre
+ * cette fonction retourne le nombre d'éléments sortis des arbres sources
+ */
+int ft_find_diff(t_ft *src1, t_ft *src2, t_ft *dst) {
+ int count = 0, ret, diff;
+ t_file_diff *desc;
+ t_ft *next1, *next2;
+
+ /* on démarre du fils de chaque arbre en créant au besoin les
+ éléments manquant dans l'arbre destination */
+
+ if (!src1 || !src2 || !src1->subtree || !src2->subtree) return (0);
+
+ if (dst && !dst->subtree) {
+ dst->subtree = NEWDIR(dst);
+ }
+
+ src1 = src1->subtree->next;
+ src2 = src2->subtree->next;
+ dst = dst->subtree->next;
+
+ while (!IS(src1->status, BASE) && !IS(src2->status, BASE)) {
+ /* look for next same data */
+ while ((ret = strcmp(src1->filename, src2->filename))) {
+ if (ret < 0) src1 = src1->next;
+ if (ret > 0) src2 = src2->next;
+ /* no element found return */
+ if (IS(src1->status, BASE) || IS(src2->status, BASE))
+ return (count);
+ }
+
+ /* backup next pointers */
+ next1 = src1->next; next2 = src2->next;
+
+ /* place dst to best previous position */
+ while (!IS(dst->status, BASE) && strcmp(src1->filename, dst->filename) <= 0)
+ dst = dst->next;
+ dst = dst->prev;
+
+ /* only if they are filled */
+ if (IS(src1->status, FILLED) && IS(src2->status, FILLED)) {
+ /* pass '.' and '..' when IGNORE_DOT option */
+ //REM if ((!IS(Options, GOPT_IGNORE_DOT) || !IS_DOTF(src1->filename)) &&
+ if ((diff = files_are_the_same(src1->desc, src2->desc, Diff, NULL)) || IS(Options, SHOW_ALL)) {
+ /* should be place before current dst, but at the good place */
+ dst = ft_add(dst, src1->filename, NULL, NULL);
+
+ /* remove usage of c1->filename, in src1 if used by dst */
+ if (src1->filename == dst->filename)
+ dst->filename = strdup(src1->filename);
+
+ /* else already exist */
+ if (dst->desc) {
+ /* a test can be made with dst->desc ..., probably an
+ * error in source data */
+ warning("duplicate entry in sources");
+ }
+ else {
+ /* create difference description structure */
+ dst->desc = desc = POOL_ALLOC(t_file_diff);
+ desc->diff = diff;
+ desc->src1 = src1->desc; src1->desc = NULL;
+ desc->src2 = src2->desc; src2->desc = NULL;
+
+ /* mark changed */
+ SET(dst->status, FILLED);
+ SET_PARENT(dst, CHANGED);
+ /* update counter */
+ count++;
+ }
+ }
+ /* mark already seen */
+ UNSET(src1->status, FILLED);
+ UNSET(src2->status, FILLED);
+
+ // printf("%s treated\n", src2->filename);
+
+ // if (!src1->subtree) ft_del(src1, NULL, NULL);
+ // if (!src2->subtree) ft_del(src2, NULL, NULL);
+
+ }
+ /* if directory, run into */
+ if (src1->subtree && src2->subtree &&
+ (IS(src1->status, CHANGED) || IS(src2->status, CHANGED)) &&
+ !IS_PDOTF(src1) && !IS_PDOTF(src2)) {
+ /* get directory in dst or create it */
+ dst = ft_add(dst, src1->filename, NULL, NULL);
+ if (src1->filename == dst->filename)
+ dst->filename = strdup(dst->filename);
+
+ count += ft_find_diff(src1, src2, dst);
+ }
+
+ /* go to next */
+ src1 = next1; src2 = next2;
+ }
+ return (count);
+}
+
+/* cette fonction permet de déplacer le contenu d'un premier arbre dans un
+ * deuxième arbre
+ */
+void ft_move(t_ft *src, t_ft *dst) {
+ t_ft *next;
+ int ret;
+
+ if (!src || !dst || !src->subtree) return;
+
+ /* move full subtree */
+ if (!dst->subtree && src->subtree) {
+ t_ft *cur;
+
+ /* change parent */
+ src->subtree->parent = dst;
+ for (cur = src->subtree->next; !IS(cur->status, BASE); cur = cur->next) {
+ if (IS_PDOTDOT(cur))
+ cur->subtree = dst->parent->subtree;
+ cur->parent = dst;
+ }
+ /* change from src to dst */
+ dst->subtree = src->subtree;
+ src->subtree = NULL;
+ return ;
+ }
+
+ src = src->subtree->next;
+ dst = dst->subtree->next;
+
+ while (!IS(src->status, BASE)) {
+ /* backup next position */
+ next = src->next;
+
+ ret = 1;
+ /* search for it in dst */
+ while (!IS(dst->status, BASE) &&
+ (ret = strcmp(dst->filename, src->filename)) < 0)
+ dst = dst->next;
+
+ if (ret == 0) {
+ /* element exist */
+ /* need to move description */
+ if (src->desc && IS(src->status, FILLED) && !dst->desc) {
+ dst->desc = src->desc;
+ src->desc = NULL;
+ }
+ /* need to run into */
+ if (src->subtree) {
+ if (IS_PDOT(src)) {
+ dst->subtree = dst->parent->subtree;
+ src->subtree = NULL;
+ }
+ else if (IS_PDOTDOT(src)) {
+ dst->subtree = dst->parent->parent->subtree;
+ src->subtree = NULL;
+ }
+ else {
+ ft_move(src, dst);
+ }
+ }
+ ft_del(src, NULL, NULL);
+ }
+ else {
+ dst = dst->prev; /* go back to the previous one */
+ /* unchain from source tree */
+ LIST_UNCHAIN(src);
+ /* chain to destination tree */
+ LIST_CHAIN(dst, src, dst->next);
+
+ /* change parent hierarchy */
+ if (IS_PDOT(src))
+ src->subtree = dst->parent->subtree;
+ else if (IS_PDOTDOT(src))
+ src->subtree = dst->parent->parent->subtree;
+ else if (src->subtree) {
+ t_ft *cur;
+
+ for (cur = src->subtree->next; !IS(cur->status, BASE); cur = cur->next) {
+ if (IS_PDOTDOT(cur))
+ cur->subtree = dst->parent->subtree;
+ }
+ }
+ src->parent = dst->parent;
+
+ /* change destination current location */
+ dst = src;
+ }
+ src = next;
+ }
+}
+
+/* cette fonction permet de déplacer le contenu de deux arbres dans un troisième
+ */
+void ft_diff_move(t_ft *src, t_ft *dst, int opt) {
+ t_ft *next;
+ t_file_diff *new = NULL;
+
+ if (!src || !dst || !src->subtree) return;
+
+ if (!dst->subtree) dst->subtree = NEWDIR(dst);
+
+ src = src->subtree->next;
+ dst = dst->subtree->next;
+
+ while (!IS(src->status, BASE)) {
+ /* backup next position */
+ next = src->next;
+
+ if (IS(src->status, FILLED) || src->subtree) {
+ /* should find or create a new element */
+ dst = ft_add(dst, src->filename, NULL, NULL);
+ if (src->filename == dst->filename) src->filename = NULL;
+ }
+
+ if (IS(src->status, FILLED) && src->desc) {
+ /* need to move description */
+ if (!(new = dst->desc)) {
+ dst->desc = new = MALLOC(sizeof(*new));
+ bzero(new, sizeof(*new));
+ new->diff = 0xFFFF;
+ }
+ if (opt == ONLY_SRC1) new->src1 = src->desc;
+ if (opt == ONLY_SRC2) new->src2 = src->desc;
+ src->desc = NULL;
+ SET(dst->status, FILLED);
+ SET_PARENT(dst, CHANGED);
+ UNSET(src->status, FILLED);
+ }
+
+ /* need to run into */
+ if (src->subtree) {
+ if (IS_PDOT(src))
+ dst->subtree = dst->parent->subtree;
+ else if (IS_PDOTDOT(src))
+ dst->subtree = dst->parent->parent->subtree;
+ else
+ ft_diff_move(src, dst, opt);
+ }
+
+ ft_del(src, NULL, NULL);
+
+ src = next;
+ }
+}
+
+/* cette fonction permet d'initialiser la structure donnée en paramêtre
+ */
+void ft_init(t_ft *d) {
+ bzero(d, sizeof(*d));
+ d->prev = d->next = d;
+ d->parent = d;
+ SET(d->status, BASE);
+}
+
+t_file_diff *fct_free_diff_desc(void *data, t_file_diff *desc) {
+ if (desc->src1) fct_free_file_desc(data, desc->src1);
+ if (desc->src2) fct_free_file_desc(data, desc->src2);
+ free(desc);
+ return (NULL);
+}
+
+char *build_diff_line(char *path, char *filename, t_file_diff *info) {
+ static char tmp[BUFFER_LENGTH];
+ static char opath[BUFFER_LENGTH];
+ char *s = tmp;
+ char *ppath;
+
+ *s = 0;
+ if (info->diff == 0) {
+ ppath = opath;
+ if (Output_Str) ppath += sprintf(ppath, "%s/", Output_Str);
+ if (Rewrite_Src1) ppath += sprintf(ppath, "%s/", Rewrite_Src1);
+ sprintf(ppath, "%s", path);
+ s += sprintf(s, "= %s", build_line(opath, filename, info->src1));
+ return (tmp);
+ }
+
+ if (info->src1 && IS(Options, SHOW_OLD)) {
+ ppath = opath;
+ if (Output_Str) ppath += sprintf(ppath, "%s/", Output_Str);
+ if (Rewrite_Src1) ppath += sprintf(ppath, "%s/", Rewrite_Src1);
+ sprintf(ppath, "%s", path);
+
+ if (!info->src2)
+ s += sprintf(s, "- %s", build_line(opath, filename, info->src1));
+ else
+ s += sprintf(s, IS(Options, SHOW_NEW)?"< %s\n":"< %s",
+ build_line(opath, filename, info->src1));
+ }
+ if (info->src2 && IS(Options, SHOW_NEW)) {
+ ppath = opath;
+ if (Output_Str) ppath += sprintf(ppath, "%s/", Output_Str);
+ if (Rewrite_Src2) ppath += sprintf(ppath, "%s/", Rewrite_Src2);
+ sprintf(ppath, "%s", path);
+
+ if (!info->src1)
+ s += sprintf(s, "+ %s", build_line(opath, filename, info->src2));
+ else
+ s += sprintf(s, "> %s", build_line(opath, filename, info->src2));
+ }
+ if (*tmp) return (tmp);
+ return (NULL);
+}
+
+int output_diff_write(t_file_status *desc, t_ft *tree, int number) {
+ return (output_file_write_(desc, tree, number, build_diff_line));
+}
+
+/* traduct a string options descriptions to flags
+ */
+int output_diff_fcntl(t_file_status *env, int cmd) {
+ return (0);
+}
+
+
+
+/* cette fonction se base sur les différents paramêtres pour
+ * déterminer les différences entre les signatures de deux types de sources.
+ * Aux types de sources sont associées des fonctions spécialisées. Cette
+ * définition est valable de la même manière pour la destination
+ */
+int flxcheck_main(int argc, char **argv) {
+ /* tree for each source */
+ t_ft src1 = { &src1, &src1, &src1, NULL, NULL, NULL, BASE };
+ t_ft src2 = { &src2, &src2, &src2, NULL, NULL, NULL, BASE };
+ /* tree for destination */
+ t_ft dst = { &dst, &dst, &dst, NULL, NULL, NULL, BASE|CHANGED };
+ t_ft tmp1, tmp2; /* les bases temporaires */
+ int nb1 = 0, nb2 = 0;
+
+ /* il faut initialiser les structures de manière à définir les
+ * fonctions associées aux sources */
+ /* on initialise un premier type de source à partir d'un premier pointeur
+ * sur arbre et vice-versa
+ */
+ if (!InputSrc1 || !InputSrc2) {
+ arg_usage(flxcheck_poptions, "{source1 source2 | source1 [...] , source2 [...]}");
+ }
+
+ if (!Output) Output = output_alloc();
+ output_add(Output, "stdout:", OutputTypes);
+
+ /* il faut initialiser les bases temporaires à partir des bases originales */
+ ft_init(&tmp1);
+ ft_init(&tmp2);
+
+ while (!input_eof(InputSrc1) || !input_eof(InputSrc2)) {
+ /* la comparaison s'effectue sur les deux sources simultanément */
+
+ /* on lit des données dans chacune des entrées vers un tampon */
+ nb1 += input_read(InputSrc1, &src1);
+ nb2 += input_read(InputSrc2, &src2);
+
+ /* on compare les données deux à deux afin de compléter 'dst' */
+ ft_find_diff(&src1, &src2, &dst);
+ ft_find_diff(&src1, &tmp2, &dst);
+ ft_find_diff(&src2, &tmp1, &dst);
+
+ /* toutes les données identiques ont été détectée pour la partie
+ * déterminée, on déplace le contenu de la source vers les tampons */
+ ft_move(&src1, &tmp1);
+ ft_move(&src2, &tmp2);
+
+
+ /* visualiser les différences si possible */
+ // ft_diff_move(&tmp1, &dst, ONLY_SRC1);
+ // ft_diff_move(&tmp2, &dst, ONLY_SRC2);
+ // output_write(output, &dst);
+ // ft_free(&dst, (void*)fct_free_diff_desc, NULL);
+
+ /* les sources sont vidées, il est possible de recommencer l'opération */
+ }
+
+
+ /* il n'y a plus de différences détectables
+ * le reste sont des différences uniques */
+ ft_diff_move(&tmp1, &dst, ONLY_SRC1);
+ ft_diff_move(&tmp2, &dst, ONLY_SRC2);
+
+ /* visualiser les différences */
+ output_write(Output, &dst, 0);
+ ft_free(&dst, (void*)fct_free_diff_desc, NULL);
+
+ /* close all interface */
+ input_free(InputSrc1);
+ input_free(InputSrc2);
+ output_free(Output);
+
+ return (0);
+}
+
+
+
+int flxcheck_pfct(int opt, t_param *param, char **flag, char **argv) {
+ static int status = 1; /* source 1 or source 2 */
+
+ if (opt == O_HELP) arg_usage(flxcheck_poptions, NULL);
+ else if (opt == O_SH_ALL) SET(Options, SHOW_SAME|SHOW_OLD|SHOW_NEW);
+ else if (opt == O_SH_OLD) UNSET(Options, SHOW_SAME|SHOW_NEW);
+ else if (opt == O_SH_NEW) UNSET(Options, SHOW_SAME|SHOW_OLD);
+ else if (opt == O_IGN_MODE) UNSET(Diff, DIFF_MODE);
+ else if (opt == O_IGN_OWNER) UNSET(Diff, DIFF_OWNER);
+ else if (opt == O_IGN_SUM) UNSET(Diff, DIFF_CHECKSUM);
+ else if (opt == O_IGN_SIZE) UNSET(Diff, DIFF_SIZE);
+ else if (opt == O_IGN_DATE) UNSET(Diff, DIFF_TIME);
+ else if (opt == O_IGN_LINK) UNSET(Diff, DIFF_LINK);
+ else if (opt == O_IGN_LDATE) UNSET(Diff, DIFF_LDATE);
+ else if (opt == O_SH_HR) SET(Options, GOPT_HUMAN_READABLE);
+ else if (opt == O_REWRITE_SRC1) Rewrite_Src1 = strdup(*(argv+1));
+ else if (opt == O_REWRITE_SRC2) Rewrite_Src2 = strdup(*(argv+1));
+ else if (opt == O_OUTPUT) Output_Str = strdup(*(argv+1));
+ else if (opt == O_IGN_DOT) SET(Options, GOPT_IGNORE_DOT);
+ else if (opt == -1) {
+ if (!strcmp(*argv, ",")) status = 3;
+ else if (status == 1 || status == 2) {
+ /* add new source to source 1 */
+ if (!InputSrc1) InputSrc1 = input_alloc();
+ input_add(InputSrc1, *argv, InputTypes);
+
+ if (status == 1) { /* search alone ',' in others parameters */
+ char **ptr = argv;
+ while (*ptr && strcmp(*ptr, ",")) ptr++;
+ if (*ptr) status = 2;
+ else status = 3;
+ }
+ }
+ else { /* status == 3 */
+ /* add new source to source 2 */
+ if (!InputSrc2) InputSrc2 = input_alloc();
+ input_add(InputSrc2, *argv, InputTypes);
+ }
+ }
+ else return (-1);
+ return (param ? param->minarg : 0);
+}
+
+
diff --git a/flx/check.h b/flx/check.h
new file mode 100644
index 0000000..824baa4
--- /dev/null
+++ b/flx/check.h
@@ -0,0 +1,27 @@
+
+
+#ifndef __CHECK_H__
+#define __CHECK_H__
+
+#include "arg.h"
+
+/* structure de définition des données */
+
+typedef struct s_file_diff t_file_diff;
+
+struct s_file_diff {
+#define ONLY_SRC1 (1<<0)
+#define ONLY_SRC2 (1<<1)
+ unsigned int diff;
+ t_file_desc *src1;
+ t_file_desc *src2;
+};
+
+extern t_param flxcheck_poptions[];
+
+extern int flxcheck_pfct(int opt, t_param *param, char **flag, char **argv) ;
+extern int flxcheck_main(int argc, char **argv);
+
+
+#endif /* __CHECK_H__ */
+
diff --git a/flx/ctrl1 b/flx/ctrl1
new file mode 100644
index 0000000..1ba1adc
--- /dev/null
+++ b/flx/ctrl1
@@ -0,0 +1,32 @@
+tree 2
+d 0775 101 100 0 -------------------------------- 1019951182 .
+- 0664 101 100 40 5856c38f855ff346556a884676d71eb5 1019727474 ./AUTHORS
+l 0777 101 100 7 ca5f65a859f411ec70ddb3fddf267e80 1019942943 ./COPYING LICENCE
+- 0664 101 100 159 37c927c58acc678bfdfb51b50a60e19d 1019727474 ./ChangeLog
+- 0664 101 100 17992 94d55d512a9ba36caa9b7df079bae19f 1019727474 ./LICENCE
+- 0664 101 100 1133 e97320bbb334c26b55847bcd7c34c121 1019922011 ./Makefile
+- 0644 101 100 384 b4f698ee014cce9486bac07630395e91 1019727474 ./README
+- 0664 101 100 258 d0dc455418e3b3f562ea8f139f5a00c2 1019727474 ./TODO
+- 0664 101 100 0 d41d8cd98f00b204e9800998ecf8427e 1019951182 ./ctrl1
+- 0664 101 100 2434 28331c83cf1ac810f1ae3256d7dc8b88 1019917001 ./d1
+- 0664 101 100 2434 8589114d104a245dd5f1f16446c15be2 1019916677 ./d2
+- 0664 101 100 2434 8589114d104a245dd5f1f16446c15be2 1019932107 ./d3
+- 0664 101 100 22657 84fe38c0bfa5266f2fe37b1c0fd3f04b 1019940625 ./d4
+- 0664 101 100 44077 527102cbfd20e79b2d01e0791fe492db 1019773438 ./data2
+- 0664 101 100 9787 848053ba4efe835cf867e8cf1e23e884 1019950725 ./fct1.c
+- 0664 101 100 9720 aadaa9de7ecde22797b1866767abbbd2 1019926775 ./fct1.c.old
+- 0664 101 100 43368 c5e7333c861253d48783d6d32af871c8 1019950734 ./fct1.o
+- 0664 101 100 13734 e95afefb5ef8e23fb882a429b988987e 1019951170 ./main.c
+- 0664 101 100 39556 9555b903c4a19a4243560ae72d5a60ca 1019951173 ./main.o
+- 0664 101 100 8300 fffb933546ded2c82cfb8d2b5a4c56ba 1019909340 ./md5.c
+- 0664 101 100 1601 264cb0e1385a7de7db84ac6e1759b3a1 1019909340 ./md5.h
+- 0664 101 100 8644 c5b1d60554ed6487ad51a4b79a60ef1c 1019947821 ./md5.o
+- 0664 101 100 1640 6ba8ecd30a1cbf40e1d78105750ad7af 1019744794 ./others.c
+- 0664 101 100 408 01180f24bb6ed21e8e30f344568d951e 1019931342 ./others.h
+- 0664 101 100 16144 5c083c055d49cb9f6e02fa6a2d30f0c8 1019947821 ./others.o
+- 0775 101 100 88587 71b4bbbe182439257e76e1600d5b4d32 1019951173 ./signfs
+- 0664 101 100 1779 a389f15ffe9107391dce888ce45e5a2f 1019949146 ./signfs.h
+- 0664 101 100 2621 bc7c62166347e6472a56d6f7d0b2f90f 1019755351 ./structure.c
+- 0664 101 100 1367 b4eb2ced67aa56e76634520e38c9181a 1019753532 ./structure.h
+- 0664 101 100 1124 e1009a1b9fa8f928457fbe41f82d3e73 1019754370 ./structure.o
+d 0775 101 100 0 -------------------------------- 1019903881 ./test
diff --git a/flx/fct1.c b/flx/fct1.c
new file mode 100644
index 0000000..79378a3
--- /dev/null
+++ b/flx/fct1.c
@@ -0,0 +1,452 @@
+/*
+ * Signfs version 0.6, Copyright Benoit DOLEZ, 2002
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+
+#include "flx.h"
+#include "utils.h"
+
+
+/* function that complete desc from file system informations */
+t_file_desc *complete_info_from_file(char *path, t_file_desc *desc, int flag) {
+ struct stat stat;
+
+ /* try to stat it */
+ if (lstat(path, &stat)) {
+ PFERROR("stat(%s)", path);
+ return (0);
+ }
+ if (!desc) {
+ /* have to create it */
+ desc = MALLOC(sizeof(*desc));
+ bzero(desc, sizeof(*desc));
+ }
+ /* copy stat informations */
+ memcpy(&desc->stat, &stat, sizeof(stat));
+
+ if (S_ISREG(stat.st_mode) && !desc->md5) /* get md5 checksum */
+ desc->md5 = checksum_md5_from_file(path);
+ else if (S_ISLNK(stat.st_mode) && !desc->link) {
+ /* get link and md5 associed */
+ char temp[BUFFER_LENGTH];
+ int l;
+
+ if ((l = readlink(path, temp, BUFFER_LENGTH)) < 0) {
+ PFERROR("readlink(%s)", path);
+ } else {
+ temp[l] = 0;
+ desc->link = strdup(temp);
+ desc->md5 = checksum_md5_from_data(temp, l);
+ }
+ }
+ return (desc);
+}
+
+
+
+/* function that compare 2 tree entry, complete checksum and link if needed */
+int files_are_the_same(t_file_desc *f1, t_file_desc *f2, int Diff, char *path) {
+ int diff = 0;
+
+ // if (!IS(f1->status, STATUS_FILLED) || !IS(f2->status, STATUS_FILLED))
+ // return (diff = DIFF_NOTFILLED, 0);
+
+ if (DIFF(TYPE) && (f1->stat.st_mode & S_IFMT) != (f2->stat.st_mode & S_IFMT))
+ diff |= DIFF_TYPE; /* types differ */
+ if (DIFF(MODE) && (f1->stat.st_mode & 07777) != (f2->stat.st_mode & 07777))
+ diff |= DIFF_MODE; /* modes differ */
+ if (DIFF(OWNER) && (f1->stat.st_uid != f2->stat.st_uid ||
+ f1->stat.st_gid != f2->stat.st_gid))
+ diff |= DIFF_OWNER; /* uid or gid differ */
+ if (DIFF(SIZE) && S_ISREG(f1->stat.st_mode) && S_ISREG(f2->stat.st_mode) &&
+ f1->stat.st_size != f2->stat.st_size)
+ diff |= DIFF_SIZE; /* sizes differ for regular files */
+ if (DIFF(DEV) && ((S_ISBLK(f1->stat.st_mode) && S_ISBLK(f2->stat.st_mode)) ||
+ (S_ISCHR(f1->stat.st_mode) && S_ISCHR(f2->stat.st_mode))) &&
+ f1->stat.st_rdev != f2->stat.st_rdev)
+ diff |= DIFF_DEV; /* minor/major differ for device files */
+ if (DIFF(TIME) && f1->stat.st_mtime != f2->stat.st_mtime) {
+ if (DIFF(LDATE) || !(S_ISLNK(f1->stat.st_mode)))
+ diff |= DIFF_TIME; /* modification times diff */
+ }
+ if (DIFF(LINK) && S_ISLNK(f1->stat.st_mode) && S_ISLNK(f2->stat.st_mode)) {
+ char temp[BUFFER_LENGTH];
+ int l;
+
+ if (f1->link != f2->link) {
+ if (!f1->link || !f2->link) {
+ if (!path) diff |= DIFF_LINK;
+ else {
+ /* rebuild link and link's checksum */
+ if ((l = readlink(path, temp, BUFFER_LENGTH)) < 0) {
+ PFERROR("readlink(%s)",path);
+ } else {
+ temp[l] = 0;
+ if (!f1->link) f1->link = strdup(temp);
+ if (!f2->link) f2->link = strdup(temp);
+ if (!f1->md5) f1->md5 = checksum_md5_from_data(temp, l);
+ if (!f2->md5) f2->md5 = checksum_md5_from_data(temp, l);
+ }
+ }
+ if (strcmp(f1->link, f2->link))
+ diff |= DIFF_LINK; /* links differ */
+ }
+ }
+ }
+ if (DIFF(CHECKSUM) && S_ISREG(f1->stat.st_mode) && S_ISREG(f2->stat.st_mode)) {
+ if (f1->md5 || f2->md5) {
+ if (!f1->md5 || !f2->md5) diff |= DIFF_CHECKSUM;
+ else if (memcmp(f1->md5, f2->md5, 16))
+ diff |= DIFF_CHECKSUM; /* checksums differ */
+ }
+ }
+ return (diff);
+}
+
+/* return the path describe by the structure */
+char *build_path(t_ft *tree) {
+ static char path[BUFFER_LENGTH];
+
+ if (!tree || !tree->filename)
+ path[0] = 0;
+ else if (tree->parent &&
+ (IS_PDOTF(tree) || !tree->parent->filename))
+ strcpy(path, tree->filename);
+ else {
+ build_path(tree->parent);
+ strcat(path, "/");
+ strcat(path, tree->filename);
+ }
+ return (path);
+}
+
+
+/* free memory for an existant tree
+ * tree : tree to clean
+ */
+void free_tree(t_tree *tree) {
+ t_tree *current, *todel;
+
+ if (tree->link) FREE(tree->link);
+ if (tree->checksum) FREE(tree->checksum);
+ if (tree->filename) FREE(tree->filename);
+ if ((current = tree->subtree)) {
+ while (current != tree) {
+ todel = current;
+ current = current->next;
+ todel->prev->next = todel->next;
+ todel->next->prev = todel->prev;
+ free_tree(todel);
+ }
+ }
+ if (tree->subtree) FREE(tree->subtree);
+ FREE(tree);
+}
+
+/* browse only directories */
+/* path : directory to treat
+ * fct : fonction that treat file and return a (new) pointer to data to recursive act
+ * data : pointer for function fct
+ */
+int browse_over_path(char *path, PROTO_FS(*fct), void *data) {
+ struct stat stat;
+ DIR *dir;
+ struct dirent *dirent;
+ off_t current_dir;
+ char *new_filename;
+ int l;
+
+ if (!path) return (0);
+
+ /* initialise new_filename */
+ new_filename = MALLOC((l = strlen(path)) + 1 + FILENAME_LENGTH);
+ memcpy(new_filename, path, l);
+ if (new_filename[l-1] != '/') strcpy(new_filename + l++, "/");
+
+ if ((dir = opendir(path))) {
+ /* each file of the directory */
+ while ((dirent = readdir(dir))) {
+ /* build new filename */
+ strcpy(new_filename + l, dirent->d_name);
+
+ /* get file informations */
+ if (lstat(new_filename, &stat)) {
+ PFERROR("stat(%s)", new_filename);
+ continue;
+ }
+
+ /* directory selection */
+ if (S_ISDIR(stat.st_mode)) {
+ void *new_data;
+ /* save current directory position */
+ current_dir = telldir(dir);
+ closedir(dir);
+
+ /* fonction on file status */
+ if ((new_data = fct(new_filename, new_filename+l, &stat, data))) {
+
+ browse_over_path(new_filename, fct, new_data);
+
+ /* if new pointer return, differs with old one, we should
+ * remove it before use (same, with filename NULL) */
+ if (new_data != data) fct(NULL, NULL, NULL, new_data);
+ }
+ /* restore directory position */
+ dir = opendir(path);
+ seekdir(dir, current_dir);
+ }
+ else {
+ /* fonction on file status */
+ fct(new_filename, new_filename+l, &stat, data);
+ }
+ }
+ closedir(dir);
+ }
+ else {
+ PFERROR("opendir(%s)", path);
+ return (0);
+ }
+ FREE(new_filename);
+ return (1);
+}
+
+
+/* build an MD5 checksum from data in file */
+char *checksum_md5_from_file(char *file) {
+ int fd;
+ size_t size;
+ char *checksum_md5 = 0, blk[BUFFER_LENGTH];
+ MD5_CTX md5_ctx;
+
+ if ((fd = open(file, O_RDONLY)) < 0 ) {
+ PFERROR("open(%s) for MD5 checksum", file);
+ }
+ else {
+ MD5_Init(&md5_ctx);
+ while ((size = read(fd, blk, BUFFER_LENGTH)) > 0)
+ MD5_Update(&md5_ctx, blk, size);
+ close(fd);
+ checksum_md5 = MALLOC(16);
+ MD5_Final(checksum_md5, &md5_ctx);
+ }
+ return (checksum_md5);
+}
+
+/* build an MD5 checksum from a string */
+char *checksum_md5_from_data(char *data, int len) {
+ char *checksum_md5 = 0;
+ MD5_CTX md5_ctx;
+
+ MD5_Init(&md5_ctx);
+ MD5_Update(&md5_ctx, data, len);
+ checksum_md5 = MALLOC(16);
+ MD5_Final(checksum_md5, &md5_ctx);
+ return (checksum_md5);
+}
+
+
+/* remove ended '/' */
+char *remove_ended_slash(char *str) {
+ static char temp[BUFFER_LENGTH];
+ int l = strlen(str);
+
+ strcpy(temp, str);
+ while (temp[l - 1] == '/') temp[--l] = 0;
+ return (temp);
+}
+
+/* return pointer to the end of the current field */
+char *end_field(char *line) {
+ while (*line && *line != ' ' && *line != '\t' && *line != '\n') {
+ if (*line++ == '\\' && (*line == '\\' ||
+ *line == ' ' ||
+ *line == '\t'||
+ *line == '\n'))
+ line++;
+ }
+ if (*line) *line++ = 0;
+ return (*line ? line : 0);
+}
+
+
+/* create directory and parent directory if needed */
+int mkdir_with_parent(char *pathname, mode_t mode) {
+ struct stat st;
+ char tmp[BUFFER_LENGTH], *ptmp = tmp;
+
+ if (*pathname == '/') *ptmp++ = *pathname++;
+ while (pathname && *pathname) {
+ while (*pathname && *pathname != '/') *ptmp++ = *pathname++;
+ while (*pathname == '/') pathname++;
+ *ptmp = 0;
+ if (stat(tmp, &st)) {
+ /* file cannot be stat, try to make directory */
+ if (mkdir(tmp, mode)) {
+ PFERROR("mkdir(%s)", tmp);
+ return (0);
+ }
+ }
+ else if (!S_ISDIR(st.st_mode)) {
+ error("%s exist and isn't a directory", tmp);
+ return (0);
+ }
+ *ptmp++ = '/';
+ }
+ return (1);
+}
+
+/* return formatted info into a static string */
+char *build_line(char *path, char *filename, t_file_desc *info) {
+ struct stat *st = &(info->stat);
+ static char blk[BUFFER_LENGTH], tmp[64];
+ int s;
+
+ /* show informations */
+ blk[s = 0] = 0;
+
+ /* bad data */
+ if (!path) {
+ sprintf(blk,"## anormal action : path=%s desc=%p", path, st);
+ return (blk);
+ }
+
+ if (st) {
+ /* display file type */
+ s += sprintf(blk+s, "%c", FILE_TYPE(st->st_mode));
+
+ /* display file mode */
+ if (IS(Options, GOPT_HUMAN_READABLE))
+ s += sprintf(blk+s," %04o(%s) ", st->st_mode & 0007777,
+ right(st->st_mode));
+ else
+ s += sprintf(blk+s," %04o ", st->st_mode & 0007777);
+
+ /* display user and group id */
+ s += sprintf(blk+s,"%5d %5d ", st->st_uid, st->st_gid);
+
+ /* display size of device info */
+ if (S_ISBLK(st->st_mode) || S_ISCHR(st->st_mode)) {
+ sprintf(tmp, "%d,%d", major(st->st_rdev), minor(st->st_rdev));
+ s += sprintf(blk+s, "%10s ", tmp);
+ } else {
+ s += sprintf(blk+s, "%10ld ", S_ISDIR(st->st_mode) ? 0 : st->st_size );
+ }
+
+ /* display checksum */
+ if (info->md5) {
+ int i;
+ for (i=0; i < 16; i++) s += sprintf(blk+s, "%02x", info->md5[i]);
+ s += sprintf(blk+s, " ");
+ }
+ else
+ s += sprintf(blk+s, "-------------------------------- ");
+
+ /* display date */
+ if (IS(Options, GOPT_HUMAN_READABLE)) {
+ strcpy(tmp, ctime(&(st->st_mtime))); tmp[strlen(tmp) - 1] = 0;
+ s += sprintf(blk+s, "%10ld(%s) ", st->st_mtime, tmp);
+ }
+ else
+ s += sprintf(blk+s, "%10ld ", st->st_mtime);
+
+ s += sprintf(blk+s, "%s", backslashed_str(path, " \\\n()\t"));
+
+ if (S_ISLNK(st->st_mode) && info->link)
+ s += sprintf(blk+s, " %s", backslashed_str(info->link, " \\\n()\t"));
+ }
+ else {
+ if (IS(Options, GOPT_HUMAN_READABLE))
+ s += sprintf(blk+s, "? 0000(-) % 5d % 5d % 10d -------------------------------- %10d(-) %s",0 , 0, 0, 0,
+ backslashed_str(path, " \\\n()\t"));
+ else
+ s += sprintf(blk+s, "? 0000 % 5d % 5d % 10d -------------------------------- %10d %s",0 , 0, 0, 0,
+ backslashed_str(path, " \\\n()\t"));
+ }
+ return (blk);
+}
+
+
+/* view files with recursive method */
+void dump_tree_(t_ft *tree, int force) {
+ static char path[BUFFER_LENGTH];
+ char *ppath;
+
+ ppath = path + strlen(path);
+ while (1) {
+ if (tree->filename) {
+ ADD_PATH(path, ppath, tree->filename);
+ printf("[%02x] %s\n", tree->status, path);
+ // UNSET(tree->status, CHANGED);
+ }
+ if (tree->subtree && (!IS_PDOTF(tree) || force)) {
+ dump_tree_(tree->subtree, 0);
+ }
+ tree = tree->next;
+ if (IS(tree->status, BASE)) break;
+ }
+ *ppath = 0;
+}
+
+void dump_tree(t_ft *tree) {
+ printf("** etat de l'arbre **\n");
+ dump_tree_(tree, 1);
+ printf("** end **\n");
+}
+
+
+/* find last good defined path (without ended '/') */
+char *define_base_path(char *real) {
+ static char tmp[BUFFER_LENGTH];
+ char *last, *breal, *lslash;
+
+ lslash = last = tmp;
+ while (*real) {
+ /* pass multiple '/' */
+ while (*real == '/') real++;
+ if (!*real) break; /* end of pathname */
+ breal = real;
+ /* get directory name */
+ while (*real && *real != '/') *last++ = *real++;
+ /* last have no ended '/' */
+ lslash = last;
+ /* find . or .., restart */
+ if (IS_DOTF(breal) || IS_DOTD(breal)) lslash = last = tmp;
+ else *last++ = *real;
+ }
+ /* remove last slash */
+ *lslash = 0;
+ return (tmp);
+}
+
+/* remove multiple '/' (and ended '/') */
+char *define_cleaned_path(char *real) {
+ static char tmp[BUFFER_LENGTH];
+ char *ptmp = tmp;
+
+ while (*real) {
+ while ((*ptmp = *real)) {
+ ptmp++;
+ if (*real++ == '/') break;
+ }
+ while (*real == '/') real++;
+ }
+ *ptmp = *real;
+ /* do not remove ending '/' */
+#if 1
+ if (ptmp-1 > tmp && *(ptmp-1) == '/') *(ptmp-1) = 0;
+#endif
+ return (tmp);
+}
+
+
+
diff --git a/flx/flx.c b/flx/flx.c
new file mode 100644
index 0000000..8aed3ab
--- /dev/null
+++ b/flx/flx.c
@@ -0,0 +1,115 @@
+#include <string.h>
+#include "utils.h"
+#include "flx.h"
+
+
+/* cette fonction ajoute et place un chainon dans la chaine t_file_tree (brother)
+ * le pointeur pfilename est le pointeur à utiliser pour le nom, attention
+ * aux allocations (il n'est pas logique qu'il contienne un '/'
+ * elle retourne un pointeur sur le nouveau chainon
+ */
+t_ft *ft_add(t_ft *base, char *pfilename, void *(*fct_init_desc)(), void *data) {
+ t_ft *new;
+ int ret = 1;
+
+ /* base initialisation */
+ if (!pfilename || !base) {
+ new = POOL_ALLOC(t_file_tree);
+ new->prev = new->next = new;
+ /* be the root dir */
+ new->parent = (!base) ? new : base;
+ new->filename = NULL;
+ new->desc = fct_init_desc ? fct_init_desc(data) : NULL;
+ new->subtree = NULL;
+ new->status = BASE;
+ return (new);
+ }
+ /* possibly pass first element */
+ if (!base->filename) base = base->next;
+ /* find best place */
+ while (base->filename && (ret = strcmp(pfilename, base->filename)) > 0)
+ base = base->next;
+ /* already exist */
+ if (ret == 0) return (base);
+
+ /* create new element and fill it */
+ new = POOL_ALLOC(t_file_tree);
+ /* data */
+ new->status = 0;
+ new->desc = NULL;
+ new->filename = pfilename;
+
+ /* description pointer initialization */
+ new->desc = fct_init_desc ? fct_init_desc(data) : NULL;
+
+ /* parent is the same for each soon, or be root dir */
+ new->parent = (!base->parent) ? new : base->parent;
+
+ /* special traitment for '.' and '..' */
+ new->subtree = NULL;
+ if (base && base->parent && IS_DOT(pfilename))
+ new->subtree = base->parent->subtree;
+ if (base && base->parent && base->parent->parent && IS_DOTDOT(pfilename))
+ new->subtree = base->parent->parent->subtree;
+
+ /* place at the before current base */
+ LIST_CHAIN(base->prev, new, base);
+ return (new);
+}
+
+/* cette fonction supprime un chainon dans une chaine t_file_tree
+ * elle retourne le pointeur sur le chainon précédent
+ */
+t_ft *ft_del(t_ft *old, void (*fct_free_desc)(void *data, void *desc), void *data) {
+ t_ft *prev;
+
+ prev = LIST_UNCHAIN(old);
+ if (old->filename) FREE(old->filename);
+ if (old->desc) {
+ if (fct_free_desc) fct_free_desc(data, old->desc);
+ // else warning("Possibly unfree memory");
+ }
+ if (old->subtree && !IS_PDOTF(old)) {
+ t_ft *c;
+ for (c = old->subtree->next; c != old->subtree; c = c->next)
+ c = ft_del(c, fct_free_desc, data);
+ POOL_FREE(t_file_tree, old->subtree);
+ }
+ POOL_FREE(t_file_tree, old);
+ return (prev);
+}
+
+/* return (and build) tree structure for matching path */
+/* path : directory to search (and create)
+ * tree : current directories structure
+ * (return) : pointer to a new base tree
+ */
+t_ft *ft_get(t_ft *tree, char *path) {
+ char tfilename[BUFFER_LENGTH];
+ char *beginpath;
+ int len;
+
+ /* no more subtree, break to current */
+ while (path && *path) {
+ /* the first level path filename */
+ beginpath = path;
+ if ((path = strchr(beginpath, '/'))) path++;
+ len = (path ? (path - beginpath - 1) : strlen(beginpath));
+
+ /* put filename in buffer */
+ strncpy(tfilename, beginpath, len); tfilename[len] = 0;
+
+ /* want subdir but don't exist, should create */
+ if (!tree->subtree) tree->subtree = NEWDIR(tree);
+
+ /* get it in current directory */
+ tree = ft_add(tree->subtree, tfilename, NULL, NULL);
+
+ /* new entry, allocate memory for filename */
+ if (tree->filename == tfilename)
+ tree->filename = strdup(tree->filename);
+
+ }
+ return (tree);
+}
+
diff --git a/flx/flx.h b/flx/flx.h
new file mode 100644
index 0000000..1113d4a
--- /dev/null
+++ b/flx/flx.h
@@ -0,0 +1,264 @@
+#ifndef __FLX_H__
+#define __FLX_H__
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <netinet/in.h>
+
+#include "utils.h"
+#include "md5.h"
+
+#define DUMPBASENAME "formilux-sig.dat"
+
+#define MD5_Init(ctx) ToolsMD5Init(ctx)
+#define MD5_Update(ctx, data, len) ToolsMD5Update(ctx, data, len)
+#define MD5_Final(data, ctx) ToolsMD5Final(data, ctx)
+
+#define O4(a) (htonl(*(int*)(a)))
+
+#define MATCH(f,m) (!strcmp(f, m))
+
+#define STATUS_REQUEST_DIR 0x0001
+#define STATUS_FILLED 0x0002
+
+#define SINGLE_DEV 0x0001
+#define HAVE_TO_CHECK 0x0002
+#define SHOW_SAME 0x0004
+#define SHOW_NEW 0x0008
+#define SHOW_OLD 0x0010
+#define SHOW_ALL (SHOW_SAME|SHOW_NEW|SHOW_OLD)
+#define GOPT_HUMAN_READABLE 0x0020
+#define GOPT_IGNORE_DOT 0x0040
+#define GOPT_IGNORE_DEPTH 0x0080
+
+#define FILE_TYPE(a) (S_ISLNK(a) ?'l':S_ISDIR(a) ?'d': \
+ S_ISCHR(a) ?'c':S_ISBLK(a) ?'b': \
+ S_ISFIFO(a)?'f':S_ISSOCK(a)?'s': \
+ S_ISREG(a) ?'-':'?')
+
+
+#define F_TYPE 0x0001
+#define F_MODE 0x0002
+#define F_OWNER 0x0004
+#define F_SIZE 0x0008
+#define F_DEV 0x0010
+#define F_CHECKSUM 0x0020
+#define F_LINK 0x0040
+#define F_TIME 0x0080
+#define F_LDATE 0x0100
+
+#define DIFF_TYPE F_TYPE
+#define DIFF_MODE F_MODE
+#define DIFF_OWNER F_OWNER
+#define DIFF_SIZE F_SIZE
+#define DIFF_DEV F_DEV
+#define DIFF_CHECKSUM F_CHECKSUM
+#define DIFF_LINK F_LINK
+#define DIFF_TIME F_TIME
+#define DIFF_LDATE F_LDATE
+#define DIFF_NOTFILLED 0x8000
+
+#define DELIM_BASE ':'
+#define DELIM_CHANGE '='
+#define DELIM_NEXT ','
+#define DELIM_LIST (char[]){ DELIM_BASE, DELIM_CHANGE, DELIM_NEXT, 0 }
+
+#define DIFF(a) (IS(Diff, DIFF_##a))
+// #define DIFF(a) (Diif)
+
+
+
+#define IS_DOTDOT(str) (*(str) == '.' && *((str)+1) == '.' && *((str)+2) == 0)
+#define IS_DOT(str) (*(str) == '.' && *((str)+1) == 0)
+#define IS_DOTF(str) (*(str) == '.' && \
+ (*((str)+1) == 0 || \
+ (*((str)+1) == '.' && *((str)+2) == 0)))
+
+#define IS_DOTD(str) (*(str) == '.' && \
+ (*((str)+1) == '/' || \
+ (*((str)+1) == '.' && *((str)+2) == '/')))
+
+
+
+#define IS_PDOT(ptr) ((ptr)->parent && \
+ (ptr)->subtree == (ptr)->parent->subtree)
+#define IS_PDOTDOT(ptr) ((ptr)->parent && (ptr)->parent->parent && \
+ (ptr)->subtree == (ptr)->parent->parent->subtree)
+#define IS_PDOTF(ptr) (IS_PDOT(ptr) || IS_PDOTDOT(ptr))
+
+
+#define ADD_PATH_DEFINE(pbegin, pend, filename) ({ \
+ char *__ret; \
+ if (filename) { \
+ *pend = 0; \
+ if (pend > pbegin && *(pend-1) != '/') strcpy(pend, "/") ; \
+ strncat((pend), (filename), BUFFER_LENGTH - ((pend) - (pbegin)) - 2); \
+ __ret = (pend) + strlen(pend); \
+ } else __ret = (pend) ; \
+ __ret; \
+})
+
+#define ADD_PATH(pbegin, pend, filename) add_path(pbegin, pend, filename)
+
+static inline char *add_path(char *pbegin, char *pend, char *filename) {
+ return (ADD_PATH_DEFINE(pbegin, pend, filename));
+}
+
+#define REMOVE_DIR_DEFINE(pbegin, pend) ({ \
+ char *__ret; \
+ if (!(pend = strrchr(pbegin, '/'))) __ret = (pbegin); \
+ else \
+ if (pend == pbegin) __ret = (pend+1); \
+ else __ret = (pend); \
+ __ret; \
+})
+
+#define REMOVE_DIR(pbegin, pend) remove_dir(pbegin, pend)
+
+static inline char *remove_dir(char *pbegin, char *pend) {
+ return (REMOVE_DIR_DEFINE(pbegin, pend));
+}
+
+#define COUNT_LEVEL1 100 /* number with all directory */
+#define COUNT_LEVEL2 100 /* maximum in a directory */
+#define NEWDIR(parent) ft_add(parent, NULL, NULL, NULL);
+
+/* structure definition for file tree */
+typedef struct s_file_tree t_file_tree ;
+typedef t_file_tree t_ft;
+
+
+struct s_file_tree {
+ t_file_tree *prev, *next; /* others file in same directory */
+ t_file_tree *parent; /* parent directory */
+ t_file_tree *subtree; /* pointer to sub directory */
+ char *filename; /* filename (without path) */
+ void *desc; /* pointer from specific data */
+
+
+
+#define FILLED 0x01
+#define CHANGED 0x02
+#define BASE 0x04
+#define WRITTEN 0x08
+#define SORTING 0x10
+#define SORTED 0x20
+#define READING 0x40
+ int status; /* status for file */
+};
+
+#define SET_MARK_CHANGED(ptr) set_parent(ptr, CHANGED)
+#define SET_PARENT(ptr, flag) set_parent(ptr, flag)
+
+static inline void set_parent(t_file_tree *cur, int flag) {
+ while (cur) {
+ if (IS(cur->status, flag)) break;
+ SET(cur->status, flag);
+ if (cur->parent == cur) break;
+ cur = cur->parent;
+ }
+}
+
+
+
+/* structure de définition des informations */
+
+typedef struct s_file_desc t_file_desc ;
+
+struct s_file_desc {
+ struct stat stat;
+ unsigned char *md5;
+ unsigned char *link;
+};
+
+#define FCT_DOIT3_PROTO(name) int (*name)(void *data, int order, \
+ t_file_tree *src1, \
+ t_file_tree *src2, \
+ t_file_tree *dst)
+
+
+typedef struct s_tree t_tree;
+
+struct s_tree {
+ t_tree *prev;
+ t_tree *next;
+ char *filename;
+ t_tree *subtree;
+ t_tree *parent;
+ u_int status;
+ struct stat stat;
+ u_char *checksum;
+ char *link;
+};
+
+typedef struct s_fctdata t_fctdata;
+
+struct s_fctdata {
+ void *(*fct)();
+ void *data;
+};
+
+
+typedef struct s_dtree t_dtree;
+
+struct s_dtree {
+ t_tree *tree1;
+ t_tree *tree2;
+};
+
+#define PROTO_FS(name) void *(name)(char *path, char *filename, struct stat *stat, void *data)
+#define PROTO_FILE(name) void *(name)(char *line, void *data)
+#define PROTO_SAVE(name) void *(name)(char *path, t_tree *new, void *data)
+
+
+extern int browse_over_path(char *path, void *(*fct)(), void *data) ;
+extern char *checksum_md5_from_file(char *file) ;
+extern char *checksum_md5_from_data(char *data, int len) ;
+extern char *end_field(char *line) ;
+extern int mkdir_with_parent(char *pathname, mode_t mode) ;
+extern char *build_line(char *path, char *filename, t_file_desc *info) ;
+extern void dump_tree(t_ft *tree) ;
+extern int dump_diff_tree(t_dtree *tree);
+extern int files_are_the_same(t_file_desc *f1, t_file_desc *f2, int Diff, char *path) ;
+extern char *build_path(t_ft *tree);
+extern t_tree *get_line(char *line) ;
+extern void free_tree(t_tree *tree);
+t_tree *get_from_signfs_line(char *line, char **rpath) ;
+char *remove_ended_slash(char *str) ;
+
+extern int browse_over_tree_from_path(char *path, void *(*add_fct)(), void *(*srch_fct)(), void *data) ;
+extern t_tree *build_new_tree_from_fs(char *path, char *filename, struct stat *stat, void *data) ;
+extern t_tree *build_check_tree_from_fs(char *path, char *filename, struct stat *stat, void *data) ;
+extern void *save_tree(char *path, t_tree *new, t_tree *tree) ;
+extern void *check_before_saving_tree(char *path, t_tree *new, t_dtree *dtree) ;
+extern void *build_new_tree_from_mfile(char *path, char *filename, struct stat *stat, void *tree) ;
+extern void build_new_tree_from_file(char *path, void *(*fct)(), void *tree) ;
+extern void *build_check_tree_from_mfile(char *path, char *filename, struct stat *stat, void *tree) ;
+
+extern t_ft *get_tree(char *path, t_ft *tree) ;
+extern t_ft *get_path(char *path, t_ft *tree) ;
+extern t_ft *get_parent_tree(char *path, t_ft *data) ;
+
+int signfs_read_file(char *path, t_tree *tree);
+int signfs_read_fs(char *path, t_tree *tree);
+int signfs_dump_tree(t_tree *tree, char *output, int level);
+
+
+extern t_ft *ft_add(t_ft *base, char *pfilename, void *(*fct_init_desc)(), void *data);
+extern t_ft *ft_del(t_ft *old, void (*fct_free_desc)(void *data, void *desc), void *data);
+extern t_ft *ft_get(t_ft *tree, char *path);
+
+extern char *define_base_path(char *path);
+extern char *define_cleaned_path(char *path);
+
+
+/* device for xdev option */
+extern dev_t SingleDev;
+extern char *DumpFilename;
+extern int RecursionLevel;
+extern int Diff;
+extern int Options, Sorted;
+
+POOL_INIT_PROTO(t_file_tree);
+
+#endif /* __FLX_H__ */
diff --git a/flx/flx_fcntl.h b/flx/flx_fcntl.h
new file mode 100644
index 0000000..f1b6f73
--- /dev/null
+++ b/flx/flx_fcntl.h
@@ -0,0 +1,14 @@
+#ifndef __FLX_FCNTL_H__
+#define __FLX_FCNTL_H__
+
+#define O_READ 0x0001
+#define O_WRITE 0x0002
+#define O_SORTED 0x0004
+
+
+#define INPUT_SORTED 0x0001
+#define OUTPUT_SORTED 0x0002
+
+#define IS_SORTED 0x0001
+
+#endif /* __FLX_FCNTL_H__ */
diff --git a/flx/flxcheck b/flx/flxcheck
new file mode 120000
index 0000000..6f04e9c
--- /dev/null
+++ b/flx/flxcheck
@@ -0,0 +1 @@
+flx \ No newline at end of file
diff --git a/flx/flxsign b/flx/flxsign
new file mode 120000
index 0000000..6f04e9c
--- /dev/null
+++ b/flx/flxsign
@@ -0,0 +1 @@
+flx \ No newline at end of file
diff --git a/flx/input.c b/flx/input.c
new file mode 100644
index 0000000..182fa83
--- /dev/null
+++ b/flx/input.c
@@ -0,0 +1,114 @@
+#include <string.h>
+#include "utils.h"
+#include "source_type.h"
+#include "input.h"
+#include "flx_fcntl.h"
+
+
+/* get data from current input and return the number of data readed
+ */
+int input_read(t_db_input *in, void *tree) {
+ t_device *current;
+ int nb = 0;
+
+ /* look for pointer initializing */
+ while (!in->eof && in->inputs) {
+ /* get current pointer to input driver */
+ current = SIMPLE_LIST_PTR(in->inputs);
+
+ /* run read function associated with current source */
+ if (current->opened->read) {
+ if (!(nb = current->opened->read(current->env, tree))) {
+ if (current->opened->close)
+ current->env = current->opened->close(current->env);
+ current->opened = NULL;
+ FREE(current);
+ SIMPLE_LIST_POP(in->inputs);
+ in->eof = (in->inputs == NULL);
+ }
+ else {
+ return (nb);
+ }
+ }
+ }
+ return (nb);
+}
+
+int input_add(t_db_input *in, char *src, t_source_type *sourcestype) {
+ char tmp[BUFFER_LENGTH], *ptmp, *otmp = NULL;
+ int sel;
+ t_device *new;
+
+ strcpy(tmp, src);
+ if ((ptmp = backslashed_strchr(tmp, ':'))) {
+ *ptmp++ = 0;
+
+ /* look for options */
+ if ((otmp = strchr(tmp, '+'))) *otmp++ = 0;
+
+ /* find corresponding source */
+ for (sel = 0; sourcestype[sel].name; sel++)
+ if (!strcmp(tmp, sourcestype[sel].name)) break;
+ if (!sourcestype[sel].name) {
+ /* not found, error */
+ error("can't find source type %s (%s:%s)\n", tmp, tmp, ptmp);
+ return (0);
+ }
+ }
+ else {
+ sel = 0;
+ ptmp = tmp;
+ }
+
+ /* allocate memory for new device */
+ new = MALLOC(sizeof(*new));
+ new->opened = &sourcestype[sel];
+ /* call of device initialize specific function */
+ if (new->opened->open) {
+ if (!(new->env = new->opened->open(ptmp, otmp))) {
+ error("can't open '%s'", src);
+ FREE(new);
+ return (0);
+ }
+ if (new->opened->fcntl) {
+ if (in->inputs) {
+ Sorted &= ~INPUT_SORTED;
+ }
+ else {
+ Sorted &= (~INPUT_SORTED|
+ ((new->opened->fcntl(new->env, IS_SORTED) ? INPUT_SORTED : 0)));
+ }
+ }
+ }
+ else
+ new->env = NULL;
+ /* add in current driver list */
+ SIMPLE_LIST_FILE(in->inputs, new);
+ in->eof = 0;
+ return (1);
+}
+
+
+inline int input_eof(t_db_input *in) {
+ return (in->eof);
+}
+
+t_db_input *input_alloc() {
+ t_db_input *in;
+
+ in = MALLOC(sizeof(t_db_input));
+ bzero(in, sizeof(t_db_input));
+ return (in);
+}
+
+t_db_input *input_free(t_db_input *old) {
+ t_device *current;
+
+ while (old->inputs) {
+ current = SIMPLE_LIST_POP(old->inputs);
+ current->opened->close(current->env);
+ FREE(current);
+ }
+ FREE(old);
+ return (NULL);
+}
diff --git a/flx/input.h b/flx/input.h
new file mode 100644
index 0000000..c6b2a9f
--- /dev/null
+++ b/flx/input.h
@@ -0,0 +1,24 @@
+#ifndef __INPUT_H__
+#define __INPUT_H__
+
+#include "source_type.h"
+
+/* input structure */
+typedef struct s_db_input t_db_input;
+
+struct s_db_input {
+ t_source_type *opened; /* source access structure description */
+ int eof; /* marker for end of file */
+ void *inputs; /* list of inputs */
+};
+
+
+extern int input_read(t_db_input *in, void *tree);
+extern int input_eof(t_db_input *in);
+extern t_db_input *input_alloc();
+extern t_db_input *input_free(t_db_input *old);
+extern int input_add(t_db_input *in, char *desc, t_source_type *sourcestype);
+
+#endif /* __INPUT_H__ */
+
+
diff --git a/flx/input_file.c b/flx/input_file.c
new file mode 100644
index 0000000..5a4b0c5
--- /dev/null
+++ b/flx/input_file.c
@@ -0,0 +1,462 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/types.h>
+#include <stdlib.h>
+#include <dirent.h>
+
+#include "input_file.h"
+#include "utils.h"
+#include "flx.h"
+
+
+#define STAT_NOTREAD 0x01
+#define STAT_MULTI_FILES 0x02
+
+#define OPT_SORTED 0x01
+#define OPT_READ 0x02
+
+
+char **get_field1(char *line) {
+ static char *tab[10];
+ char *pline = line;
+ int i = 0;
+
+ while (*line && i < 9) {
+ /* pass spaces */
+ while (*line == ' ' || *line == '\t') line++;
+ /* verify */
+ if (!*line) break;
+ /* backup pointer */
+ tab[i] = pline;
+ /* look for data */
+ while (*line && *line != ' ' && *line != '\t') {
+ /* pass '(' in value fields */
+ if (*line == '(') {
+ *line++ = 0;
+ while (*line && *line != ')') line++;
+ break;
+ }
+ /* pass backslashed characters */
+ if (*line == '\\' && *(line+1)) {
+ *pline++ = *(line+1);
+ line += 2 ;
+ }
+ else {
+ *pline++ = *line++ ;
+ }
+ }
+ if (*line) line++;
+ *pline++ = 0;
+ i++;
+ }
+ tab[i] = NULL;
+ return (tab);
+}
+
+/* treat a line, build new tree and compile with current
+ * tab is a tab of char that finish with a NULL string
+ * filename is a pointer address to a filename
+ * desc is the current desc pointer
+ */
+t_file_desc *fill_from_signfs_line(char **tab, char **rpath, t_file_desc **desc) {
+ char *p1, temp[64];
+ struct stat *st;
+ int nfield, i;
+
+ /* just want filename */
+ if (!desc) {
+ /* search the 7th position */
+ for (i=0; (*rpath = tab[i]) && i < 7 ; i++);
+ /* passe bad saved ./ and ../ */
+ if (i == 7) {
+ p1 = NULL;
+ while (p1 != *rpath) {
+ p1 = *rpath;
+ if (!strncmp(*rpath, "./", 2)) *rpath += 2;
+ if (!strncmp(*rpath, "../", 3)) *rpath += 3;
+ }
+ }
+ return (NULL);
+ }
+ /* want to complete data */
+ if (!*desc) {
+ *desc = MALLOC(sizeof(**desc));
+ bzero(*desc, sizeof(**desc));
+ }
+ st = &((*desc)->stat);
+ for(nfield = 0; (p1 = tab[nfield]); nfield++) {
+
+ switch (nfield) {
+ case 0: /* file type */
+ st->st_mode |= (*p1 == 'l' ? S_IFLNK :
+ *p1 == 'd' ? S_IFDIR :
+ *p1 == 'c' ? S_IFCHR :
+ *p1 == 'b' ? S_IFBLK :
+ *p1 == 'f' ? S_IFIFO :
+ *p1 == 's' ? S_IFSOCK :
+ *p1 == '-' ? S_IFREG : 0);
+ break;
+ case 1: /* file mode */
+ st->st_mode |= strtol(p1, NULL, 8); break;
+ case 2: /* user id */
+ st->st_uid = atoi(p1); break;
+ case 3: /* group id */
+ st->st_gid = atoi(p1); break;
+ case 4: /* size or major/minor for devices */
+ strncpy(temp, p1, 64); temp[63] = 0;
+ if ((p1 = strchr(temp, ','))) {
+ *p1++ = 0;
+ st->st_rdev = atoi(temp)*256 + atoi(p1);
+ }
+ else
+ st->st_size = atol(temp);
+ break;
+ case 5: /* checksum */
+ if (p1[0] != '-') {
+ for (i = 0 ; p1[i] ; i++)
+ temp[i] = (unsigned char)
+ (HEXTODEC(p1[i * 2]) * 16 + HEXTODEC(p1[i * 2 + 1]));
+ (*desc)->md5 = MALLOC(i);
+ memcpy((*desc)->md5, temp, i);
+ }
+ break;
+ case 6: /* modification time */
+ st->st_mtime = (time_t)atol(p1); break;
+ case 7: /* filename (p1 is path, p2 is filename) */
+ if (rpath) *rpath = p1;
+ break;
+ case 8: /* link */
+ (*desc)->link = strdup(p1);
+ break;
+ }
+ }
+ return (*desc);
+}
+
+
+
+int input_file_read_files(t_file_status *desc, t_ft *tree, int cmax) {
+ char line[BUFFER_LENGTH], **tab;
+ char *filename, *path;
+ int count = 0;
+ t_ft *new;
+ /* variable used for acceleration */
+ char oldpath[BUFFER_LENGTH] = "", *poldpath = oldpath;
+ t_ft *oldtree;
+
+ if (!desc->fd || feof(desc->fd)) return (0);
+
+ /* possibly have to mark current working directory has SORTING */
+ strcpy(oldpath, desc->cpath);
+ poldpath = oldpath + strlen(oldpath);
+ oldtree = ft_get(tree, oldpath);
+ SET(oldtree->status, READING);
+
+ if (IS(desc->status, STAT_MULTI_FILES)) {
+ SET(oldtree->status, SORTING);
+ }
+
+ /* read count entry in file */
+ while (!cmax || count < cmax) {
+ /* read one line from current fd */
+ if (!fgets(line, BUFFER_LENGTH, desc->fd)) break;
+
+ line[ strlen(line)-1 ] = 0;
+ /* split into field */
+ tab = get_field1(line);
+
+ /* just get filename */
+ fill_from_signfs_line(tab, &path, NULL);
+ if (!path) continue;
+
+ /* look for required string in path */
+ /* remove leading '/' */
+ filename = path + strlen(path) - 1;
+ while (*filename == '/') *filename-- = 0;
+ /* find filename into path */
+ if (!(filename = strrchr(path, '/'))) filename = path;
+ else filename++;
+
+ /* options tell to ignore '.' and '..' */
+ if (IS(Options, GOPT_IGNORE_DOT) && IS_DOTF(filename))
+ continue;
+
+ /* look for old definition */
+ if (filename != path && (poldpath - path) == (filename - path - 1) &&
+ !strncmp(oldpath, path, filename - path - 1)) {
+ new = ft_get(oldtree, filename);
+ // SET(oldtree->status, READING);
+ }
+ else {
+ /* look for this object from base */
+ new = ft_get(tree, path);
+ UNSET(oldtree->status, READING);
+ oldtree = new->parent;
+ strcpy(oldpath, build_path(oldtree));
+ poldpath = oldpath + strlen(oldpath);
+ SET(oldtree->status, READING);
+ }
+
+ /* complete information from line */
+ new->desc = fill_from_signfs_line(tab, NULL, (void*)&new->desc);
+
+ /* mark tree as changed and completed */
+ SET(new->status, FILLED);
+ SET_PARENT(new, CHANGED);
+
+ /* file counter */
+ count++;
+ if (cmax && count >= cmax) return (count);
+ }
+ /* end of file, close it */
+ if (desc->fd != stdin) fclose(desc->fd);
+ desc->fd = NULL;
+
+ return (count);
+}
+
+FILE *input_file_set_next_file(t_file_status *desc, t_ft *tree) {
+ char *pcpath, *pbpath;
+ t_ft *ctree;
+
+ /* something to read or no more dir to read */
+ if (desc->fd || !desc->dirnames) return (desc->fd);
+
+ /* restore/build tree position for cpath */
+ tree = ft_get(tree, desc->cpath);
+
+ /* initialize pointer to end of path */
+ pcpath = desc->cpath + strlen(desc->cpath);
+ pbpath = desc->bpath + strlen(desc->bpath);
+
+ while (1) {
+
+ /* mark directory as unsorted */
+ SET(tree->status, SORTING);
+ /* get directory entries if never done */
+ if (IS(desc->status, STAT_NOTREAD)) {
+ DIR *dir;
+ struct dirent *dirent;
+ struct stat st;
+
+ /* unset all previous flag */
+ UNSET(desc->status, STAT_MULTI_FILES);
+
+ if (!(dir = opendir(desc->bpath)))
+ PFERROR("opendir(%s)", desc->bpath);
+ else {
+ while ((dirent = readdir(dir))) {
+
+ /* build path to work with it */
+ ADD_PATH(desc->bpath, pbpath, dirent->d_name);
+
+ if (stat(desc->bpath, &st)) {
+ /* stat filename to find directory */
+ PFERROR("stat(%s)", desc->bpath);
+ }
+ /* check for specfic files */
+ else if (!strcmp(dirent->d_name, DUMPBASENAME)) {
+ /* set multifiles (unsorted) flag */
+ if (desc->filenames) SET(desc->status, STAT_MULTI_FILES);
+ /* backup filename */
+ SIMPLE_LIST_PUSH(desc->filenames, STRDUP(dirent->d_name));
+ }
+ /* if directory (without . and ..) */
+ else if (S_ISDIR(st.st_mode) && !IS_DOTF(dirent->d_name)) {
+ /* backup path */
+ PUSH_STR_SORTED(SIMPLE_LIST_PTR(desc->dirnames),
+ STRDUP(dirent->d_name));
+ /* set flag SORTING to futur directory */
+ ctree = ft_get(tree, dirent->d_name);
+ SET(ctree->status, SORTING);
+ }
+ }
+ closedir(dir);
+ /* remove all added filenames */
+ *pbpath = *pcpath = 0;
+ }
+ UNSET(desc->status, STAT_NOTREAD);
+ }
+
+ /* look for all files to read */
+ while (desc->filenames) {
+ char *filename;
+
+ /* get filename and build complet path */
+ filename = SIMPLE_LIST_POP(desc->filenames);
+ ADD_PATH(desc->bpath, pbpath, filename);
+ FREE(filename);
+ /* try to open and return */
+ if (!(desc->fd = fopen(desc->bpath, "r"))) PFERROR("fopen(%s)", desc->bpath);
+ else {
+ /* remove filename from cpath */
+ *pbpath = 0;
+ return (desc->fd);
+ }
+ /* clean filename */
+ *pbpath = 0;
+ }
+
+ /* all files in this directory are read */
+ UNSET(tree->status, SORTING);
+
+ /* look for all directories marked */
+ if (SIMPLE_LIST_PTR(desc->dirnames)) {
+ char *filename;
+
+ filename = SIMPLE_LIST_POP(SIMPLE_LIST_PTR(desc->dirnames));
+ /* get new path and add it to current */
+ pcpath = ADD_PATH(desc->cpath, pcpath, filename);
+ pbpath = ADD_PATH(desc->bpath, pbpath, filename);
+
+ /* push a new directory stack */
+ SIMPLE_LIST_PUSH(desc->dirnames, NULL);
+ /* seek tree with new path */
+ tree = ft_get(tree, filename);
+
+ SET(desc->status, STAT_NOTREAD);
+ FREE(filename);
+ continue;
+ }
+
+ /* nothing to do return to parent */
+ SIMPLE_LIST_POP(desc->dirnames);
+ /* no more parent */
+ if (!desc->dirnames) return (NULL);
+ /* set to parent */
+ tree = tree->parent;
+ pcpath = REMOVE_DIR(desc->cpath, pcpath);
+ *pcpath = 0;
+ pbpath = REMOVE_DIR(desc->bpath, pbpath);
+ *pbpath = 0;
+
+ }
+ return (desc->fd);
+}
+
+int input_file_read(t_file_status *desc, t_ft *tree) {
+ int count = 0, cmax = COUNT_LEVEL1;
+
+ /* force marking the base : ABNORMAL */
+ SET(tree->status, CHANGED);
+ /* file input loop */
+ while (!cmax || count < cmax) {
+ if (!input_file_set_next_file(desc, tree)) break;
+ count += input_file_read_files(desc, tree, COUNT_LEVEL2);
+ }
+ return (count);
+}
+
+/* traduct a string options descriptions to flags
+ */
+int input_file_fcntl(t_file_status *env, int cmd) {
+ if (IS(cmd, IS_SORTED)) return (env ? IS(env->options, OPT_SORTED) : 1);
+ return (0);
+}
+
+
+t_file_status *input_file_open(char *pathname, char *opts) {
+ t_file_status *new;
+ char *filename;
+ int status;
+ char tmp[BUFFER_LENGTH];
+ char *ppath, *popts, *pvalue;
+ int options = (OPT_SORTED|OPT_READ);
+
+ popts = opts ? strcpy(tmp, opts) : NULL;
+ ppath = pathname ? strcpy(tmp + strlen(tmp) + 1, pathname) : NULL;
+
+ /* part to get source specific options */
+ while (popts) {
+ int sign = 1;
+ char *t;
+
+ /* select an option and its value */
+ if ((t = strchr(popts, '+'))) *t++ = 0;
+ if ((pvalue = strchr(popts, '='))) *pvalue++ = 0;
+
+ /* remove negative */
+ while (*popts == '!') { sign = -sign ; popts++; }
+
+ /* treat option */
+ if (!*popts) continue;
+ else if (!strcmp(popts, "sort")) /* sorted flag */
+ options = (sign > 0 ? (options|OPT_SORTED) : (options&~OPT_SORTED));
+ else {
+ error("unknown option : %s", popts);
+ return (0);
+ }
+ popts = t;
+ }
+
+ new = MALLOC(sizeof(*new));
+ bzero(new, sizeof(*new));
+ filename = ppath;
+ new->options = options;
+ /* looking for separator before filename */
+ if (ppath && (ppath = backslashed_strmchr(ppath, DELIM_LIST))) {
+ status = *ppath;
+ *ppath++ = 0;
+ }
+
+ if (!filename || !filename[0] || !strcmp(filename, "-")) {
+ /* special case for stdin */
+ new->fd = stdin;
+ }
+ else {
+ struct stat st;
+ /* case for files, should stat them */
+ if (stat(filename, &st)) {
+ PFERROR("stat(%s)", filename);
+ FREE(new);
+ return (NULL);
+ }
+ if (S_ISDIR(st.st_mode)) {
+ /* directory, directory treatment */
+ strcpy(new->bpath, define_cleaned_path(filename));
+ strcpy(new->cpath, "");
+ new->filenames = NULL;
+ new->dirnames = NULL;
+ SET(new->status, STAT_NOTREAD);
+ SIMPLE_LIST_PUSH(new->dirnames, NULL);
+ }
+ else {
+ /* can test and open */
+ if (!(new->fd = fopen(filename, "r"))) {
+ PFERROR("open(%s)", filename);
+ FREE(new);
+ return (NULL);
+ }
+ }
+ }
+ return (new);
+}
+
+
+t_file_status *input_stdin_open(char *desc, char *opts) {
+ if ((desc = backslashed_strmchr(desc, DELIM_LIST)))
+ return (input_file_open(desc, opts));
+ return (input_file_open("", opts));
+}
+
+t_file_status *input_file_close(t_file_status *old) {
+ if (old->fd && old->fd != stdin) fclose(old->fd);
+ while (old->dirnames) {
+ while (SIMPLE_LIST_PTR(old->dirnames))
+ FREE(SIMPLE_LIST_POP(SIMPLE_LIST_PTR(old->dirnames)));
+ SIMPLE_LIST_POP(old->dirnames);
+ }
+ while (old->filenames)
+ FREE(SIMPLE_LIST_POP(old->dirnames));
+ FREE(old);
+ return (NULL);
+}
+
+
+
+
+
+
+
+
diff --git a/flx/input_file.h b/flx/input_file.h
new file mode 100644
index 0000000..9042552
--- /dev/null
+++ b/flx/input_file.h
@@ -0,0 +1,34 @@
+#ifndef __INPUT_FILE_H__
+#define __INPUT_FILE_H__
+
+#include <stdio.h>
+
+#include "utils.h"
+#include "flx.h"
+#include "flx_fcntl.h"
+
+typedef struct s_file_status t_file_status;
+
+struct s_file_status {
+ FILE *fd; /* pointer to current file */
+ char bpath[BUFFER_LENGTH]; /* path for real directory */
+ char cpath[BUFFER_LENGTH]; /* path for saving infos */
+ void *dirnames; /* stack for directory names */
+ void *filenames; /* stack for file names */
+ int status; /* reading status */
+ void *fdstack; /* output file descriptor stack */
+ int recursion, prev_recursion; /* recursion requiered */
+ int options; /* options flags */
+};
+
+extern int input_file_fcntl(t_file_status *env, int cmd);
+
+extern int input_file_read(t_file_status *spec, t_ft *tree);
+extern t_file_status *input_file_open(char *desc, char *opts);
+extern t_file_status *input_file_close(t_file_status *spec);
+
+extern t_file_status *input_stdin_open(char *desc, char *opts);
+
+#endif /* __INPUT_FILE_H__ */
+
+
diff --git a/flx/input_fs.c b/flx/input_fs.c
new file mode 100644
index 0000000..042134c
--- /dev/null
+++ b/flx/input_fs.c
@@ -0,0 +1,332 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "input_fs.h"
+#include "flx.h"
+#include "utils.h"
+
+#define STAT_NOTREAD 0x01
+#define STAT_TOBECONTINUED 0x02
+#define STAT_DOINIT 0x04
+
+
+#define OPT_XDEV 0x01
+#define OPT_FOLLOW_LINKS 0x02
+#define OPT_SORTED 0x04
+#define OPT_READ 0x08
+
+static t_file_desc *complete_info_from_fs(char *path, t_file_desc *desc) {
+ struct stat stat;
+
+ /* try to stat it */
+ if (lstat(path, &stat)) {
+ PFERROR("stat(%s)", path);
+ return (0);
+ }
+ if (!desc) {
+ /* have to create it */
+ desc = MALLOC(sizeof(*desc));
+ bzero(desc, sizeof(*desc));
+ }
+ /* copy stat informations */
+ memcpy(&desc->stat, &stat, sizeof(stat));
+
+ if (S_ISREG(stat.st_mode) && !desc->md5) /* get md5 checksum */
+ desc->md5 = checksum_md5_from_file(path);
+ else if (S_ISLNK(stat.st_mode) && !desc->link) {
+ /* get link and md5 associed */
+ char temp[BUFFER_LENGTH];
+ int l;
+
+ if ((l = readlink(path, temp, BUFFER_LENGTH)) < 0) {
+ PFERROR("readlink(%s)", path);
+ } else {
+ temp[l] = 0;
+ desc->link = strdup(temp);
+ desc->md5 = checksum_md5_from_data(temp, l);
+ }
+ }
+ return (desc);
+}
+
+int desc_s_isdir_from_fs(char *filename, t_file_desc *desc) {
+ if (!desc) {
+ struct stat st;
+ if (!filename) return (0);
+
+ if (stat(filename, &st)) {
+ PFERROR("stat(%s)", filename);
+ return (0);
+ }
+ return (S_ISDIR(st.st_mode));
+ }
+ return (S_ISDIR(desc->stat.st_mode));
+}
+
+#define DESC_S_ISDIR(desc) ((desc)?(S_ISDIR(((t_file_desc*)(desc))->stat.st_mode)):0)
+#define DESC_DEV(desc) ((desc)?(((t_file_desc*)(desc))->stat.st_dev):0)
+
+
+/* get file entries from filesystem
+ * ics : input current status
+ * tree : tree to load
+ * return the number of entries readed
+ */
+int input_fs_read(t_fs_status *desc, t_ft *tree) {
+ char *pcpath, *pbpath;
+ int count = 0, cmax = COUNT_LEVEL2;
+
+ /* something to read or no more dir to read */
+ if (!desc->dirnames) return (0);
+
+ /* force to mark base ABNORMAL! */
+ SET(tree->status, CHANGED);
+ /* restore/build tree position for cpath */
+ tree = ft_get(tree, desc->cpath);
+
+ /* set base path pointers */
+ pcpath = desc->cpath + strlen(desc->cpath);
+ pbpath = desc->bpath + strlen(desc->bpath);
+
+ /* read infos for wanted directory */
+ if (IS(desc->status, STAT_DOINIT)) {
+
+ if (!(tree->desc = complete_info_from_fs(desc->bpath, tree->desc)))
+ return (0);
+ SET_PARENT(tree, CHANGED);
+ SET(tree->status, FILLED);
+ count++;
+
+ /* remove init flag */
+ UNSET(desc->status, STAT_DOINIT);
+
+ /* set base device */
+ desc->dev = DESC_DEV(tree->desc);
+
+ /* this part is used to detect directory and directly */
+ if (IS(Options, GOPT_IGNORE_DEPTH) ||
+ !DESC_S_ISDIR(tree->desc) || desc->depth == 1) {
+ SIMPLE_LIST_POP(desc->dirnames);
+ return (count);
+ }
+
+ /* sub directory recursion */
+ desc->depth--;
+ }
+
+ while (1) {
+
+ /* get directory entries if never done */
+ if (IS(desc->status, STAT_NOTREAD)) {
+ DIR *dir;
+ struct dirent *dirent = NULL;
+ t_ft *new;
+
+ /* mark directory as unsorted */
+ SET(tree->status, SORTING);
+
+ if (!(dir = opendir(desc->bpath)))
+ PFERROR("opendir(%s)", desc->bpath);
+ else {
+ /* restore old stored position */
+ if (IS(desc->status, STAT_TOBECONTINUED)) {
+ seekdir(dir, desc->off_dir);
+ }
+
+ /* look for each files */
+ while ((!cmax || count < cmax)) {
+
+ if (!(dirent = readdir(dir))) break;
+
+ /* options tell to ignore '.' and '..' */
+ if (IS(Options, GOPT_IGNORE_DOT) && IS_DOTF(dirent->d_name))
+ continue;
+
+ /* build path to work with it */
+ // ADD_PATH(desc->cpath, pcpath, dirent->d_name);
+ ADD_PATH(desc->bpath, pbpath, dirent->d_name);
+
+ /* create/get entry */
+ new = ft_get(tree, dirent->d_name);
+
+ /* get file informations */
+ new->desc = complete_info_from_fs(desc->bpath, new->desc);
+ SET_PARENT(new, CHANGED);
+ SET(new->status, FILLED);
+
+ /* if directory (without . and ..) and not XDEV */
+ /* if not maximum directory level reached */
+ if (desc->depth != 1 &&
+ DESC_S_ISDIR(new->desc) && !IS_DOTF(dirent->d_name) &&
+ (!IS(desc->options, OPT_XDEV) || desc->dev == DESC_DEV(new->desc))) {
+
+ PUSH_STR_SORTED(SIMPLE_LIST_PTR(desc->dirnames),
+ STRDUP(dirent->d_name));
+ /* set flag SORTING to futur directory */
+ SET(new->status, SORTING);
+ }
+ count++;
+ }
+ *pcpath = *pbpath = 0;
+
+ /* have finished to read ?? */
+ if (dirent) {
+ /* no break and return number */
+ desc->off_dir = telldir(dir);
+ closedir(dir);
+ SET(desc->status, STAT_TOBECONTINUED);
+ return (count);
+ }
+ closedir(dir);
+ }
+ UNSET(desc->status, STAT_NOTREAD|STAT_TOBECONTINUED);
+ }
+
+ /* all files in this directory are read */
+ UNSET(tree->status, SORTING);
+
+ /* look for all directories marked */
+ if (SIMPLE_LIST_PTR(desc->dirnames)) {
+ char *filename;
+
+ filename = SIMPLE_LIST_POP(SIMPLE_LIST_PTR(desc->dirnames));
+ /* get new path and add it to current */
+ pcpath = ADD_PATH(desc->cpath, pcpath, filename);
+ /* set new complet path */
+ pbpath = ADD_PATH(desc->bpath, pbpath, filename);
+
+ /* decrease directory depth */
+ if (desc->depth) desc->depth--;
+
+ /* push a new directory stack */
+ SIMPLE_LIST_PUSH(desc->dirnames, NULL);
+ /* seek tree with new path */
+ tree = ft_get(tree, filename);
+
+ SET(desc->status, STAT_NOTREAD);
+ FREE(filename);
+ continue;
+ }
+
+ /* nothing to do return to parent */
+ SIMPLE_LIST_POP(desc->dirnames);
+
+ /* increase directory depth */
+ if (desc->depth) desc->depth++;
+
+ /* no more parent */
+ if (!desc->dirnames) return (count);
+ /* set to parent */
+ tree = tree->parent;
+ pcpath = REMOVE_DIR(desc->cpath, pcpath);
+ *pcpath = 0;
+ pbpath = REMOVE_DIR(desc->bpath, pbpath);
+ *pbpath = 0;
+ }
+ return (count);
+}
+
+
+/* traduct a string options descriptions to flags
+ */
+int input_fs_fcntl(t_fs_status *env, int cmd) {
+ if (IS(cmd, IS_SORTED)) return (env ? IS(env->options, OPT_SORTED) : 1);
+ return (0);
+}
+
+/* initialise or add data to current input driver
+ */
+t_fs_status *input_fs_open(char *pathname, char *opts) {
+ t_fs_status *new;
+ char tmp[BUFFER_LENGTH];
+ char *ppath, *popts, *pvalue, *filename;
+ int status = 0;
+ int options = (OPT_SORTED|OPT_XDEV|OPT_READ);
+ int depth = 0;
+
+ popts = opts ? strcpy(tmp, opts) : NULL;
+ ppath = pathname ? strcpy(tmp + strlen(tmp) + 1, pathname) : NULL;
+
+ while (popts) {
+ int sign = 1;
+ char *t;
+
+ /* select an option and its value */
+ if ((t = strchr(popts, '+'))) *t++ = 0;
+ if ((pvalue = strchr(popts, '='))) *pvalue++ = 0;
+
+ /* remove negative */
+ while (*popts == '!') { sign = -sign ; popts++; }
+
+ /* treat option */
+ if (!*popts) continue;
+ else if (!strcmp(popts, "sort")) /* sorted flag */
+ options = (sign > 0 ? (options|OPT_SORTED) : (options&~OPT_SORTED));
+ else if (!strcmp(popts, "xdev")) /* do not recurse across fs */
+ options = (sign > 0 ? (options|OPT_XDEV) : (options&~OPT_XDEV));
+ else if (!strcmp(popts, "depth")) /* recursive level across directory */
+ depth = atoi(pvalue);
+ else if (!strcmp(popts, "flw")) /* follow links */
+ options = (sign > 0 ? (options|OPT_FOLLOW_LINKS) : (options&~OPT_FOLLOW_LINKS));
+ else {
+ error("unknown option : %s", popts);
+ return (0);
+ }
+ popts = t;
+ }
+
+ new = MALLOC(sizeof(*new));
+ bzero(new, sizeof(*new));
+
+ new->dirnames = NULL;
+ SIMPLE_LIST_PUSH(new->dirnames, NULL);
+ new->status = STAT_NOTREAD | STAT_DOINIT;
+
+ /* save special options */
+ new->options = options;
+ new->depth = depth;
+
+ filename = ppath;
+ /* looking for separator before filename */
+ if (ppath && (ppath = backslashed_strmchr(ppath, DELIM_LIST))) {
+ status = *ppath;
+ *ppath++ = 0;
+ }
+
+ strcpy(new->bpath, define_cleaned_path(filename));
+ if (!*new->bpath) strcpy(new->bpath, ".");
+
+ /* have to remove sub parameters */
+ // HERE
+
+ if (status == '=' && ppath)
+ strcpy(new->cpath, define_cleaned_path(ppath));
+ else
+ strcpy(new->cpath, define_base_path(filename));
+ return (new);
+}
+
+/* free all used memory
+ */
+t_fs_status *input_fs_close(t_fs_status *old) {
+ while (old->dirnames) {
+ while (SIMPLE_LIST_PTR(old->dirnames))
+ FREE(SIMPLE_LIST_POP(SIMPLE_LIST_PTR(old->dirnames)));
+ SIMPLE_LIST_POP(old->dirnames);
+ }
+ FREE(old);
+ return (NULL);
+}
+
+
+
+
+
+
+
+
+
diff --git a/flx/input_fs.h b/flx/input_fs.h
new file mode 100644
index 0000000..a1594cf
--- /dev/null
+++ b/flx/input_fs.h
@@ -0,0 +1,29 @@
+#ifndef __INPUT_FS_H__
+#define __INPUT_FS_H__
+
+#include "utils.h"
+#include "flx.h"
+#include "flx_fcntl.h"
+
+typedef struct s_fs_status t_fs_status;
+
+struct s_fs_status {
+ char bpath[BUFFER_LENGTH]; /* current real path */
+ char cpath[BUFFER_LENGTH]; /* current path representation */
+ off_t off_dir; /* dir offset for backup/restore */
+ int status; /* action status */
+ int options; /* read or write options */
+ void *dirnames; /* stack for directory backup */
+ dev_t dev; /* base device number */
+ int depth; /* depth level */
+};
+
+extern int input_fs_fcntl(t_fs_status *env, int cmd);
+
+extern int input_fs_read(t_fs_status *spec, t_ft *tree);
+extern t_fs_status *input_fs_open(char *desc, char *opts);
+extern t_fs_status *input_fs_close(t_fs_status *spec);
+
+#endif /* __INPUT_FS_H__ */
+
+
diff --git a/flx/main.c b/flx/main.c
new file mode 100644
index 0000000..dedfd73
--- /dev/null
+++ b/flx/main.c
@@ -0,0 +1,79 @@
+/*
+ * Signfs version 0.6, Copyright Benoit DOLEZ, 2002
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <dirent.h>
+#include <string.h>
+#include <time.h>
+#include <stdlib.h>
+#include <stdarg.h>
+
+#include "flx.h"
+#include "check.h"
+#include "sign.h"
+#include "utils.h"
+#include "arg.h"
+
+
+POOL_INIT(t_file_tree);
+
+/* device for xdev option */
+dev_t SingleDev = -1;
+char *DumpFilename = DUMPBASENAME;
+int RecursionLevel = 0; /* follow recursion */
+int Diff = 0xFFFF;
+int Options = (SHOW_OLD|SHOW_NEW);
+char *Progname = NULL;
+
+#define FLX_SIGN 1
+#define FLX_CHECK 2
+
+
+t_param FLX_poptions[] = {
+ { 0, NULL, 0xFFFF, 0, "sign -h|<options> input [...]
+ sign data" },
+ { 0, NULL, 0xFFFF, 0, "check -h|<options> src1 src2
+ check difference between src1 and src2" },
+ { 0, NULL, 0xFFFF, 0, "check -h|<options> src1 [...] , src2 [...]
+ check difference between srcs1 and srcs2" },
+ { 0, NULL, 0, 0}
+};
+
+
+int main(int argc, char **argv) {
+ int ret = 0, mode = 0;
+ struct { int (*fctprm)(); void *dtaprm; int (*fctmain)(); } flx[] = {
+ { NULL, FLX_poptions, NULL },
+ { flxsign_pfct, flxsign_poptions, flxsign_main },
+ { flxcheck_pfct, flxcheck_poptions, flxcheck_main }
+ };
+
+ /* look at parameter with program name */
+ if (!strcmp(progname(argv[0]), "flxcheck")) mode = FLX_CHECK ;
+ else if (!strcmp(progname(argv[0]), "flxsign")) mode = FLX_SIGN ;
+ else if (!strcmp(progname(argv[0]), "flx") && argc > 1) {
+ if (!strcmp(argv[1], "check")) mode = FLX_CHECK ;
+ else if (!strcmp(argv[1], "sign")) mode = FLX_SIGN ;
+ else arg_usage(FLX_poptions, NULL);
+ argc--; argv++;
+ }
+ else
+ arg_usage(FLX_poptions, NULL);
+
+ ret = arg_init(argc, argv, flx[mode].dtaprm, flx[mode].fctprm);
+
+ if (ret <= 0) exit(1);
+ argc -= ret; argv += ret;
+
+ /* execute program */
+ return (flx[mode].fctmain(argc, argv));
+}
+
+
+
diff --git a/flx/md5.c b/flx/md5.c
new file mode 100644
index 0000000..3c42ff6
--- /dev/null
+++ b/flx/md5.c
@@ -0,0 +1,261 @@
+/* FIXME: ces routines ne fournissent qu'un résultat sur 64 bits sur ALPHA !!!
+ ctx->buf[0]=ctx->buf[1]=0.
+*/
+
+
+//#include <endian.h>
+#if __BYTE_ORDER == __BIG_ENDIAN
+#define HIGHFIRST 1
+#endif
+
+/*
+ * This code implements the MD5 message-digest algorithm.
+ * The algorithm is due to Ron Rivest. This code was
+ * written by Colin Plumb in 1993, no copyright is claimed.
+ * This code is in the public domain; do with it what you wish.
+ *
+ * Equivalent code is available from RSA Data Security, Inc.
+ * This code has been tested against that, and is equivalent,
+ * except that you don't need to include two pages of legalese
+ * with every copy.
+ *
+ * To compute the message digest of a chunk of bytes, declare an
+ * MD5Context structure, pass it to MD5Init, call MD5Update as
+ * needed on buffers full of bytes, and then call MD5Final, which
+ * will fill a supplied 16-byte array with the digest.
+ */
+#include <string.h> /* for memcpy() */
+#include "md5.h"
+
+#ifndef HIGHFIRST
+#define byteReverse(buf, len) /* Nothing */
+#else
+void byteReverse(unsigned char *buf, unsigned longs);
+
+#ifndef ASM_MD5
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+ uint32 t;
+ do {
+ t = (uint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(uint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+#endif
+
+/*
+ * Start MD5 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void ToolsMD5Init(struct MD5Context *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void ToolsMD5Update(struct MD5Context *ctx, unsigned char const *buf, unsigned len)
+{
+ uint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((uint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ ToolsMD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ ToolsMD5Transform(ctx->buf, (uint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void ToolsMD5Final(unsigned char digest[16], struct MD5Context *ctx)
+{
+ unsigned count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ ToolsMD5Transform(ctx->buf, (uint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((uint32 *) ctx->in)[14] = ctx->bits[0];
+ ((uint32 *) ctx->in)[15] = ctx->bits[1];
+
+ ToolsMD5Transform(ctx->buf, (uint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+#ifndef ASM_MD5
+
+/* The four core functions - F1 is optimized somewhat */
+
+/* #define F1(x, y, z) (x & y | ~x & z) */
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+/* This is the central step in the MD5 algorithm. */
+#define MD5STEP(f, w, x, y, z, data, s) \
+ ( w += f(x, y, z) + data, w = w<<s | w>>(32-s), w += x )
+
+/*
+ * The core of the MD5 algorithm, this alters an existing MD5 hash to
+ * reflect the addition of 16 longwords of new data. MD5Update blocks
+ * the data and converts bytes into longwords for this routine.
+ */
+void ToolsMD5Transform(uint32 buf[4], uint32 const in[16])
+{
+ register uint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+#endif
diff --git a/flx/md5.h b/flx/md5.h
new file mode 100644
index 0000000..7e287a6
--- /dev/null
+++ b/flx/md5.h
@@ -0,0 +1,55 @@
+/*
+ * SignFS : Tool to have an image of the filesystem
+ *
+ * Copyright (C) 1999-2001, Willy Tarreau <willy@ant-computing.com>
+ *
+ * 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 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * File: md5.h
+ * Object: list and hash functions
+ * Version: 0.3
+ * Date: Sun Dec 23 14:21:50 CET 2001
+ * Autors: Willy Tarreau <willy@ant-computing.com>
+ */
+
+#ifndef MD5_H
+#define MD5_H
+
+#ifdef __alpha
+typedef unsigned int uint32;
+#else
+typedef unsigned long uint32;
+#endif
+
+struct MD5Context {
+ uint32 buf[4];
+ uint32 bits[2];
+ unsigned char in[64];
+};
+
+void ToolsMD5Init(struct MD5Context *context);
+void ToolsMD5Update(struct MD5Context *context, unsigned char const *buf,
+ unsigned len);
+void ToolsMD5Final(unsigned char digest[16], struct MD5Context *context);
+void ToolsMD5Transform(uint32 buf[4], uint32 const in[16]);
+
+/*
+ * This is needed to make RSAREF happy on some MS-DOS compilers.
+ */
+typedef struct MD5Context MD5_CTX;
+
+#endif /* !MD5_H */
diff --git a/flx/output.c b/flx/output.c
new file mode 100644
index 0000000..7898fc8
--- /dev/null
+++ b/flx/output.c
@@ -0,0 +1,157 @@
+#include <string.h>
+#include "utils.h"
+#include "flx.h"
+#include "output.h"
+#include "source_type.h"
+#include "flx_fcntl.h"
+
+int Sorted = (INPUT_SORTED|OUTPUT_SORTED); /* input/output sorted status */
+
+t_file_desc *free_file_desc(t_file_desc *desc) {
+ if (!desc) return (NULL);
+ if (desc->md5) FREE(desc->md5);
+ if (desc->link) FREE(desc->link);
+ FREE(desc);
+ return (NULL);
+}
+
+t_file_desc *fct_free_file_desc(void *data, t_file_desc *desc) {
+ return (free_file_desc(desc));
+}
+
+/* this function free file tree and return 1 if the free is completed
+ * it doesn't free the element (base)
+ */
+int ft_free(t_ft *tree, void *(*fct_free)(void *data, void *desc), void *data) {
+ t_ft *next;
+
+ /* nothing have change, do not free */
+ if (IS(Sorted, OUTPUT_SORTED) && !IS(Sorted, INPUT_SORTED)) return (0);
+
+ /* remove description */
+ if (IS(tree->status, FILLED)) {
+ if (tree->desc && fct_free) tree->desc = fct_free(data, tree->desc);
+ UNSET(tree->status, FILLED);
+ }
+ /* check for recursion */
+ if (!IS(tree->status, CHANGED) || IS(tree->status, SORTING) || !tree->subtree) {
+ UNSET(tree->status, CHANGED);
+ return (1);
+ }
+ /* look for first soon */
+ tree = tree->subtree->next;
+
+ while (!IS(tree->status, BASE)) {
+
+ /* pass unchanged elements */
+ if (!IS(tree->status, CHANGED)) { tree = tree->next; continue ; }
+
+ /* unset filled and remove data */
+ if (IS(tree->status, FILLED)) {
+ if (tree->desc && fct_free) tree->desc = fct_free(data, tree->desc);
+ UNSET(tree->status, FILLED);
+ }
+ /* stop if necessary */
+ if (IS(Sorted, OUTPUT_SORTED) && IS(tree->status, SORTING))
+ return (0);
+
+ /* check if having to look at subtree */
+ if (tree->subtree && !IS_PDOTF(tree)) {
+ if (ft_free(tree, fct_free, data)) {
+ if (tree->subtree == tree->subtree->next)
+ POOL_FREE(t_file_tree, tree->subtree);
+ }
+ else return (0);
+ }
+ /* free filename memory */
+ if (tree->filename) FREE(tree->filename);
+ /* unchain and go to the next */
+ next = tree->next;
+ UNSET(tree->status, CHANGED);
+ if (fct_free) {
+ LIST_UNCHAIN(tree);
+ POOL_FREE(t_file_tree, tree);
+ }
+ tree = next;
+ }
+ return (1);
+}
+
+int output_write(t_db_output *out, void *data, int number) {
+ t_device *dst;
+ void *current;
+ int valid = 1;
+
+ for (current = out->outputs; current ; current = SIMPLE_LIST_NEXT(current)) {
+ dst = SIMPLE_LIST_PTR(current);
+ if (dst->opened->write)
+ valid = dst->opened->write(dst->env, data, number) && valid;
+ }
+ return (valid);
+}
+
+int output_add(t_db_output *out, char *desc, t_source_type *sourcestype) {
+ char tmp[BUFFER_LENGTH], *ptmp, *otmp = NULL;
+ int i;
+ t_device *new;
+
+ strcpy(tmp, desc);
+ if ((ptmp = backslashed_strchr(tmp, ':'))) {
+ *ptmp++ = 0;
+
+ /* look for options */
+ if ((otmp = strchr(tmp, '+'))) *otmp++ = 0;
+
+ /* find corresponding source */
+ for (i = 0; sourcestype[i].name; i++)
+ if (!strcmp(tmp, sourcestype[i].name)) break;
+ if (!sourcestype[i].name) {
+ /* not found, error */
+ error("can't find source type %s (%s:%s)", tmp, tmp, ptmp);
+ return (0);
+ }
+ }
+ else {
+ error("no source type specified");
+ return (0);
+ }
+
+ /* allocate memory for new device */
+ new = MALLOC(sizeof(*new));
+ new->opened = &sourcestype[i];
+ if (new->opened->open) {
+ if (!(new->env = new->opened->open(ptmp, otmp))) {
+ error("can't open '%s'", desc);
+ FREE(new);
+ return (0);
+ }
+ if (new->opened->fcntl)
+ Sorted |= (new->opened->fcntl(new->env, IS_SORTED) ? OUTPUT_SORTED : 0);
+ }
+ else
+ new->env = NULL;
+ SIMPLE_LIST_PUSH(out->outputs, new);
+ return (1);
+}
+
+t_db_output *output_alloc() {
+ t_db_output *out;
+
+ out = MALLOC(sizeof(*out));
+ bzero(out, sizeof(*out));
+ return (out);
+}
+
+t_db_output *output_free(t_db_output *old) {
+ t_device *dst;
+
+ while (old->outputs) {
+ dst = SIMPLE_LIST_POP(old->outputs);
+ if (dst->opened->close)
+ dst->opened->close(dst->env);
+ FREE(dst);
+ }
+ FREE(old);
+ return (NULL);
+}
+
diff --git a/flx/output.h b/flx/output.h
new file mode 100644
index 0000000..0609357
--- /dev/null
+++ b/flx/output.h
@@ -0,0 +1,33 @@
+#ifndef __OUTPUT_H__
+#define __OUTPUT_H__
+
+#include "source_type.h"
+
+//#define DOFREE (1<<0)
+//#define DOFLUSH (1<<1)
+//#define DOINIT (1<<2)
+//#define GOSUBTREE (1<<3)
+//#define GOBASE (1<<4)
+//#define GOPARENT (1<<5)
+
+typedef struct s_db_output t_db_output;
+
+struct s_db_output {
+ void *outputs; /* list of output destination */
+};
+
+extern int output_write(t_db_output *out, void *tree, int number);
+extern t_db_output *output_alloc();
+extern t_db_output *output_free(t_db_output *old);
+extern int output_add(t_db_output *out, char *desc, t_source_type *sourcestype);
+
+int ft_foreach(void *data, t_ft *tree, int flag, int (*fct_doit)());
+
+int ft_free(t_ft *tree, void *(*fct_free)(void *data, void *desc), void *data);
+t_file_desc *fct_free_file_desc(void *data, t_file_desc *desc);
+
+#endif /* __OUTPUT_H__ */
+
+
+
+
diff --git a/flx/output_file.c b/flx/output_file.c
new file mode 100644
index 0000000..cbfed4e
--- /dev/null
+++ b/flx/output_file.c
@@ -0,0 +1,267 @@
+#include <stdlib.h>
+#include <string.h>
+#include "flx.h"
+#include "output_file.h"
+#include "input_file.h"
+#include "check.h"
+#include "output.h"
+
+#define STAT_WRITESUBDIR (1<<0)
+#define STAT_DOINIT (1<<1)
+#define STAT_VIEWSORTED (1<<2)
+
+#define OPT_SORTED 0x01
+#define OPT_WRITE 0x02
+
+/* affiche le contenu d'un répertoire à partir de l'emplacement spécifié en
+ * reprenant son nom
+ */
+int output_file_write_(t_file_status *desc, t_ft *tree,
+ int number, char *(*desc_to_str)()) {
+ char *pcpath, *pbpath;
+ int count = 0;
+
+ /* output initialization */
+ if (IS(desc->status, STAT_DOINIT)) {
+ UNSET(desc->status, STAT_DOINIT);
+ }
+
+ /* nothing have change, do not free */
+ if (number > 0 &&
+ IS(Sorted, OUTPUT_SORTED) && !IS(Sorted, INPUT_SORTED)) return (0);
+
+ /* initialize path pointers */
+ pcpath = desc->cpath + strlen(desc->cpath);
+ pbpath = desc->bpath + strlen(desc->bpath);
+
+ tree = ft_get(tree, desc->cpath);
+ /* find a valid directory */
+ while (!IS(tree->status, CHANGED) && SIMPLE_LIST_NEXT(desc->fdstack)) {
+ pcpath = REMOVE_DIR(desc->cpath, pcpath); *pcpath = 0;
+ pbpath = REMOVE_DIR(desc->bpath, pbpath); *pbpath = 0;
+ desc->recursion--;
+ tree = tree->parent;
+ }
+
+ /* start from changed subdirectory */
+ if (!tree->subtree || !IS(tree->status, CHANGED) || IS(tree->status, SORTING)) {
+ return (0);
+ }
+ tree = tree->subtree->next;
+
+ while (desc->fdstack) {
+
+ /* write all in the subdirectory */
+ while (!IS(tree->status, BASE)) {
+
+ /* nothing to do, pass */
+ if (!IS(tree->status, CHANGED)) { tree = tree->next; continue; }
+
+ /* the status have change, something to do with it, update path */
+ ADD_PATH(desc->cpath, pcpath, tree->filename);
+
+ /* filename have been newly filled */
+ if (IS(tree->status, FILLED)) {
+ char *str = desc_to_str(desc->cpath, pcpath, tree->desc);
+ if (str) {
+ fprintf(desc->fd, "%s\n", str);
+ count++;
+ }
+ }
+
+ /* stop recursion when an output is sorted and
+ * and this directory isn't finished to fill */
+ if (number > 0 &&
+ IS(desc->status, STAT_VIEWSORTED) && IS(tree->status, SORTING)) {
+ *pcpath = 0;
+ return (count);
+ }
+
+ /* treat sub directory, not for back pointers (. and ..) */
+ if (tree->subtree && !IS_DOTF(tree->filename)) {
+
+ /* add backup file descriptor for this level */
+ SIMPLE_LIST_PUSH(desc->fdstack, desc->fd);
+
+ /* backup directory filename and new position */
+ pcpath += strlen(pcpath);
+
+ if (desc->recursion > 0) {
+ FILE *newfd;
+
+ /* build new path, and new fd and so continue */
+ pbpath = ADD_PATH(desc->bpath, pbpath, tree->filename);
+
+ if (mkdir_with_parent(desc->bpath, ~GET_UMASK() & 0777)) {
+ /* open new fd for this directory */
+ ADD_PATH(desc->bpath, pbpath, DUMPBASENAME);
+ if (!(newfd = fopen(desc->bpath, "w")))
+ PFERROR("fopen(%s)", desc->bpath);
+ else
+ desc->fd = newfd;
+ }
+ /* remove filename from bpath */
+ *pbpath = 0;
+
+ }
+
+ /* recursion level (can be negative) */
+ desc->recursion--;
+
+ /* go subtree */
+ tree = tree->subtree->next;
+
+ continue;
+ }
+
+ /* look for next */
+ tree = tree->next;
+ }
+ /* remove added filenames */
+ *pcpath = 0;
+
+ /* verify that all files are readed */
+ if (number > 0 &&
+ IS(tree->parent->status, READING)) return (count);
+
+ /* search old path */
+ pcpath = REMOVE_DIR(desc->cpath, pcpath); *pcpath = 0;
+
+ /* recursion level : up */
+ desc->recursion++;
+ /* if recursion level, can close old fd */
+ if (desc->recursion > 0) {
+ pbpath = REMOVE_DIR(desc->bpath, pbpath); *pbpath = 0;
+ fclose(desc->fd);
+ }
+
+ /* get last fd */
+ desc->fd = SIMPLE_LIST_POP(desc->fdstack);
+
+ /* restore backuped position */
+ tree = tree->parent->next;
+ }
+ return (count);
+}
+
+int output_file_write(t_file_status *desc, t_ft *tree, int number) {
+ return (output_file_write_(desc, tree, number, build_line));
+}
+
+
+/* traduct a string options descriptions to flags
+ */
+int output_file_fcntl(t_file_status *env, int cmd) {
+ return (0);
+}
+
+
+t_file_status *output_file_open(char *pathname, char *opts) {
+ t_file_status *new;
+ char *filename;
+ int status, ret;
+ char tmp[BUFFER_LENGTH];
+ char *ppath, *popts, *pvalue;
+ int options = (OPT_SORTED|OPT_WRITE);
+
+ popts = opts ? strcpy(tmp, opts) : NULL;
+ ppath = pathname ? strcpy(tmp + strlen(tmp) + 1, pathname) : NULL;
+
+ /* memory allocation for new element */
+ new = MALLOC(sizeof(*new));
+ bzero(new, sizeof(*new));
+ new->recursion = 0;
+
+ /* part to get source specific options */
+ while (popts) {
+ int sign = 1;
+ char *t;
+
+ /* select an option and its value */
+ if ((t = strchr(popts, '+'))) *t++ = 0;
+ if ((pvalue = strchr(popts, '='))) *pvalue++ = 0;
+
+ /* remove negative */
+ while (*popts == '!') { sign = -sign ; popts++; }
+
+ /* treat option */
+ if (!*popts) continue;
+ else if (!strcmp(popts, "sort")) /* sorted flag */
+ options = (sign > 0 ? (options|OPT_SORTED) : (options&~OPT_SORTED));
+ else if (!strcmp(popts, "level") && pvalue) /* recurse level */
+ new->recursion = atoi(pvalue);
+ else {
+ error("unknown option : %s", popts);
+ FREE(new);
+ return (0);
+ }
+ popts = t;
+ }
+
+ filename = ppath;
+ if (ppath && (ppath = backslashed_strmchr(ppath, DELIM_LIST))) {
+ status = *ppath++;
+ }
+
+ SET(new->status, STAT_VIEWSORTED); /* default is sorted */
+ SET(new->status, STAT_DOINIT);
+
+ if (!filename || !filename[0] || !strcmp(filename, "-")) {
+ /* special case for stdout */
+ new->fd = stdout;
+ }
+ else {
+ struct stat st;
+ /* case for files, should stat them */
+ if (!(ret = stat(filename, &st)) && S_ISDIR(st.st_mode)) {
+ /* directory, directory treatment */
+
+ /* build base filename path */
+ strcpy(new->bpath, filename);
+ filename = new->bpath + strlen(new->bpath);
+ ADD_PATH(new->bpath, filename, DUMPBASENAME);
+ /* open the file */
+ if (!(new->fd = fopen(new->bpath, "w"))) {
+ PFERROR("fopen(%s)", new->bpath);
+ exit(3);
+ }
+ *filename = 0;
+ }
+ else {
+ /* can get confirmation */
+ /* can test and open */
+ if (!(new->fd = fopen(filename, "w"))) {
+ PFERROR("fopen(%s)", filename);
+ exit(3);
+ }
+ }
+ }
+ /* initialise file descriptor stack */
+ new->fdstack = NULL;
+ SIMPLE_LIST_PUSH(new->fdstack, new->fd);
+
+ return (new);
+}
+
+t_file_status *output_file_close(t_file_status *old) {
+ while (old->fdstack && old->recursion < 0) {
+ SIMPLE_LIST_POP(old->fdstack);
+ old->recursion--;
+ }
+ if (old->fd && old->fd != stdout) fclose(old->fd);
+ while (old->fdstack) {
+ old->fd = SIMPLE_LIST_POP(old->fdstack);
+ fclose(old->fd);
+ }
+ FREE(old);
+ return (NULL);
+}
+
+t_file_status *output_stdout_open(char *desc, char *opts) {
+ if ((desc = backslashed_strmchr(desc, DELIM_LIST)))
+ return (output_file_open(desc, opts));
+ return (output_file_open("", opts));
+}
+
+
+
diff --git a/flx/output_file.h b/flx/output_file.h
new file mode 100644
index 0000000..74e78e2
--- /dev/null
+++ b/flx/output_file.h
@@ -0,0 +1,20 @@
+#ifndef __OUTPUT_FILE_H__
+#define __OUTPUT_FILE_H__
+
+#include "flx.h"
+#include "input_file.h"
+#include "flx_fcntl.h"
+
+extern int output_file_fcntl(t_file_status *env, int cmd);
+
+extern int output_file_write_(t_file_status *spec, t_ft *tree, int number, char *(*fct)());
+extern int output_file_write(t_file_status *spec, t_ft *tree, int number);
+extern t_file_status *output_file_open(char *desc, char *opts);
+extern t_file_status *output_file_close(t_file_status *spec);
+
+extern t_file_status *output_stdout_open(char *desc, char *opts);
+
+
+#endif /* __OUTPUT_FILE_H__ */
+
+
diff --git a/flx/sign.c b/flx/sign.c
new file mode 100644
index 0000000..146a8a0
--- /dev/null
+++ b/flx/sign.c
@@ -0,0 +1,117 @@
+#include <stdio.h>
+#include "input.h"
+#include "output.h"
+#include "source_type.h"
+#include "arg.h"
+#include "input_fs.h"
+#include "input_file.h"
+#include "output_file.h"
+
+/* source type have the form :
+ * [type[(type_options)]:]file[:origin1][=rewrite1],[origin2[=rewrite2]]
+ * if type isn't set, type = 'fs'
+ * the end of the string was treat by specific init function
+ * type_options : [!]type_option[,type_options]
+ * input fs specific options :
+ * - xdev : don't go across fs (default)
+ * - flw : follow symlinks links
+ * - depth : directory depth to walk
+ * output file tree specific options :
+ * - level=N : subdirectory level to create
+ * output specific options :
+ * - long : human readable form
+ */
+
+/* command line is:
+ * ./flx sign [options] [inputs]
+ * options are :
+ * -h,--help : this help
+ */
+
+
+static t_source_type InputTypes[] = {
+ { "fs",
+ (void*)input_fs_open, (void*)input_fs_read, NULL, (void*)input_fs_close,
+ (void*)input_fs_fcntl },
+ { "file",
+ (void*)input_file_open, (void*)input_file_read, NULL, (void*)input_file_close,
+ (void*)input_file_fcntl },
+ { "stdin",
+ (void*)input_stdin_open, (void*)input_file_read, NULL, (void*)input_file_close,
+ (void*)input_file_fcntl },
+ { NULL }
+};
+static t_source_type OutputTypes[] = {
+ { "file",
+ (void*)output_file_open, NULL, (void*)output_file_write, (void*)output_file_close,
+ (void*)output_file_fcntl },
+ { "stdout",(void*)output_stdout_open, NULL, (void*)output_file_write, (void*)output_file_close,
+ (void*)output_file_fcntl },
+ { NULL }
+};
+
+static void *SignOutput = NULL, *SignInput = NULL;
+
+
+#define O_HELP 1
+#define O_OUTPUT 2
+#define O_IGN_DOT 3
+#define O_IGN_DEPTH 4
+
+t_param flxsign_poptions[] = {
+ { 'h', "help", O_HELP, 0,
+ "-h,--help show this help"},
+ { 'o', "output", O_OUTPUT, 1,
+ "-o,--output <file> select output"},
+ { 0, "ignore-dot", O_IGN_DOT, 0,
+ "--ignore-dot do not store '.' and '..'" },
+ { 0, "no-depth", O_IGN_DEPTH, 0,
+ "--no-depth do not run across directories" },
+ { 0, NULL, 0 }
+} ;
+
+int flxsign_pfct(int opt, t_param *param, char **flag, char **argv) {
+ if (opt == O_HELP) arg_usage(flxsign_poptions, NULL);
+ else if (opt == O_OUTPUT) {
+ if (!SignOutput) SignOutput = output_alloc();
+ output_add(SignOutput, argv[1], OutputTypes);
+ }
+ else if (opt == O_IGN_DOT) SET(Options, GOPT_IGNORE_DOT);
+ else if (opt == O_IGN_DEPTH) SET(Options, GOPT_IGNORE_DEPTH);
+ else if (opt == -1) {
+ if (!SignInput) SignInput = input_alloc();
+ input_add(SignInput, *argv, InputTypes);
+ }
+ else return (-1);
+ return (param ? param->minarg : 0);
+}
+
+
+int flxsign_main(int argc, char **argv) {
+ t_ft Root = { &Root, &Root, &Root /* parent */, NULL /* subtree */ ,
+ NULL /* filename */, NULL /* desc */, BASE|CHANGED /* status */ };
+ int nb;
+
+ if (!SignInput) {
+ SignInput = input_alloc();
+ input_add(SignInput, "fs:.", InputTypes);
+ }
+
+ if (!SignOutput) {
+ SignOutput = output_alloc();
+ output_add(SignOutput, "stdout:", OutputTypes);
+ }
+
+ while ((nb = input_read(SignInput, &Root))) {
+ output_write(SignOutput, &Root, nb);
+ ft_free(&Root, (void*)fct_free_file_desc, NULL);
+ }
+ output_write(SignOutput, &Root, 0);
+ ft_free(&Root, (void*)fct_free_file_desc, NULL);
+
+ output_free(SignOutput);
+ input_free(SignInput);
+ return (0);
+}
+
+
diff --git a/flx/sign.h b/flx/sign.h
new file mode 100644
index 0000000..047ee85
--- /dev/null
+++ b/flx/sign.h
@@ -0,0 +1,14 @@
+#ifndef __SIGN_H__
+#define __SIGN_H__
+
+#include "arg.h"
+
+extern t_param flxsign_poptions[];
+
+extern int flxsign_pfct(int opt, t_param *param, char **flag, char **argv);
+extern int flxsign_main(int argc, char **argv);
+
+
+#endif /* __SIGN_H__ */
+
+
diff --git a/flx/source_type.h b/flx/source_type.h
new file mode 100644
index 0000000..dbd98fd
--- /dev/null
+++ b/flx/source_type.h
@@ -0,0 +1,29 @@
+#ifndef __SOURCE_TYPE_H__
+#define __SOURCE_TYPE_H__
+
+#include "flx.h"
+
+
+/* struct definition for all type of source */
+typedef struct s_source_type t_source_type;
+struct s_source_type {
+ char *name;
+
+ void *(*open)(char *str_desc, char *opts);
+ int (*read)(void *desc, t_ft *tree);
+ int (*write)(void *desc, t_ft *tree, int number);
+ void *(*close)(void *desc);
+ int (*fcntl)(void *env, int cmd);
+};
+
+
+/* device environnement */
+typedef struct s_device t_device;
+
+struct s_device {
+ t_source_type *opened;
+ void *env;
+};
+
+
+#endif /* __SOURCE_TYPE_H__ */
diff --git a/flx/utils.c b/flx/utils.c
new file mode 100644
index 0000000..96a52ae
--- /dev/null
+++ b/flx/utils.c
@@ -0,0 +1,147 @@
+#include <string.h>
+#include <stdio.h>
+#include <dirent.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <stdarg.h>
+
+#include "utils.h"
+
+POOL_INIT(p2void);
+
+// fonction to return write in 'ls -l' format
+char *right(mode_t m) {
+ static char dsc[10];
+ dsc[0]=(m&S_IRUSR)?'r':'-';
+ dsc[1]=(m&S_IWUSR)?'w':'-';
+ dsc[2]=(m&S_IXUSR)?'x':'-';
+ dsc[3]=(m&S_IRGRP)?'r':'-';
+ dsc[4]=(m&S_IWGRP)?'w':'-';
+ dsc[5]=(m&S_IXGRP)?'x':'-';
+ dsc[6]=(m&S_IROTH)?'r':'-';
+ dsc[7]=(m&S_IWOTH)?'w':'-';
+ dsc[8]=(m&S_IXOTH)?'x':'-';
+ dsc[9]=0;
+ return(dsc);
+}
+
+// return directory name of a [path/]filename string
+// the return value is in static value
+char *dirname(char *str) {
+ static char tmp[8192],*p;
+ strcpy(tmp,str);
+ if ((p=strrchr(tmp,'/'))) return (*p=0,tmp);
+ return (NULL);
+}
+
+// return the filename of a [path/]filename string
+char *basename(char *str) {
+ static char *p;
+ if (!(p=strrchr(str,'/'))) return str;
+ return (p+1);
+}
+
+int fatal_error(char *message, ...) {
+ va_list argp;
+ char buff[BUFFLEN];
+
+ va_start(argp,message);
+ vsnprintf(buff,BUFFLEN,message,argp);
+ va_end(argp);
+ write(2, "Fatal: ", 7);
+ write(2, buff, strlen(buff));
+ write(2, "\n", 1);
+ exit (3);
+}
+
+int error(char *message, ...) {
+ va_list argp;
+ char buff[BUFFLEN];
+
+ va_start(argp,message);
+ vsnprintf(buff,BUFFLEN,message,argp);
+ va_end(argp);
+ write(2, "Error: ", 7);
+ write(2,buff,strlen(buff));
+ write(2, "\n", 1);
+ return (2);
+}
+
+void warning(char *message, ...) {
+ va_list argp;
+ char buff[BUFFLEN];
+
+ va_start(argp,message);
+ vsnprintf(buff,BUFFLEN,message,argp);
+ va_end(argp);
+ write(2, "Warning: ", sizeof("Warning: "));
+ write(2, buff, strlen(buff));
+ write(2, "\n", 1);
+ return ;
+}
+
+int pferror(char *message, ...) {
+ va_list argp;
+ char buff[BUFFLEN];
+
+ va_start(argp,message);
+ vsnprintf(buff,BUFFLEN,message,argp);
+ perror(buff);
+ va_end(argp);
+ return (2);
+}
+
+/* strchr but bybass backslash '\\' characters */
+char *backslashed_strchr(char *s, char c) {
+ while (*s) {
+ if (*s == '\\' && *(s+1)) s++;
+ else if (*s == c) return (s);
+ s++;
+ }
+ return (NULL);
+}
+
+/* strchr with multiple characters but bypass '\\' characters */
+char *backslashed_strmchr(char *s, char *mc) {
+ char *c;
+
+ while (*s) {
+ if (*s == '\\' && *(s+1)) s++;
+ else
+ for (c = mc; *c ; c++)
+ if (*s == *c) return (s);
+ s++;
+ }
+ return (NULL);
+}
+
+/* return the string with characters 'toback' backslashed */
+char *backslashed_str(char *s, char *toback) {
+ static char buff[BUFFLEN];
+ char *pbuff = buff;
+
+ while (*s) {
+ if (strchr(toback, *s)) {
+ *pbuff++ = '\\';
+ }
+ *pbuff++ = *s++;
+ }
+ *pbuff = 0;
+ return (buff);
+}
+
+void *push_str_sorted(void *ptr, char *str) {
+ void *c;
+
+ if (!ptr || strcmp(str, SIMPLE_LIST_PTR(ptr)) < 0)
+ SIMPLE_LIST_PUSH(ptr, str);
+ else {
+ for (c = ptr; SIMPLE_LIST_NEXT(c) &&
+ strcmp(SIMPLE_LIST_NEXT_PTR(c), str) < 0 ;
+ c = SIMPLE_LIST_NEXT(c));
+ SIMPLE_LIST_PUSH(SIMPLE_LIST_NEXT(c), str);
+ }
+ return (ptr);
+}
+
diff --git a/flx/utils.h b/flx/utils.h
new file mode 100644
index 0000000..5c47333
--- /dev/null
+++ b/flx/utils.h
@@ -0,0 +1,187 @@
+
+#ifndef __UTILS_H__
+#define __UTILS_H__
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <malloc.h>
+#include <string.h>
+#include <stdio.h>
+
+#define BUFFER_LENGTH 8192
+#define FILENAME_LENGTH 4096
+
+#define MALLOC(size) ({ \
+ void *__var; \
+ if (!(__var = malloc(size))) { \
+ PFERROR("malloc(%d)", size); \
+ exit(2); \
+ } \
+ __var; \
+})
+
+#define CALLOC(nb, size) ({ \
+ void *__var; \
+ if (!(__var = calloc(nb, size))) { \
+ PFERROR("calloc(%d, %d)", nb, size); \
+ exit(2); \
+ } \
+ __var; \
+})
+
+#define FREE(ptr) free(ptr)
+
+#define STRDUP(str) ({ \
+ char *__var; \
+ if (!(__var = strdup(str))) { \
+ PFERROR("strdup(%s)", str); \
+ exit(2); \
+ } \
+ __var; \
+})
+
+#define GET_UMASK() ({mode_t __mask = umask(0); umask(__mask); __mask; })
+
+
+#define IS(v, f) (((v) & (f)) == (f))
+#define SET(v, f) ((v) |= (f))
+#define UNSET(v, f) ((v) &= ~(f))
+
+
+#ifndef __USE_BSD
+typedef unsigned int u_int;
+typedef unsigned char u_char;
+#endif
+
+
+#define BUFFLEN BUFFER_LENGTH
+
+#define PFERROR(str...) PFERROR2(##str, 0)
+#define PFERROR2(str, p...) pferror("%s:%d: " str, __FILE__, __LINE__, ##p)
+#define HEXTODEC(a) (('0'<=(a) && (a)<='9')?(a)-'0':(a)-'a'+10)
+
+
+#ifdef MEM_OPTIM
+/*
+ * Returns a pointer to type <type> taken from the
+ * pool <pool_type> or dynamically allocated. In the
+ * first case, <pool_type> is updated to point to the
+ * next element in the list.
+ */
+#define POOL_ALLOC(type) ({ \
+ void *p; \
+ if ((p = pool_##type) == NULL) \
+ p = malloc(sizeof(##type)); \
+ else { \
+ pool_##type = *(void **)pool_##type; \
+ } \
+ p; \
+})
+
+/*
+ * Puts a memory area back to the corresponding pool.
+ * Items are chained directly through a pointer that
+ * is written in the beginning of the memory area, so
+ * there's no need for any carrier cell. This implies
+ * that each memory area is at least as big as one
+ * pointer.
+ */
+#define POOL_FREE(type, ptr) ({ \
+ *(void **)ptr = (void *)pool_##type; \
+ pool_##type = (void *)ptr; \
+})
+#define POOL_INIT(type) type *pool_##type = NULL
+#define POOL_INIT_PROTO(type) extern type *pool_##type
+
+#else
+#define POOL_ALLOC(type) (calloc(1,sizeof(##type)));
+#define POOL_FREE(type, ptr) (free(ptr));
+#define POOL_INIT
+#endif /* MEM_OPTIM */
+
+
+typedef void *p2void[2];
+
+/* initialise memory pool for list managing */
+
+#define PUSH_STR_SORTED(ptr, str) (ptr = push_str_sorted(ptr, str))
+
+/* unusable!!!
+ * #define SIMPLE_LIST_FOREACH(list, data, current, next) \
+ * for(current = list; \
+ * (next = SIMPLE_LIST_NEXT(current), data = SIMPLE_LIST_PTR(current), current); \
+ * current = next)
+ */
+
+#define SIMPLE_LIST_FLUSH(list) ( { \
+ while (list) SIMPLE_LIST_POP(list); \
+})
+
+#define SIMPLE_LIST_NEXT_PTR(list) (SIMPLE_LIST_PTR(SIMPLE_LIST_NEXT(list)))
+#define SIMPLE_LIST_NEXT(list) (*(((void**)(list))))
+#define SIMPLE_LIST_PTR(list) (*(((void**)(list)) + 1))
+#define SIMPLE_LIST_INIT() POOL_INIT(p2void)
+
+#define SIMPLE_LIST_PUSH(list, elem) ( { \
+ void **__new; \
+ __new = POOL_ALLOC(p2void); \
+ __new[0] = (void*)(list); \
+ __new[1] = (void*)(elem); \
+ (list) = (void *)__new; \
+})
+
+#define SIMPLE_LIST_FILE(list, elem) ( { \
+ void **__next = list; \
+ if (!list) { \
+ __next = POOL_ALLOC(p2void); \
+ (list) = (void*)__next; \
+ } else { \
+ while (SIMPLE_LIST_NEXT(__next)) __next = SIMPLE_LIST_NEXT(__next); \
+ SIMPLE_LIST_NEXT(__next) = POOL_ALLOC(p2void); \
+ __next = SIMPLE_LIST_NEXT(__next); \
+ } \
+ __next[0] = NULL; \
+ __next[1] = (void*)(elem); \
+} )
+
+
+#define SIMPLE_LIST_DEFILE(list) SIMPLE_LIST_POP(list)
+#define SIMPLE_LIST_POP(list) ( { \
+ void **__old = (void **)list, *__elem = NULL; \
+ if (list) { \
+ list = __old[0]; \
+ __elem = __old[1]; \
+ POOL_FREE(p2void, __old); \
+ } \
+ __elem ; \
+})
+
+
+#define LIST_CHAIN(pprev, pnew, pnext) ({ \
+ (pnew)->prev = pprev; \
+ (pnew)->next = pnext; \
+ (pnew)->prev->next = pnew; \
+ (pnew)->next->prev = pnew; \
+})
+
+#define LIST_UNCHAIN(pold) ({ \
+ (pold)->prev->next = (pold)->next; \
+ (pold)->next->prev = (pold)->prev; \
+})
+
+
+POOL_INIT_PROTO(p2void);
+
+char *right(mode_t mode);
+char *dirname(char *);
+char *basename(char *);
+int error(char *,...);
+void warning(char *,...);
+int fatal_error(char *,...);
+int pferror(char *,...);
+char *backslashed_strchr(char *s, char c);
+char *backslashed_strmchr(char *s, char *mc);
+char *backslashed_str(char *, char *toback);
+void *push_str_sorted(void *ptr, char *str);
+
+#endif /* __UTILS_H__ */
diff --git a/ifenslave/Makefile b/ifenslave/Makefile
new file mode 100644
index 0000000..3a7ec80
--- /dev/null
+++ b/ifenslave/Makefile
@@ -0,0 +1,16 @@
+OBJS=ifenslave
+include ../../include/rules.make
+CC=gcc
+CFLAGS+=-Wstrict-prototypes -I/usr/src/linux/include -momit-leaf-frame-pointer
+
+all: $(OBJS)
+
+ifenslave: ifenslave.o
+ $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $<
+ strip -R .comment -R .note $@
+ objdump -h $@ | grep -q '\.data[ ]*00000000' && strip -R .data $@ || true
+ # sstrip $@
+
+%.o: %.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
diff --git a/ifenslave/ifenslave.c b/ifenslave/ifenslave.c
new file mode 100644
index 0000000..18e1ec0
--- /dev/null
+++ b/ifenslave/ifenslave.c
@@ -0,0 +1,652 @@
+/* Mode: C;
+ * ifenslave.c: Configure network interfaces for parallel routing.
+ *
+ * This program controls the Linux implementation of running multiple
+ * network interfaces in parallel.
+ *
+ * Usage: ifenslave [-v] master-interface < slave-interface [metric <N>] > ...
+ *
+ * Author: Donald Becker <becker@cesdis.gsfc.nasa.gov>
+ * Copyright 1994-1996 Donald Becker
+ *
+ * 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.
+ *
+ * The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
+ * Center of Excellence in Space Data and Information Sciences
+ * Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
+ *
+ * Changes :
+ * - 2000/10/02 Willy Tarreau <willy at meta-x.org> :
+ * - few fixes. Master's MAC address is now correctly taken from
+ * the first device when not previously set ;
+ * - detach support : call BOND_RELEASE to detach an enslaved interface.
+ * - give a mini-howto from command-line help : # ifenslave -h
+ *
+ * - 2001/02/16 Chad N. Tindel <ctindel at ieee dot org> :
+ * - Master is now brought down before setting the MAC address. In
+ * the 2.4 kernel you can't change the MAC address while the device is
+ * up because you get EBUSY.
+ *
+ * - 2001/09/13 Takao Indoh <indou dot takao at jp dot fujitsu dot com>
+ * - Added the ability to change the active interface on a mode 1 bond
+ * at runtime.
+ *
+ * - 2001/10/23 Chad N. Tindel <ctindel at ieee dot org> :
+ * - No longer set the MAC address of the master. The bond device will
+ * take care of this itself
+ * - Try the SIOC*** versions of the bonding ioctls before using the
+ * old versions
+ * - 2002/02/18 Erik Habbinga <erik_habbinga @ hp dot com> :
+ * - ifr2.ifr_flags was not initialized in the hwaddr_notset case,
+ * SIOCGIFFLAGS now called before hwaddr_notset test
+ *
+ * - 2002/10/31 Tony Cureington <tony.cureington * hp_com> :
+ * - If the master does not have a hardware address when the first slave
+ * is enslaved, the master is assigned the hardware address of that
+ * slave - there is a comment in bonding.c stating "ifenslave takes
+ * care of this now." This corrects the problem of slaves having
+ * different hardware addresses in active-backup mode when
+ * multiple interfaces are specified on a single ifenslave command
+ * (ifenslave bond0 eth0 eth1).
+ *
+ */
+
+static char *version =
+"ifenslave.c:v0.07 9/9/97 Donald Becker (becker@cesdis.gsfc.nasa.gov).\n"
+"detach support added on 2000/10/02 by Willy Tarreau (willy at meta-x.org).\n"
+"2.4 kernel support added on 2001/02/16 by Chad N. Tindel (ctindel at ieee dot org.\n";
+
+static const char *usage_msg =
+"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n"
+" ifenslave -c master-interface slave-if\n";
+
+static const char *howto_msg =
+"Usage: ifenslave [-adfrvVh] <master-interface> < <slave-if> [metric <N>] > ...\n"
+" ifenslave -c master-interface slave-if\n"
+"\n"
+" To create a bond device, simply follow these three steps :\n"
+" - ensure that the required drivers are properly loaded :\n"
+" # modprobe bonding ; modprobe <3c59x|eepro100|pcnet32|tulip|...>\n"
+" - assign an IP address to the bond device :\n"
+" # ifconfig bond0 <addr> netmask <mask> broadcast <bcast>\n"
+" - attach all the interfaces you need to the bond device :\n"
+" # ifenslave bond0 eth0 eth1 eth2\n"
+" If bond0 didn't have a MAC address, it will take eth0's. Then, all\n"
+" interfaces attached AFTER this assignment will get the same MAC addr.\n"
+"\n"
+" To detach a dead interface without setting the bond device down :\n"
+" # ifenslave -d bond0 eth1\n"
+"\n"
+" To set the bond device down and automatically release all the slaves :\n"
+" # ifconfig bond0 down\n"
+"\n"
+" To change active slave :\n"
+" # ifenslave -c bond0 eth0\n"
+"\n";
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <ctype.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <linux/if.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/if_bonding.h>
+#include <linux/sockios.h>
+
+struct option longopts[] = {
+ /* { name has_arg *flag val } */
+ {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */
+ {"force", 0, 0, 'f'}, /* Force the operation. */
+ {"help", 0, 0, '?'}, /* Give help */
+ {"howto", 0, 0, 'h'}, /* Give some more help */
+ {"receive-slave", 0, 0, 'r'}, /* Make a receive-only slave. */
+ {"verbose", 0, 0, 'v'}, /* Report each action taken. */
+ {"version", 0, 0, 'V'}, /* Emit version information. */
+ {"detach", 0, 0, 'd'}, /* Detach a slave interface. */
+ {"change-active", 0, 0, 'c'}, /* Change the active slave. */
+ { 0, 0, 0, 0 }
+};
+
+/* Command-line flags. */
+unsigned int
+opt_a = 0, /* Show-all-interfaces flag. */
+opt_f = 0, /* Force the operation. */
+opt_r = 0, /* Set up a Rx-only slave. */
+opt_d = 0, /* detach a slave interface. */
+opt_c = 0, /* change-active-slave flag. */
+verbose = 0, /* Verbose flag. */
+opt_version = 0,
+opt_howto = 0;
+int skfd = -1; /* AF_INET socket for ioctl() calls. */
+
+static void if_print(char *ifname);
+
+int
+main(int argc, char **argv)
+{
+ struct ifreq ifr2, if_hwaddr, if_ipaddr, if_metric, if_mtu, if_dstaddr;
+ struct ifreq if_netmask, if_brdaddr, if_flags;
+ int goterr = 0;
+ int c, errflag = 0;
+ sa_family_t master_family;
+ char **spp, *master_ifname, *slave_ifname;
+ int hwaddr_notset;
+ int master_up;
+
+ while ((c = getopt_long(argc, argv, "acdfrvV?h", longopts, 0)) != EOF)
+ switch (c) {
+ case 'a': opt_a++; break;
+ case 'f': opt_f++; break;
+ case 'r': opt_r++; break;
+ case 'd': opt_d++; break;
+ case 'c': opt_c++; break;
+ case 'v': verbose++; break;
+ case 'V': opt_version++; break;
+ case 'h': opt_howto++; break;
+ case '?': errflag++;
+ }
+
+ /* option check */
+ if (opt_c)
+ if(opt_a || opt_f || opt_r || opt_d || verbose || opt_version ||
+ opt_howto || errflag ) {
+ fprintf(stderr, usage_msg);
+ return 2;
+ }
+
+ if (errflag) {
+ fprintf(stderr, usage_msg);
+ return 2;
+ }
+
+ if (opt_howto) {
+ fprintf(stderr, howto_msg);
+ return 0;
+ }
+
+ if (verbose || opt_version) {
+ printf(version);
+ if (opt_version)
+ exit(0);
+ }
+
+ /* Open a basic socket. */
+ if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
+ perror("socket");
+ exit(-1);
+ }
+
+ if (verbose)
+ fprintf(stderr, "DEBUG: argc=%d, optind=%d and argv[optind] is %s.\n",
+ argc, optind, argv[optind]);
+
+ /* No remaining args means show all interfaces. */
+ if (optind == argc) {
+ if_print((char *)NULL);
+ (void) close(skfd);
+ exit(0);
+ }
+
+ /* Copy the interface name. */
+ spp = argv + optind;
+ master_ifname = *spp++;
+ slave_ifname = *spp++;
+
+ /* Check command line. */
+ if (opt_c) {
+ char **tempp = spp;
+ if ((master_ifname == NULL)||(slave_ifname == NULL)||(*tempp++ != NULL)) {
+ fprintf(stderr, usage_msg);
+ return 2;
+ }
+ }
+
+ /* A single args means show the configuration for this interface. */
+ if (slave_ifname == NULL) {
+ if_print(master_ifname);
+ (void) close(skfd);
+ exit(0);
+ }
+
+ /* Get the vitals from the master interface. */
+ {
+ struct ifreq *ifra[7] = { &if_ipaddr, &if_mtu, &if_dstaddr,
+ &if_brdaddr, &if_netmask, &if_flags,
+ &if_hwaddr };
+ const char *req_name[7] = {
+ "IP address", "MTU", "destination address",
+ "broadcast address", "netmask", "status flags",
+ "hardware address" };
+ const int ioctl_req_type[7] = {
+ SIOCGIFADDR, SIOCGIFMTU, SIOCGIFDSTADDR,
+ SIOCGIFBRDADDR, SIOCGIFNETMASK, SIOCGIFFLAGS,
+ SIOCGIFHWADDR };
+ int i;
+
+ for (i = 0; i < 7; i++) {
+ strncpy(ifra[i]->ifr_name, master_ifname, IFNAMSIZ);
+ if (ioctl(skfd, ioctl_req_type[i], ifra[i]) < 0) {
+ fprintf(stderr,
+ "Something broke getting the master's %s: %s.\n",
+ req_name[i], strerror(errno));
+ }
+ }
+
+ hwaddr_notset = 1; /* assume master's address not set yet */
+ for (i = 0; hwaddr_notset && (i < 6); i++) {
+ hwaddr_notset &= ((unsigned char *)if_hwaddr.ifr_hwaddr.sa_data)[i] == 0;
+ }
+
+ /* The family '1' is ARPHRD_ETHER for ethernet. */
+ if (if_hwaddr.ifr_hwaddr.sa_family != 1 && !opt_f) {
+ fprintf(stderr, "The specified master interface '%s' is not"
+ " ethernet-like.\n This program is designed to work"
+ " with ethernet-like network interfaces.\n"
+ " Use the '-f' option to force the operation.\n",
+ master_ifname);
+
+ exit (1);
+ }
+ master_family = if_hwaddr.ifr_hwaddr.sa_family;
+ if (verbose) {
+ unsigned char *hwaddr = (unsigned char *)if_hwaddr.ifr_hwaddr.sa_data;
+ printf("The current hardware address (SIOCGIFHWADDR) of %s is type %d "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", master_ifname,
+ if_hwaddr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1],
+ hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]);
+ }
+ }
+
+
+ /* do this when enslaving interfaces */
+ do {
+ if (opt_d) { /* detach a slave interface from the master */
+ strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ);
+ strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ);
+ if ((ioctl(skfd, SIOCBONDRELEASE, &if_flags) < 0) &&
+ (ioctl(skfd, BOND_RELEASE_OLD, &if_flags) < 0)) {
+ fprintf(stderr, "SIOCBONDRELEASE: cannot detach %s from %s. errno=%s.\n",
+ slave_ifname, master_ifname, strerror(errno));
+ }
+ else { /* we'll set the interface down to avoid any conflicts due to
+ same IP/MAC */
+ strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ);
+ if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) {
+ int saved_errno = errno;
+ fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname,
+ strerror(saved_errno));
+ }
+ else {
+ ifr2.ifr_flags &= ~(IFF_UP | IFF_RUNNING);
+ if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) {
+ int saved_errno = errno;
+ fprintf(stderr, "Shutting down interface %s failed: %s\n",
+ slave_ifname, strerror(saved_errno));
+ }
+ }
+ }
+ }
+ else { /* attach a slave interface to the master */
+ /* two possibilities :
+ - if hwaddr_notset, do nothing. The bond will assign the
+ hwaddr from it's first slave.
+ - if !hwaddr_notset, assign the master's hwaddr to each slave
+ */
+
+ strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ);
+ if (ioctl(skfd, SIOCGIFFLAGS, &ifr2) < 0) {
+ int saved_errno = errno;
+ fprintf(stderr, "SIOCGIFFLAGS on %s failed: %s\n", slave_ifname,
+ strerror(saved_errno));
+ return 1;
+ }
+
+ if (hwaddr_notset) {
+ /* assign the slave hw address to the
+ * master since it currently does not
+ * have one; otherwise, slaves may
+ * have different hw addresses in
+ * active-backup mode as seen when enslaving
+ * using "ifenslave bond0 eth0 eth1" because
+ * hwaddr_notset is set outside this loop.
+ * TODO: put this and the "else" portion in
+ * a function.
+ */
+ goterr = 0;
+ master_up = 0;
+ if (if_flags.ifr_flags & IFF_UP) {
+ if_flags.ifr_flags &= ~IFF_UP;
+ if (ioctl(skfd, SIOCSIFFLAGS,
+ &if_flags) < 0) {
+ goterr = 1;
+ fprintf(stderr,
+ "Shutting down "
+ "interface %s failed: "
+ "%s\n",
+ master_ifname,
+ strerror(errno));
+ } else {
+ /* we took the master down,
+