diff options
-rw-r--r-- | README | 20 | ||||
-rw-r--r-- | findcdrom/Makefile | 3 | ||||
-rwxr-xr-x | findcdrom/findcdrom | bin | 0 -> 924 bytes | |||
-rwxr-xr-x | findcdrom/findcdrom-debug | bin | 0 -> 6340 bytes | |||
-rw-r--r-- | findcdrom/findcdrom.c | 73 | ||||
-rw-r--r-- | flx/AUTHORS | 1 | ||||
l--------- | flx/COPYING | 1 | ||||
-rw-r--r-- | flx/ChangeLog | 9 | ||||
-rw-r--r-- | flx/LICENCE | 340 | ||||
-rw-r--r-- | flx/Makefile | 215 | ||||
-rw-r--r-- | flx/NOTES | 143 | ||||
-rw-r--r-- | flx/README | 20 | ||||
-rw-r--r-- | flx/TODO | 14 | ||||
-rw-r--r-- | flx/arg.c | 106 | ||||
-rw-r--r-- | flx/arg.h | 49 | ||||
-rw-r--r-- | flx/check.c | 556 | ||||
-rw-r--r-- | flx/check.h | 27 | ||||
-rw-r--r-- | flx/ctrl1 | 32 | ||||
-rw-r--r-- | flx/fct1.c | 452 | ||||
-rw-r--r-- | flx/flx.c | 115 | ||||
-rw-r--r-- | flx/flx.h | 264 | ||||
-rw-r--r-- | flx/flx_fcntl.h | 14 | ||||
l--------- | flx/flxcheck | 1 | ||||
l--------- | flx/flxsign | 1 | ||||
-rw-r--r-- | flx/input.c | 114 | ||||
-rw-r--r-- | flx/input.h | 24 | ||||
-rw-r--r-- | flx/input_file.c | 462 | ||||
-rw-r--r-- | flx/input_file.h | 34 | ||||
-rw-r--r-- | flx/input_fs.c | 332 | ||||
-rw-r--r-- | flx/input_fs.h | 29 | ||||
-rw-r--r-- | flx/main.c | 79 | ||||
-rw-r--r-- | flx/md5.c | 261 | ||||
-rw-r--r-- | flx/md5.h | 55 | ||||
-rw-r--r-- | flx/output.c | 157 | ||||
-rw-r--r-- | flx/output.h | 33 | ||||
-rw-r--r-- | flx/output_file.c | 267 | ||||
-rw-r--r-- | flx/output_file.h | 20 | ||||
-rw-r--r-- | flx/sign.c | 117 | ||||
-rw-r--r-- | flx/sign.h | 14 | ||||
-rw-r--r-- | flx/source_type.h | 29 | ||||
-rw-r--r-- | flx/utils.c | 147 | ||||
-rw-r--r-- | flx/utils.h | 187 | ||||
-rw-r--r-- | ifenslave/Makefile | 16 | ||||
-rw-r--r-- | ifenslave/ifenslave.c | 652 | ||||
-rw-r--r-- | include/rules.make | 20 | ||||
-rw-r--r-- | init/Makefile | 3 | ||||
-rw-r--r-- | init/README | 99 | ||||
-rwxr-xr-x | init/examples/cd_nofloppy | 58 | ||||
-rwxr-xr-x | init/examples/cd_preinit | 63 | ||||
-rwxr-xr-x | init/examples/cd_ramonly | 66 | ||||
-rwxr-xr-x | init/examples/hd_preinit | 60 | ||||
-rwxr-xr-x | init/init | bin | 0 -> 5620 bytes | |||
-rw-r--r-- | init/init.c | 1274 | ||||
-rwxr-xr-x | init/mkdev | bin | 0 -> 3156 bytes | |||
-rw-r--r-- | init/mkdev.c | 516 | ||||
-rwxr-xr-x | lcd/lcdtee | bin | 0 -> 684 bytes | |||
-rwxr-xr-x | lcd/lcdwrite | bin | 0 -> 812 bytes | |||
-rw-r--r-- | mii/Makefile | 16 | ||||
-rw-r--r-- | mii/libmii.c | 526 | ||||
-rw-r--r-- | mii/mii-diag.c | 457 | ||||
-rw-r--r-- | mii/starfire-diag.c | 640 | ||||
-rw-r--r-- | mii/tulip-diag.c | 1656 | ||||
-rw-r--r-- | mktmp/Makefile | 9 | ||||
-rwxr-xr-x | mktmp/mktmp | bin | 0 -> 1692 bytes | |||
-rw-r--r-- | mktmp/mktmp.c | 136 | ||||
-rw-r--r-- | remount/Makefile | 12 | ||||
-rwxr-xr-x | remount/remountr | bin | 0 -> 436 bytes | |||
-rw-r--r-- | remount/remountr.c | 25 | ||||
l--------- | remount/remountw | 1 | ||||
-rwxr-xr-x | scripts/flxadd | 350 | ||||
-rwxr-xr-x | scripts/flxfix | 85 | ||||
-rwxr-xr-x | scripts/noctrlaltdel | 20 | ||||
-rwxr-xr-x | scripts/pci-listall | 2 | ||||
-rwxr-xr-x | scripts/pcidev | 141 | ||||
-rwxr-xr-x | scripts/pkg | 505 | ||||
-rwxr-xr-x | scripts/reset | 3 | ||||
-rwxr-xr-x | signfs/signfs | bin | 0 -> 17596 bytes | |||
-rw-r--r-- | uname/Makefile | 3 | ||||
-rwxr-xr-x | uname/uname | bin | 0 -> 787 bytes | |||
-rw-r--r-- | uname/uname.c | 109 | ||||
-rw-r--r-- | wd/Makefile | 9 | ||||
-rwxr-xr-x | wd/wdd | bin | 0 -> 431 bytes | |||
-rw-r--r-- | wd/wdd.c | 38 |
83 files changed, 12387 insertions, 0 deletions
@@ -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 Binary files differnew file mode 100755 index 0000000..ca03e7d --- /dev/null +++ b/findcdrom/findcdrom diff --git a/findcdrom/findcdrom-debug b/findcdrom/findcdrom-debug Binary files differnew file mode 100755 index 0000000..116ad95 --- /dev/null +++ b/findcdrom/findcdrom-debug 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, + * so we must bring it up + */ + master_up = 1; + } + } + + if (!goterr) { + /* get the slaves MAC address */ + strncpy(if_hwaddr.ifr_name, + slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCGIFHWADDR, + &if_hwaddr) < 0) { + fprintf(stderr, + "Could not get MAC " + "address of %s: %s\n", + slave_ifname, + strerror(errno)); + strncpy(if_hwaddr.ifr_name, + master_ifname, + IFNAMSIZ); + goterr=1; + } + } + + if (!goterr) { + strncpy(if_hwaddr.ifr_name, + master_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCSIFHWADDR, + &if_hwaddr) < 0) { + fprintf(stderr, + "Could not set MAC " + "address of %s: %s\n", + master_ifname, + strerror(errno)); + goterr=1; + } else { + hwaddr_notset = 0; + } + } + + if (master_up) { + if_flags.ifr_flags |= IFF_UP; + if (ioctl(skfd, SIOCSIFFLAGS, + &if_flags) < 0) { + fprintf(stderr, + "Bringing up interface " + "%s failed: %s\n", + master_ifname, + strerror(errno)); + } + } + + } else { + /* we'll assign master's hwaddr to this slave */ + if (ifr2.ifr_flags & IFF_UP) { + ifr2.ifr_flags &= ~IFF_UP; + if (ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { + int saved_errno = errno; + fprintf(stderr, "Shutting down interface %s failed: %s\n", + slave_ifname, strerror(saved_errno)); + } + } + + strncpy(if_hwaddr.ifr_name, slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCSIFHWADDR, &if_hwaddr) < 0) { + int saved_errno = errno; + fprintf(stderr, "SIOCSIFHWADDR on %s failed: %s\n", if_hwaddr.ifr_name, + strerror(saved_errno)); + if (saved_errno == EBUSY) + fprintf(stderr, " The slave device %s is busy: it must be" + " idle before running this command.\n", slave_ifname); + else if (saved_errno == EOPNOTSUPP) + fprintf(stderr, " The slave device you specified does not support" + " setting the MAC address.\n Your kernel likely does not" + " support slave devices.\n"); + else if (saved_errno == EINVAL) + fprintf(stderr, " The slave device's address type does not match" + " the master's address type.\n"); + } else { + if (verbose) { + unsigned char *hwaddr = if_hwaddr.ifr_hwaddr.sa_data; + printf("Slave's (%s) hardware address set to " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", slave_ifname, + hwaddr[0], hwaddr[1], hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + } + } + } + + if (*spp && !strcmp(*spp, "metric")) { + if (*++spp == NULL) { + fprintf(stderr, usage_msg); + exit(2); + } + if_metric.ifr_metric = atoi(*spp); + strncpy(if_metric.ifr_name, slave_ifname, IFNAMSIZ); + if (ioctl(skfd, SIOCSIFMETRIC, &if_metric) < 0) { + fprintf(stderr, "SIOCSIFMETRIC on %s: %s\n", slave_ifname, + strerror(errno)); + goterr = 1; + } + spp++; + } + + if (strncpy(if_ipaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFADDR, &if_ipaddr) < 0) { + fprintf(stderr, + "Something broke setting the slave's address: %s.\n", + strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_ipaddr.ifr_addr.sa_data; + printf("Set the slave's (%s) IP address to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + if (strncpy(if_mtu.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFMTU, &if_mtu) < 0) { + fprintf(stderr, "Something broke setting the slave MTU: %s.\n", + strerror(errno)); + } else { + if (verbose) + printf("Set the slave's (%s) MTU to %d.\n", slave_ifname, if_mtu.ifr_mtu); + } + + if (strncpy(if_dstaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFDSTADDR, &if_dstaddr) < 0) { + fprintf(stderr, "Error setting the slave (%s) with SIOCSIFDSTADDR: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_dstaddr.ifr_dstaddr.sa_data; + printf("Set the slave's (%s) destination address to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + if (strncpy(if_brdaddr.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFBRDADDR, &if_brdaddr) < 0) { + fprintf(stderr, + "Something broke setting the slave (%s) broadcast address: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_brdaddr.ifr_broadaddr.sa_data; + printf("Set the slave's (%s) broadcast address to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + if (strncpy(if_netmask.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFNETMASK, &if_netmask) < 0) { + fprintf(stderr, + "Something broke setting the slave (%s) netmask: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) { + unsigned char *ipaddr = if_netmask.ifr_netmask.sa_data; + printf("Set the slave's (%s) netmask to %d.%d.%d.%d.\n", + slave_ifname, ipaddr[0], ipaddr[1], ipaddr[2], ipaddr[3]); + } + } + + ifr2.ifr_flags |= IFF_UP; /* the interface will need to be up to be bonded */ + if ((ifr2.ifr_flags &= ~(IFF_SLAVE | IFF_MASTER)) == 0 + || strncpy(ifr2.ifr_name, slave_ifname, IFNAMSIZ) <= 0 + || ioctl(skfd, SIOCSIFFLAGS, &ifr2) < 0) { + fprintf(stderr, + "Something broke setting the slave (%s) flags: %s.\n", + slave_ifname, strerror(errno)); + } else { + if (verbose) + printf("Set the slave's (%s) flags %4.4x.\n", slave_ifname, if_flags.ifr_flags); + } + + /* Do the real thing */ + if ( ! opt_r) { + strncpy(if_flags.ifr_name, master_ifname, IFNAMSIZ); + strncpy(if_flags.ifr_slave, slave_ifname, IFNAMSIZ); + if (!opt_c) { + if ((ioctl(skfd, SIOCBONDENSLAVE, &if_flags) < 0) && + (ioctl(skfd, BOND_ENSLAVE_OLD, &if_flags) < 0)) { + fprintf(stderr, "SIOCBONDENSLAVE: %s.\n", strerror(errno)); + } + } + else { + if ((ioctl(skfd, SIOCBONDCHANGEACTIVE, &if_flags) < 0) && + (ioctl(skfd, BOND_CHANGE_ACTIVE_OLD, &if_flags) < 0)) { + fprintf(stderr, "SIOCBONDCHANGEACTIVE: %s.\n", strerror(errno)); + } + } + } + } + } while ( (slave_ifname = *spp++) != NULL); + + /* Close the socket. */ + (void) close(skfd); + + return(goterr); +} + +static short mif_flags; + +/* Get the inteface configuration from the kernel. */ +static int if_getconfig(char *ifname) +{ + struct ifreq ifr; + int metric, mtu; /* Parameters of the master interface. */ + struct sockaddr dstaddr, broadaddr, netmask; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFFLAGS, &ifr) < 0) + return -1; + mif_flags = ifr.ifr_flags; + printf("The result of SIOCGIFFLAGS on %s is %x.\n", + ifname, ifr.ifr_flags); + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFADDR, &ifr) < 0) + return -1; + printf("The result of SIOCGIFADDR is %2.2x.%2.2x.%2.2x.%2.2x.\n", + ifr.ifr_addr.sa_data[0], ifr.ifr_addr.sa_data[1], + ifr.ifr_addr.sa_data[2], ifr.ifr_addr.sa_data[3]); + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFHWADDR, &ifr) < 0) + return -1; + + { + /* Gotta convert from 'char' to unsigned for printf(). */ + unsigned char *hwaddr = (unsigned char *)ifr.ifr_hwaddr.sa_data; + printf("The result of SIOCGIFHWADDR is type %d " + "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n", + ifr.ifr_hwaddr.sa_family, hwaddr[0], hwaddr[1], + hwaddr[2], hwaddr[3], hwaddr[4], hwaddr[5]); + } + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMETRIC, &ifr) < 0) { + metric = 0; + } else + metric = ifr.ifr_metric; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFMTU, &ifr) < 0) + mtu = 0; + else + mtu = ifr.ifr_mtu; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFDSTADDR, &ifr) < 0) { + memset(&dstaddr, 0, sizeof(struct sockaddr)); + } else + dstaddr = ifr.ifr_dstaddr; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFBRDADDR, &ifr) < 0) { + memset(&broadaddr, 0, sizeof(struct sockaddr)); + } else + broadaddr = ifr.ifr_broadaddr; + + strcpy(ifr.ifr_name, ifname); + if (ioctl(skfd, SIOCGIFNETMASK, &ifr) < 0) { + memset(&netmask, 0, sizeof(struct sockaddr)); + } else + netmask = ifr.ifr_netmask; + + return(0); +} + +static void if_print(char *ifname) +{ + char buff[1024]; + struct ifconf ifc; + struct ifreq *ifr; + int i; + + if (ifname == (char *)NULL) { + ifc.ifc_len = sizeof(buff); + ifc.ifc_buf = buff; + if (ioctl(skfd, SIOCGIFCONF, &ifc) < 0) { + fprintf(stderr, "SIOCGIFCONF: %s\n", strerror(errno)); + return; + } + + ifr = ifc.ifc_req; + for (i = ifc.ifc_len / sizeof(struct ifreq); --i >= 0; ifr++) { + if (if_getconfig(ifr->ifr_name) < 0) { + fprintf(stderr, "%s: unknown interface.\n", + ifr->ifr_name); + continue; + } + + if (((mif_flags & IFF_UP) == 0) && !opt_a) continue; + /*ife_print(&ife);*/ + } + } else { + if (if_getconfig(ifname) < 0) + fprintf(stderr, "%s: unknown interface.\n", ifname); + } +} + + +/* + * Local variables: + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 4 + * c-basic-offset: 4 + * tab-width: 4 + * compile-command: "gcc -Wall -Wstrict-prototypes -O -I/usr/src/linux/include ifenslave.c -o ifenslave" + * End: + */ diff --git a/include/rules.make b/include/rules.make new file mode 100644 index 0000000..14ccdee --- /dev/null +++ b/include/rules.make @@ -0,0 +1,20 @@ +CC=diet gcc +CFLAGS=-mpreferred-stack-boundary=2 -malign-jumps=0 -malign-loops=0 -malign-functions=0 -Os -march=i386 -mcpu=i386 +LDFLAGS=-s + +all: $(OBJS) + +%: %.c + $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $< + strip -R .comment -R .note $@ + objdump -h $@ | grep -q '\.data[ ]*00000000' && strip -R .data $@ || true + sstrip $@ + +%-debug: %.c + $(CC) $(LDFLAGS) $(CFLAGS) -DDEBUG -o $@ $< + strip -R .comment -R .note $@ + objdump -h $@ | grep -q '\.data[ ]*00000000' && strip -R .data $@ || true + +clean: + @rm -f *.[ao] *~ core + @rm -f $(OBJS) diff --git a/init/Makefile b/init/Makefile new file mode 100644 index 0000000..bc1ed4f --- /dev/null +++ b/init/Makefile @@ -0,0 +1,3 @@ +OBJS=init mkdev +include ../include/rules.make +CFLAGS+=-fomit-frame-pointer diff --git a/init/README b/init/README new file mode 100644 index 0000000..d729afb --- /dev/null +++ b/init/README @@ -0,0 +1,99 @@ +< extracted from init.c > + +/* + preinit - new try on 2002/04/20 - Willy Tarreau <willy AT meta-x.org> + + usage : /sbin/preinit [ \< config_file ] [ { init args | "rebuild" } ] + + Note : the "\< config_file" is to be used within configuration files : + #!/sbin/preinit < + .... + Thus, when you pass "init=/.preinit", the kernel executes : + /sbin/preinit < /.preinit + + The '<' character has been chosen for its rareness. + + the "rebuild" argument make the tool only rebuild a complete /dev + tree from the informations contained in the .preinit file, and then + exit. It does this even if the pid is not 1, but doesn't execute nor + mount anything. Only mkdir, links, blocks, chars and fifo devices are + created. Very useful before a lilo : + + # chroot /mnt/disk /.preinit rebuild + # lilo -r /mnt/disk + # umount /mnt/disk/dev + + If /dev/console is found under /dev, it will not be rebuilt. + + **** needs to rework the doc a bit since it's not up-to-date. **** + + This code tries to build a few filesystem squeleton so that init has enough + to work correctly : + - mount -t proc /proc /proc + - mount -t tmpfs /dev /dev + - get information from a file : /.preinit which describes what to mount, + what ramdisks, links and dirs to make : + +ln L source dest + make a symlink from <source> to <dest> +md D path [ mode ] + create a directory named <path> with the mode <mode>. If mode is left + undefined, 0755 is assumed. +mt M blkdev[(major:minor)] path fstype [ { ro | rw } [ flags ] ] + if <major:minor> is specified, create a block device <blkdev> + with <major> and <minor> and mode 0600. + mount <blkdev> under <path> with type <fstype>, read-only, except if + rw is specified, and args <flags>. +in I path + set the next init program to <path> +ex E cmd [ args ]* + execute <cmd> with args <args> and wait for its completion. +rx R dir cmd [ args ]* + chroot to <dir>, execute <cmd> with args <args> and wait for its completion. +bl B mode uid gid major minor naming_rule + create a set of block devices +ch C mode uid gid major minor naming_rule + create a set of char devices +fi F mode uid gid name + create a fifo +ma U mode + change umask +pr P <new_root> <put_old_relative> + pivot root : old root is displaced into new_root/put_old_relative, and + new_root is displaced under /. +mv K <old_dir> <new_dir> + keep directory <old_dir> after a pivot, then unmount it from old_dir. + usefull for /dev, /proc, /var ... +um O <old_dir> + umount <old_dir> after a pivot for example. +lo l </dev/loopX> <file> + losetup /dev/loopX file. + # anything + comment. + + The devices naming rules consist in strings mixed with numbering rules delimited with + brackets. Each numbering rule has 4 comma-separated fields : + - type of this string portion : 'c' for a single char, 'i' for an int, 'I' for an int + for which 0 is not printed, 'h' for an hex digit + - the range : + - chars: any concatenation of character ranges separated with a dash '-': 'a-fk-npq' + - ints : either an int or a range composed of 2 ints separated with a dash : '1-16' + - hex : same as int, but with hex digits (case insensitive) + - the scale : how much to add to the minor device for each step in the range. + + The commands may be prefixed with a '|' or '&', in which case, they will be + executed only if the previous command failed (|) or succeeded (&). + + Example : + ln hda3 /dev/disk => symlinks /dev/disk to hda3 + md /var/tmp 1777 => creates a directory /var/tmp with mode 1777 + mt /dev/hda1 /boot ext2 => attempts to mount /dev/hda1 read-only under /boot. + |mt /dev/hda1(3:1) /boot ext2 => only if the previous command failed, creates /dev/hda1 with major 3, minor 1 and mounts it under /boot + in /sbin/init-std => the following init will be this /sbin/init-std (31 chars max) + ex /sbin/initramdisk /dev/ram6 1200 => executes /sbin/initramdisk with these args and waits for its completion + bl 0600 0 0 3 1 hd[c,ab,64][i,1-16,1] => makes all hdaX and hdbX with X ranging from 1 to 16 + ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] => makes all 256 pty* + #comment => ignore this line + + For executable reduction reasons, the .preinit file is limited to 4 kB. +*/ diff --git a/init/examples/cd_nofloppy b/init/examples/cd_nofloppy new file mode 100755 index 0000000..6aa2fd6 --- /dev/null +++ b/init/examples/cd_nofloppy @@ -0,0 +1,58 @@ +#!/sbin/init < +# mem, kmem, null, zero, random, urandom, tty0, tty, console, ptmx, initctl +# full, fd +mt /proc /proc proc rw +mt /var /var tmpfs rw mode=755 +md /var/run 755 +md /var/tmp 1777 +md /dev/pts 755 + +bl 0600 0 0 3 0 hd[c,ab,64][I,0-16,1] +bl 0600 0 0 22 0 hd[c,cd,64][I,0-16,1] +bl 0600 0 0 33 0 hd[c,ef,64][I,0-16,1] +bl 0600 0 0 8 0 sd[c,a-h,16][I,0-15,1] +md /dev/rd 755 # DAC960 raid disks (majors 48-55) +bl 0600 0 0 48 0 rd/c0d[i,0-31,8] +bl 0600 0 0 48 1 rd/c0d[i,0-31,8]p[i,1-7,1] +md /dev/ida 755 # Compaq raid disks (majors 72-79) +bl 0600 0 0 72 0 ida/c0d[i,0-15,16] +bl 0600 0 0 72 1 ida/c0d[i,0-15,16]p[i,1-15,1] +bl 0600 0 0 11 0 sr[i,0-16,1] +ch 0600 0 0 9 0 st[i,0-15,1] +bl 0600 0 0 9 0 md[i,0-15,1] +bl 0600 0 0 2 0 fd0 +bl 0600 0 0 2 28 fd0u1440 +ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 3 0 tty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 4 1 tty[i,1-12,1] +bl 0600 0 0 7 0 loop[i,0-9,1] +bl 0600 0 0 1 0 ram[i,0-9,1] +ch 0600 0 5 4 64 ttyS[i,0-9,1] +bl 0400 0 0 1 250 initrd +ch 0600 0 3 10 1 psaux +ch 0600 0 0 10 144 nvram +ch 0600 0 0 10 130 watchdog +ch 0600 0 0 14 0 mixer +ch 0600 0 0 14 3 dsp +md /dev/input 755 +ch 0600 0 0 13 63 input/mice + +ln psaux /dev/mouse + +ex /sbin/findcdrom +mt /dev/cdrom /cdrom iso9660 ro + +# pivot_root only works on mount points, so we'll fake +# /cdrom by remounting /cdrom/dist into it +mv /cdrom/dist /cdrom +mv /proc /cdrom/proc +mv /var /cdrom/var +mv /dev /cdrom/dev # cannot unmount because /dev/console +pr /cdrom mnt/initrd + +um /mnt/initrd/dev +mv /mnt/initrd/cdrom /mnt/cdrom +um /mnt/initrd/cdrom + +in /sbin/init-sysv + diff --git a/init/examples/cd_preinit b/init/examples/cd_preinit new file mode 100755 index 0000000..786a95f --- /dev/null +++ b/init/examples/cd_preinit @@ -0,0 +1,63 @@ +#!/sbin/init < +# mem, kmem, null, zero, random, urandom, tty0, tty, console, ptmx, initctl +# full, fd +mt /proc /proc proc rw +mt /var /var tmpfs rw mode=755 +md /var/run 755 +md /var/tmp 1777 +md /dev/pts 755 + +bl 0600 0 0 3 0 hd[c,ab,64][I,0-16,1] +bl 0600 0 0 22 0 hd[c,cd,64][I,0-16,1] +bl 0600 0 0 33 0 hd[c,ef,64][I,0-16,1] +bl 0600 0 0 8 0 sd[c,a-h,16][I,0-15,1] +md /dev/rd 755 # DAC960 raid disks (majors 48-55) +bl 0600 0 0 48 0 rd/c0d[i,0-31,8] +bl 0600 0 0 48 1 rd/c0d[i,0-31,8]p[i,1-7,1] +md /dev/ida 755 # Compaq raid disks (majors 72-79) +bl 0600 0 0 72 0 ida/c0d[i,0-15,16] +bl 0600 0 0 72 1 ida/c0d[i,0-15,16]p[i,1-15,1] +bl 0600 0 0 11 0 sr[i,0-16,1] +ch 0600 0 0 9 0 st[i,0-15,1] +bl 0600 0 0 9 0 md[i,0-15,1] +bl 0600 0 0 2 0 fd0 +bl 0600 0 0 2 28 fd0u1440 +ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 3 0 tty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 4 1 tty[i,1-12,1] +bl 0600 0 0 7 0 loop[i,0-9,1] +bl 0600 0 0 1 0 ram[i,0-9,1] +ch 0600 0 5 4 64 ttyS[i,0-9,1] +bl 0400 0 0 1 250 initrd +ch 0600 0 3 10 1 psaux +ch 0600 0 0 10 144 nvram +ch 0600 0 0 10 130 watchdog +ch 0600 0 0 14 0 mixer +ch 0600 0 0 14 3 dsp +md /dev/input 755 +ch 0600 0 0 13 63 input/mice + +ln psaux /dev/mouse + +ex /sbin/findcdrom +mt /dev/cdrom /cdrom iso9660 ro + +# pivot_root only works on mount points, so we'll fake +# /cdrom by remounting /cdrom/dist into it +mv /cdrom/dist /cdrom +mv /proc /cdrom/proc +mv /var /cdrom/var +mv /dev /cdrom/dev # cannot unmount because /dev/console +pr /cdrom mnt/initrd + +um /mnt/initrd/dev +mv /mnt/initrd/cdrom /mnt/cdrom +um /mnt/initrd/cdrom + +mt /dev/fd0 /mnt/floppy ext2 ro +|mt /dev/fd0 /mnt/floppy vfat ro +&ex /mnt/floppy/autorun +um /mnt/floppy + +in /sbin/init-sysv + diff --git a/init/examples/cd_ramonly b/init/examples/cd_ramonly new file mode 100755 index 0000000..5e73cb1 --- /dev/null +++ b/init/examples/cd_ramonly @@ -0,0 +1,66 @@ +#!/sbin/init < +# mem, kmem, null, zero, random, urandom, tty0, tty, console, ptmx, initctl +# full, fd +mt /proc /proc proc rw +mt /var /var tmpfs rw mode=755 +md /var/run 755 +md /var/tmp 1777 +md /dev/pts 755 + +bl 0600 0 0 3 0 hd[c,ab,64][I,0-16,1] +bl 0600 0 0 22 0 hd[c,cd,64][I,0-16,1] +bl 0600 0 0 33 0 hd[c,ef,64][I,0-16,1] +bl 0600 0 0 8 0 sd[c,a-h,16][I,0-15,1] +md /dev/rd 755 # DAC960 raid disks (majors 48-55) +bl 0600 0 0 48 0 rd/c0d[i,0-31,8] +bl 0600 0 0 48 1 rd/c0d[i,0-31,8]p[i,1-7,1] +md /dev/ida 755 # Compaq raid disks (majors 72-79) +bl 0600 0 0 72 0 ida/c0d[i,0-15,16] +bl 0600 0 0 72 1 ida/c0d[i,0-15,16]p[i,1-15,1] +bl 0600 0 0 11 0 sr[i,0-16,1] +ch 0600 0 0 9 0 st[i,0-15,1] +bl 0600 0 0 9 0 md[i,0-15,1] +bl 0600 0 0 2 0 fd0 +bl 0600 0 0 2 28 fd0u1440 +ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 3 0 tty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 4 1 tty[i,1-12,1] +bl 0600 0 0 7 0 loop[i,0-9,1] +bl 0600 0 0 1 0 ram[i,0-9,1] +ch 0600 0 5 4 64 ttyS[i,0-9,1] +bl 0400 0 0 1 250 initrd +ch 0600 0 3 10 1 psaux +ch 0600 0 0 10 144 nvram +ch 0600 0 0 10 130 watchdog +ch 0600 0 0 14 0 mixer +ch 0600 0 0 14 3 dsp +md /dev/input 755 +ch 0600 0 0 13 63 input/mice + +ln psaux /dev/mouse + +ex /sbin/findcdrom +mt /dev/cdrom /cdrom iso9660 ro +mt / /cdrom/dist/lost+found tmpfs rw size=33554432 + +# hide this stuff not to copy it ! +mt tmpfs /cdrom/dist/home/httpd/www.ant-computing.com tmpfs rw size=4096 +rx /cdrom/dist /bin/cp -dRfpx / /lost+found +um /cdrom/dist/home/httpd/www.ant-computing.com + +mv /proc /cdrom/dist/lost+found/proc +mv /var /cdrom/dist/lost+found/var +mv /dev /cdrom/dist/lost+found/dev # cannot unmount because /dev/console + +pr /cdrom/dist/lost+found mnt/initrd + +um /mnt/initrd/dev +um /mnt/initrd/cdrom + +mt /dev/fd0 /mnt/floppy ext2 ro +|mt /dev/fd0 /mnt/floppy vfat ro +&ex /mnt/floppy/autorun +um /mnt/floppy + +in /sbin/init-sysv + diff --git a/init/examples/hd_preinit b/init/examples/hd_preinit new file mode 100755 index 0000000..beca81d --- /dev/null +++ b/init/examples/hd_preinit @@ -0,0 +1,60 @@ +#!/sbin/init < +# This .preinit is to be copied onto a hard disk to be used as-is. +# Don't forget to change the links at the bottom ! +# +# mem, kmem, null, zero, random, urandom, tty0, tty, console, ptmx, initctl +# full, fd +mt /proc /proc proc rw + +# we first try to mount /tmp as a tmpfs, next /var if it fails. +mt /tmp /tmp tmpfs rw +|mt /var /var tmpfs rw mode=755 +md /var/tmp 1777 +md /var/run 755 +md /dev/pts 755 + +bl 0600 0 0 3 0 hd[c,ab,64][I,0-16,1] +bl 0600 0 0 22 0 hd[c,cd,64][I,0-16,1] +bl 0600 0 0 33 0 hd[c,ef,64][I,0-16,1] +bl 0600 0 0 8 0 sd[c,a-h,16][I,0-15,1] +md /dev/rd 755 # DAC960 raid disks (majors 48-55) +bl 0600 0 0 48 0 rd/c0d[i,0-31,8] +bl 0600 0 0 48 1 rd/c0d[i,0-31,8]p[i,1-7,1] +md /dev/ida 755 # Compaq raid disks (majors 72-79) +bl 0600 0 0 72 0 ida/c0d[i,0-15,16] +bl 0600 0 0 72 1 ida/c0d[i,0-15,16]p[i,1-15,1] +bl 0600 0 0 11 0 sr[i,0-16,1] +ch 0600 0 0 9 0 st[i,0-15,1] +bl 0600 0 0 9 0 md[i,0-15,1] +bl 0600 0 0 2 0 fd0 +bl 0600 0 0 2 28 fd0u1440 +ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 3 0 tty[c,p-za-f,16][h,0-f,1] +ch 0600 0 5 4 1 tty[i,1-12,1] +bl 0600 0 0 7 0 loop[i,0-9,1] +bl 0600 0 0 1 0 ram[i,0-9,1] +ch 0600 0 5 4 64 ttyS[i,0-9,1] +bl 0400 0 0 1 250 initrd +ch 0600 0 3 10 1 psaux +ch 0600 0 0 10 144 nvram +ch 0600 0 0 10 130 watchdog +ch 0600 0 0 14 0 mixer +ch 0600 0 0 14 3 dsp +md /dev/input 755 +ch 0600 0 0 13 63 input/mice + +ln psaux /dev/mouse +ln hdc /dev/cdrom + +md /dev/fs 755 + +# The partitions are referenced here, so that +# lilo.conf and fstab only use links. +ln hda /dev/mbr +ln hda1 /dev/boot +ln hda2 /dev/swap +ln hda3 /dev/root +ln ../hda6 /dev/fs/var + +in /sbin/init-sysv + diff --git a/init/init b/init/init Binary files differnew file mode 100755 index 0000000..6445edf --- /dev/null +++ b/init/init diff --git a/init/init.c b/init/init.c new file mode 100644 index 0000000..4593a40 --- /dev/null +++ b/init/init.c @@ -0,0 +1,1274 @@ +/* + WARNING ! THIS CODE IS OPTIMIZED FOR SIZE WITH COMPILED-IN ARGUMENTS. IT IS + SUBJECT TO BUFFER OVERFLOWS SO DON'T USE IT WITH RUNTIME ARGUMENTS !!! +*/ + +/* TODO : + - make the config buffer bigger + - a few security checks (buffer overflows...) + - cleanup the code a bit +*/ + +/* + preinit - new try on 2002/04/20 - Willy Tarreau <willy AT meta-x.org> + + usage : /sbin/preinit [ \< config_file ] [ { init args | "rebuild" } ] + + Note : the "\< config_file" is to be used within configuration files : + #!/sbin/preinit < + .... + Thus, when you pass "init=/.preinit", the kernel executes : + /sbin/preinit < /.preinit + + The '<' character has been chosen for its rareness. + + the "rebuild" argument make the tool only rebuild a complete /dev + tree from the informations contained in the .preinit file, and then + exit. It does this even if the pid is not 1, but doesn't execute nor + mount anything. Only mkdir, links, blocks, chars and fifo devices are + created. Very useful before a lilo : + + # chroot /mnt/disk /.preinit rebuild + # lilo -r /mnt/disk + # umount /mnt/disk/dev + + If /dev/console is found under /dev, it will not be rebuilt. + + **** needs to rework the doc a bit since it's not up-to-date. **** + + This code tries to build a few filesystem squeleton so that init has enough + to work correctly : + - mount -t proc /proc /proc + - mount -t tmpfs /dev /dev + - get information from a file : /.preinit which describes what to mount, + what ramdisks, links and dirs to make : + +ln L source dest + make a symlink from <source> to <dest> +md D path [ mode ] + create a directory named <path> with the mode <mode>. If mode is left + undefined, 0755 is assumed. +mt M blkdev[(major:minor)] path fstype [ { ro | rw } [ flags ] ] + if <major:minor> is specified, create a block device <blkdev> + with <major> and <minor> and mode 0600. + mount <blkdev> under <path> with type <fstype>, read-only, except if + rw is specified, and args <flags>. +in I path + set the next init program to <path> +ex E cmd [ args ]* + execute <cmd> with args <args> and wait for its completion. +rx R dir cmd [ args ]* + chroot to <dir>, execute <cmd> with args <args> and wait for its completion. +bl B mode uid gid major minor naming_rule + create a set of block devices +ch C mode uid gid major minor naming_rule + create a set of char devices +fi F mode uid gid name + create a fifo +ma U mode + change umask +pr P <new_root> <put_old_relative> + pivot root : old root is displaced into new_root/put_old_relative, and + new_root is displaced under /. +mv K <old_dir> <new_dir> + keep directory <old_dir> after a pivot, then unmount it from old_dir. + usefull for /dev, /proc, /var ... +um O <old_dir> + umount <old_dir> after a pivot for example. +lo l </dev/loopX> <file> + losetup /dev/loopX file. + # anything + comment. + + The devices naming rules consist in strings mixed with numbering rules delimited with + brackets. Each numbering rule has 4 comma-separated fields : + - type of this string portion : 'c' for a single char, 'i' for an int, 'I' for an int + for which 0 is not printed, 'h' for an hex digit + - the range : + - chars: any concatenation of character ranges separated with a dash '-': 'a-fk-npq' + - ints : either an int or a range composed of 2 ints separated with a dash : '1-16' + - hex : same as int, but with hex digits (case insensitive) + - the scale : how much to add to the minor device for each step in the range. + + The commands may be prefixed with a '|' or '&', in which case, they will be + executed only if the previous command failed (|) or succeeded (&). + + Example : + ln hda3 /dev/disk => symlinks /dev/disk to hda3 + md /var/tmp 1777 => creates a directory /var/tmp with mode 1777 + mt /dev/hda1 /boot ext2 => attempts to mount /dev/hda1 read-only under /boot. + |mt /dev/hda1(3:1) /boot ext2 => only if the previous command failed, creates /dev/hda1 with major 3, minor 1 and mounts it under /boot + in /sbin/init-std => the following init will be this /sbin/init-std (31 chars max) + ex /sbin/initramdisk /dev/ram6 1200 => executes /sbin/initramdisk with these args and waits for its completion + bl 0600 0 0 3 1 hd[c,ab,64][i,1-16,1] => makes all hdaX and hdbX with X ranging from 1 to 16 + ch 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] => makes all 256 pty* + #comment => ignore this line + + For executable reduction reasons, the .preinit file is limited to 4 kB. + + The root directory should contain the following dirs : + - /var (directory) -> can be a ramfs or a real dir on another device + - /var/tmp (directory) -> idem + - /tmp (directory) -> idem + - /etc (directory or symlink) -> several possibilities : + - directory on the root fs (preferably) + - directory on another fs + - ramfs (or ramdisk) and directory extracted from other source + - symlink to /boot/etc (in this case, /boot/etc must be a populated directory) + /etc will already have several symlinks + + /boot (mandatory directory) contains the following : + - [kernel version] (directory) with vmlinuz, System.map, config and + the tree behind /lib/modules/[version] + - current (symlink to kernel version) + - vmlinuz (symlink to current/vmlinuz) + - System.map (symlink to current/System.map) + - config (symlink to current/config) + - eventually initrd (symlink to current/initrd) + - modules.dep (symlink to current/modules.dep) + - modules.pcimap (symlink to current/modules.pcimap) + + /boot *may* contain the following : + - etc (populated directory) + - bootfstab (if /etc and /boot/etc empty or non-existant) + + This helps in making /lib/modules : it will simply be a symlink to + /boot/current which will contain all modules. + + +wrong for now: + /tmp will always be linked to fs/var/tmp. + /var will always be linked to fs/var. + /fs must contain a description file for it (what to mount where, what to + initialize) so that init has a working filesystem hierarchy and fstab works. + /fs should be FAT-compatible, at least for its root structure. +*/ + +#include <stdio.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/mount.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include <linux/loop.h> + +#ifdef DEBUG +static void print(char *c) { + char *p = c; + while (*p) + p++; + write(0, c, p-c); +} +#else +#define print(a,...) do{}while(0) +#endif + +//#define ATOL(x) atol(x) +#define ATOL(x) my_atoul(x) + +typedef unsigned char uchar; + +extern char **environ; + +static const char cfg_fname[] = "/.preinit"; /* configuration file */ +static const char tmpfs_fs[] = "tmpfs"; +static const char dev_console[] = "dev/console"; +static const char dev_root[] = "dev/root"; +static const char dev_name[] = "/dev"; +static const char root_dir[] = "/"; +static const char var_dir[] = "/var"; +static const char var_run[] = "/var/run"; +static const char var_tmp[] = "/var/tmp"; +static const char proc_dir[] = "/proc"; +static const char proc_self_fd[] = "/proc/self/fd"; +static const char proc_cmdline[] = "/proc/cmdline"; +static const char sbin_init_sysv[] = "sbin/init-sysv"; +static const char str_rebuild[] = "rebuild"; +static const char dev_options[] = "size=0,nr_inodes=4096,mode=755"; + +#define tmp_name (var_tmp + 4) //static const char tmp_name[] = "/tmp"; +#define proc_fs (proc_dir+1) //static const char proc_fs[] = "proc"; +#define fd_dir (proc_self_fd + 11) //static const char fd_dir[] = "fd"; + +#define UID_ROOT 0 +#define GID_ROOT 0 +#define GID_TTY 5 +#define GID_KMEM 9 + +/* used by naming rules */ +#define MAX_FIELDS 8 +#define MAX_DEVNAME_LEN 64 +#define MAX_CFG_SIZE 4096 +#define MAX_CFG_ARGS 16 +#define MAX_CMDLINE_LEN 512 + +struct dev_varstr { + char type; + union { + struct { + char *set; + char *ptr; + char value; /* value to be printed */ + uchar index; /* index in the set */ + } chr; + struct { + uchar low; + uchar high; + uchar value; + } num; + } u; + uchar scale; +}; + +static const struct { + char name[8]; + short gid; + char major, minor; + mode_t mode; /* mode + S_IFCHR, S_IFBLK, S_IFIFO */ +} dev_nodes[] = { + /* console must always be at the first location */ + { "console", GID_TTY, 5, 1, 0600 | S_IFCHR }, + { "mem", GID_KMEM, 1, 1, 0640 | S_IFCHR }, + { "kmem", GID_KMEM, 1, 2, 0640 | S_IFCHR }, + { "null", GID_ROOT, 1, 3, 0666 | S_IFCHR }, + { "port", GID_KMEM, 1, 4, 0640 | S_IFCHR }, + { "zero", GID_ROOT, 1, 5, 0666 | S_IFCHR }, + { "full", GID_ROOT, 1, 7, 0666 | S_IFCHR }, + { "random", GID_ROOT, 1, 8, 0644 | S_IFCHR }, + { "urandom", GID_ROOT, 1, 9, 0644 | S_IFCHR }, + { "tty0", GID_TTY, 4, 0, 0600 | S_IFCHR }, + { "tty", GID_TTY, 5, 0, 0666 | S_IFCHR }, + { "ptmx", GID_TTY, 5, 2, 0666 | S_IFCHR }, + { "initctl", GID_ROOT, 0, 0, 0600 | S_IFIFO }, +}; + +#define NB_TOKENS 15 + +enum { + TOK_LN = 0, /* ln : make a symlink */ + TOK_MD, /* md : mkdir */ + TOK_MT, /* mt : mount */ + TOK_IN, /* in : set init program */ + TOK_EX, /* ex : execute */ + TOK_RX, /* rx : execute under chroot */ + TOK_BL, /* bl : make block devices */ + TOK_CH, /* ch : make char devices */ + TOK_FI, /* fi : make a fifo */ + TOK_MA, /* ma : set umask */ + TOK_PR, /* pr : pivot root */ + TOK_MV, /* mv : move */ + TOK_UM, /* um : umount */ + TOK_LO, /* lo : losetup */ + TOK_EC, /* ec : echo */ + TOK_UNK, /* unknown command */ + TOK_EOF, /* end of file */ + TOK_COND_OR = 0x40, /* conditionnal OR */ + TOK_COND_AND = 0x80, /* conditionnal AND */ + TOK_COND = 0xc0, /* any condition */ +}; + +/* this contains all two-chars command, 1-char commands, followed by a token + * number. + */ +static const struct { + char lcmd[2]; /* long form */ + char scmd; /* short form */ + char minargs; /* min #args */ +} tokens[NB_TOKENS] = { + "ln", 'L', 2, /* TOK_LN */ + "md", 'D', 1, /* TOK_MD */ + "mt", 'M', 3, /* TOK_MT */ + "in", 'I', 1, /* TOK_IN */ + "ex", 'E', 1, /* TOK_EX */ + "rx", 'R', 2, /* TOK_RX */ + "bl", 'B', 6, /* TOK_BL */ + "ch", 'C', 6, /* TOK_CH */ + "fi", 'F', 4, /* TOK_FI */ + "ma", 'U', 1, /* TOK_MA */ + "pr", 'P', 2, /* TOK_PR */ + "mv", 'K', 2, /* TOK_MV */ + "um", 'O', 1, /* TOK_UM */ + "lo", 'l', 2, /* TOK_LO */ + "ec", 0, 0, /* TOK_EC */ +}; + +static char cfg_data[MAX_CFG_SIZE]; +static char *cfg_args[MAX_CFG_ARGS]; +static char *cfg_line; +static char cmdline[MAX_CMDLINE_LEN]; +static char *cst_str[MAX_FIELDS]; +static char *var_str[MAX_FIELDS]; +static struct dev_varstr var[MAX_FIELDS]; +static int error; /* an error has emerged from last operation */ + +static unsigned long my_atoul(const char *s) { + unsigned long res = 0; + unsigned long digit; + + while (*s) { + digit = *s - '0'; + if (digit > 9) + return 0; + res = res * 10 + digit; + s++; + } + return res; +} + +static int streq(const char *str1, const char *str2) { + char c1; + while ((c1 = *str1) && c1 == *str2) { /* the second test ensures that *str2 != 0 */ + str1++; + str2++; + } + return ((c1 | *str2) == 0); +} + +/* + * copies at most <size-1> chars from <src> to <dst>. Last char is always + * set to 0, unless <size> is 0. The number of chars copied is returned + * (excluding the terminating zero). + * This code has been optimized for size and speed : on x86, it's 45 bytes + * long, uses only registers, and consumes only 4 cycles per char. + */ +static inline int my_strlcpy(char *dst, const char *src, int size) { + char *orig = dst; + if (size) { + while (--size && (*dst = *src)) { + src++; dst++; + } + *dst = 0; + } + return dst - orig; +} + +static void reopen_console() { + int i, fd, oldfd; + + oldfd = dup2(0, 3); // keep a valid console on fd 3 + + for (i = 0; i < 3; i++) + close(i); + + fd = open(dev_console, O_RDWR); // fd = 0 (stdin) or -1 (error) + if (fd < 0) + dup(oldfd); // restore 0 from old console + + close(oldfd); + dup(0); // stdout + dup(0); // stderr + + print("init/info : reopened /dev/console\n"); +} + +/* reads the kernel command line </proc/cmdline> into memory and searches + * for the first assignment of the required variable. Return its value + * (which may be empty) or NULL if not found. + */ +char *find_arg(char *arg) { + char *a, *c; + + /* read cmdline the first time */ + if (!*cmdline) { + int fd, len; + + if ((fd = open(proc_cmdline, O_RDONLY)) == -1) + return NULL; + if ((len = read(fd, cmdline, sizeof(cmdline)-1)) == -1) { + close(fd); + return NULL; + } + cmdline[len] = 0; + close(fd); + } + + /* search for the required arg in cmdline */ + c = cmdline; + a = arg; + + while (*c) { + if (*a == 0) { + /* complete match. is it a full word ? */ + if (*c == '=') { + a = ++c; + while ((*a != ' ') && (*a != '\0') && (*a != '\n')) + a++; + *a = 0; + return c; /* return value */ + } + else if (*c == ' ' || *c == '\n' || *c == '\0') { + *c = 0; + return c; /* return pointer to empty string */ + } + else { /* not full word. bad match. */ + c -= (a - arg) - 1; + a = arg; + } + } + if (*c == *a) { + a++; + c++; + } + else { + c -= (a - arg) - 1; + a = arg; + } + } + if (*a == 0) /* complete match at end of string */ + return c; /* pointer to empty string */ + else + return NULL; /* not found */ +} + +/* reads the configuration file <cfg_file> into memory. + * returns 0 if OK, -1 if error. + */ +static inline int read_cfg(char *cfg_file) { + int cfg_fd; + int cfg_size; + + if (cfg_line == NULL) { + if (((cfg_fd = open(cfg_file, O_RDONLY)) == -1) || + ((cfg_size = read(cfg_fd, cfg_data, sizeof(cfg_data) - 1)) == -1)) { + return -1; + } + close(cfg_fd); + cfg_line = cfg_data; + cfg_data[cfg_size] = 0; + } + return 0; +} + +/* reads one line from <cfg_data>. comments are ignored. The command token is + * returned as the result of this function, or TOK_UNK if none matches, or + * TOK_EOF if nothing left. All args are copied into <cfg_args> as an array + * of pointers. Maximum line length is 256 chars and maximum args number is 15. + */ +static int parse_cfg() { + int nbargs; + int token; + int cond; + + memset(cfg_args, 0, sizeof(cfg_args)); + while (*cfg_line) { + char c, *p = cfg_line; + + /* search beginning of line */ + while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') + p++; + + /* now search end of line */ + cfg_line = p; + while (*cfg_line && *cfg_line != '#' && *cfg_line != '\n' && *cfg_line != '\r') + cfg_line++; + + /* terminate the line cleanly to avoid further tests */ + while (c = *cfg_line) { + *cfg_line++ = '\0'; + if (c == '\n') + break; + } + + /* skip empty lines */ + if (!*p) + continue; + + if (*p == '|') { + cond = TOK_COND_OR; + p++; + } + else if (*p == '&') { + cond = TOK_COND_AND; + p++; + } + else + cond = 0; + + /* fills the cfg_args[] array with the command itself, followed by all + * args. + */ + for (nbargs = 0; *p && (nbargs < MAX_CFG_ARGS - 1); nbargs++) { + int backslash = 0; + cfg_args[nbargs] = p; + do { + if (backslash) { + backslash = 0; + memmove(p - 1, p, cfg_line - p); + } + else { + backslash = (*p == '\\'); + p++; + } + } while (*p && (backslash || (*p != ' ' && *p != '\t'))); + if (*p) { + *p = 0; + do p++; while (*p == ' ' || *p == '\t'); + } + } + + /* search a matching token for the command : it can either be a single + * char (old language) or a double char (new language) + */ + for (token = 0; token < NB_TOKENS; token++) + if ((!cfg_args[0][1] && tokens[token].scmd == cfg_args[0][0]) || + (cfg_args[0][1] && + (tokens[token].lcmd[1] == cfg_args[0][1]) && + (tokens[token].lcmd[0] == cfg_args[0][0]))) + return token | cond; + + return TOK_UNK; + } + return TOK_EOF; +} + +/* makes a dev entry */ +static inline int mknod_chown(mode_t mode, uid_t uid, gid_t gid, uchar major, uchar minor, char *name) { + if (mknod(name, mode, makedev(major, minor)) == -1) { + error = 1; + print("init/error : mknod("); print(name); print(") failed\n"); + } + + if (chown(name, uid, gid) == -1) { + error = 1; + print("init/error : chown("); print(name); print(") failed\n"); + } +} + +/* breaks a 3-fields, comma-separated string into 3 fields */ +static inline int varstr_break(char *str, char *type, char **set, uchar *scale) { + int state; + char *res[3]; + + for (state = 0; state < 3; state++) { + res[state] = str; + while (*str && *str != ',') + str++; + if (*str) + *str++ = 0; + else if (state < 2) + return 1; + } + + *type = *res[0]; + *set = res[1]; + *scale = ATOL(res[2]); + return 0; +} + +/* reads a range from a string of the form "low-high" or "value". + * Returns 0 if OK, or 1 if error. + */ +static int int_range(char *from, uchar *low, uchar *high) { + char c; + *low = 0; + while ((c = *from) != '\0') { + if (isdigit(c)) + *low = *low * 10 + c - '0'; + else if (c == '-') { + low = high; + *low = 0; + } + else + return 1; + from++; + } + if (low != high) /* high has not been written to */ + *high = *low; + + return 0; +} + +/* reads a range from a hex string of the form "low-high" or "value". + * Returns 0 if OK, or 1 if error. + */ +static int hex_range(char *from, uchar *low, uchar *high) { + uchar c; + *low = 0; + while ((c = *from) != '\0') { + if (c == '-') { + low = high; /* all writes will now be done on <high> */ + *low = 0; + } + else { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else + return 1; + + // if (((uchar)(c -= '0') > 9) /* not a digit */ + // && (((uchar)(c -= 'A' - '0' - 10) < 0xa) || ((uchar)c > 0xf)) + // && (((uchar)(c -= 'a' - 'A') < 0xa) || ((uchar)c > 0xf))) + // return 1; + + *low = (*low << 4) + c; + } + from++; + } + if (low != high) /* high has not been written to */ + *high = *low; + + return 0; +} + +static inline char *addcst(char *dest, char *cst) { + while ((*dest++ = *cst++) != '\0'); + return dest - 1; +} + +static inline char *addchr(char *dest, char chr) { + *dest++ = chr; + *dest = '\0'; + return dest; +} + +static char *addint(char *dest, uchar num) { + int div; + char *out = dest; + for (div = (1<<16) + (10<<8) + (100); div > 0;) { + int q, r, d; + d = (unsigned char)div; + q = num / d; r = num % d; + div >>= 8; + if (!div || (out != dest) || q) { + *out++ = q + '0'; + } + num = r; + } + *out = '\0'; + return out; +} + +static char *addhex(char *dest, uchar num) { + uchar c; + if (num > 0x0F) { + c = num >> 4; + *dest++ = (c > 9) ? (c - 10 + 'a') : (c + '0'); + } + c = num & 0x0F; + *dest++ = (c > 9) ? (c - 10 + 'a') : (c + '0'); + *dest = '\0'; + return dest; +} + +/* builds a device name from the current <var> and <cst_str> arrays, + * and compute the corresponding minor number by adding all the relevant + * fields' values + */ +static void name_and_minor(char *name, uchar *minor, int fields) { + uchar min; + int f; + + min = 0; + for (f = 0; f < fields; f++) { + if (*cst_str[f]) + name = addcst(name, cst_str[f]); + switch (var[f].type) { + case 'c' : + name = addchr(name, var[f].u.chr.value); + min += var[f].u.chr.index * var[f].scale; + break; + case 'h' : + name = addhex(name, var[f].u.num.value); + goto recalc_int; + case 'i' : + name = addint(name, var[f].u.num.value); + goto recalc_int; + case 'I' : + if (var[f].u.num.value) + name = addint(name, var[f].u.num.value); + recalc_int: + min += (var[f].u.num.value - var[f].u.num.low) * var[f].scale; + break; + case 0 : + break; + default: + print("init/conf : field type must be c, h, i or I\n"); + } + } + if (minor) + *minor = min; +} + +/* increments the index for variable #f. When it overflows, it goes back to the + * beginning and a carry is returned for the next variable to be incremented. + * 0 is returned if no carry is returned, otherwise, 1 is returned. + */ +static int inc_var_index(int f) { + switch (var[f].type) { + case 'c' : + if ((var[f].u.chr.ptr[1] == '-') && (var[f].u.chr.value < var[f].u.chr.ptr[2])) { + var[f].u.chr.value++; + var[f].u.chr.index++; + return 0; + } else { /* we cannot increment within the current range */ + if (*++var[f].u.chr.ptr == '-') { + if (*++var[f].u.chr.ptr) + var[f].u.chr.ptr++; + } + if (!*var[f].u.chr.ptr) { /* no other range found */ + var[f].u.chr.value = *(var[f].u.chr.ptr = var[f].u.chr.set); + var[f].u.chr.index = 0; + return 1; + } + else { /* found a new range */ + var[f].u.chr.value = *var[f].u.chr.ptr; + var[f].u.chr.index++; + return 0; + } + } + case 'h': + case 'i': + case 'I': + if (var[f].u.num.value == var[f].u.num.high) { + var[f].u.num.value = var[f].u.num.low; + return 1; + } else { + var[f].u.num.value++; + return 0; + } + default: + return 1; /* an empty variable propagates carry */ + } +} + + +/* makes one or several device inodes depending on the rule <rule> */ +static void multidev(mode_t mode, uid_t uid, gid_t gid, uchar major, uchar minor, char *rule) { + char *p1, *p2; + int state; + int i; + + enum { + ST_STRING = 0, + ST_CONST + }; + + int field; /* each field is a couple of a cst string and a var string */ + + p1 = p2 = rule; + state = ST_STRING; + field = 0; + + cst_str[field] = var_str[field] = p2; /* be sure to point to something valid */ + + while (*p2) { + if (state == ST_STRING) { + if (*p2 == '[') { + state = ST_CONST; + cst_str[field] = p1; + *p2++ = 0; + p1 = p2; + } + else + p2++; + } + else if (state == ST_CONST) { + if (*p2 == ']') { + state = ST_STRING; + var_str[field++] = p1; + *p2++ = 0; + p1 = p2; + cst_str[field] = p1; + } + else + p2++; + } + } + + if (state == ST_STRING) { + if (p2 > p1) { + state = ST_CONST; + cst_str[field] = p1; + var_str[field++] = p2; + *p2++ = 0; + } + } + else { + print("var string incomplete\n"); + } + + /* now we must "compile" the variable fields */ + for (i = 0; i < field; i++) { + memset(&var[i], 0, sizeof(var[i])); + if (varstr_break(var_str[i], &var[i].type, &var[i].u.chr.set, &var[i].scale)) { + //print("empty variable field in string <"); print(var_str[i]); print(">\n"); + continue; + } + + switch (var[i].type) { + case 'c': + var[i].u.chr.value = *(var[i].u.chr.ptr = var[i].u.chr.set); + var[i].u.chr.index = 0; + break; + case 'h': + if (hex_range(var[i].u.chr.set, &var[i].u.num.low, &var[i].u.num.high)) { + //printf("error in hex range in <%s>\n", var_str[i]); + print("init/conf : error in hex range\n"); + continue; + } + var[i].u.num.value = var[i].u.num.low; + break; + case 'i': + case 'I': + if (int_range(var[i].u.chr.set, &var[i].u.num.low, &var[i].u.num.high)) { + print("init/conf : error in int range\n"); + //printf("error in int range in <%s>\n", var_str[i]); + continue; + } + var[i].u.num.value = var[i].u.num.low; + break; + default: + // unknown type + break; + } + } + + while (1) { + char name[MAX_DEVNAME_LEN]; + uchar minor_offset; + int f; + + name_and_minor(name, &minor_offset, field); + // printf("name = %s, minor = %d\n", name, minor + minor_offset); + + mknod_chown(mode, uid, gid, major, minor + minor_offset, name); + f = 0; + while (inc_var_index(f) && (f<field)) + f++; + + if (f >= field) + break; + } +} + +/* converts an octal permission mode into the mode_t equivalent */ +static mode_t a2mode(char *ascii) { + mode_t m = 0; + while ((unsigned)(*ascii - '0') < 8) { + m = (m << 3) | (*ascii - '0'); + ascii++; + } + return m; +} + +int main(int argc, char **argv) { + int old_umask; + int pid1, err; + int cfg_ok; + int rebuild; + int token; + struct stat statf; + char *cmdline_arg; + char *cfg_file; + + /* check if a config file name has been given to preinit : init [ \< <cfg_file> ] [ init args ] */ + if (argc > 2 && *argv[1] == '<') { + cfg_file = argv[2]; + argv[2] = argv[0]; + argv += 2; + argc -= 2; + } + else + cfg_file = (char *)cfg_fname; + + /* restore the correct name. Warning: in the case where init is launched + * from userspace, the config file is not read again so only the hardcoded + * name will be used for the executable name. + */ + *argv = &sbin_init_sysv;/*"sbin/init-sysv"*/; + old_umask = umask(0); + + /* if "rebuild" is passed as the only argument, then we'll try to rebuild a + * full /dev even if not pid==1, but only if it was not already populated + */ + rebuild = (argc == 2 && streq(argv[1], str_rebuild/*"rebuild"*/)); + + pid1 = (getpid() == 1) /*|| 1*/; + cfg_ok = (read_cfg(cfg_file) == 0); + + chdir(root_dir); /* be sure not to stay under /dev ! */ + /* do nothing if we're not called as the first process */ + if (pid1 || rebuild) { + /* check if /dev is already populated : /dev/console should exist */ + if (stat(dev_console, &statf) == -1) { + print("init/info: /dev/console not found, rebuilding /dev.\n"); + if (mount(dev_name, dev_name, tmpfs_fs, MS_MGC_VAL, dev_options) == -1) + print("init/err: cannot mount /dev.\n"); + else { + int i; + if (chdir(dev_name) == -1) + print("init/error : cannot chdir(/dev)\n"); + + print("init/info: /dev has been mounted.\n"); + for (i = 0; i < sizeof(dev_nodes) / sizeof(dev_nodes[0]); i++) { + mknod_chown(dev_nodes[i].mode, (uid_t)UID_ROOT, (gid_t)dev_nodes[i].gid, + dev_nodes[i].major, dev_nodes[i].minor, (char *)dev_nodes[i].name); + } + symlink(proc_self_fd, fd_dir); + print("init/info: /dev has been rebuilt.\n"); + + chdir(root_dir); + /* if /dev was empty, we may not have had /dev/console, so the + * kernel couldn't bind us to it. So let's attach to it now. + */ + reopen_console(); + } + } + else { + if (!pid1) { + /* we don't want to rebuild anything else if pid is not 1 */ + print("init/info: /dev is OK.\n"); + return 0; + } + } + + /* if /dev/root is non-existent, we'll try to make it now */ + + if (stat(dev_root, &statf) == -1) { + print("init/info : /dev/root does not exist. Rebuilding...\n"); + if (stat(root_dir, &statf) == 0) { + if (mknod(dev_root, 0600 | S_IFBLK, statf.st_dev) == -1) { + //error = 1; + print("init/error : mknod(/dev/root) failed\n"); + } + } + else { + print("init/error : cannot stat(/)\n"); + } + } + } + + /* here, the cwd is still "/" */ + if (cfg_ok) { + while ((token = parse_cfg()) != TOK_EOF) { + int cond = 0; + int lasterr = error; + + if (token == TOK_UNK) { + print("unknown command.\n"); + break; + } + + cond = token & TOK_COND; + token &= ~TOK_COND; + + if (cfg_args[tokens[token].minargs] == NULL) { + print("Missing args\n"); + break; + } + + /* skip conditionnal executions if unneeded */ + if ((cond & TOK_COND_OR) && (!lasterr) || + (cond & TOK_COND_AND) && (lasterr)) + continue; + + /* now we can reset the error */ + error = 0; + + /* the first command set is always available */ + if (token == TOK_IN) { + /* I <path> : specify the path to init */ + print("<I>nit : used config name for init\n"); + *argv = cfg_args[1]; + continue; + } + + if (!pid1 && !rebuild) { /* other options are reserved for pid 1 only or rebuild mode */ + print("Command ignored since pid not 1\n"); + continue; + } + + /* the second command set is available if pid==1 or if "rebuild" is set */ + switch (token) { + case TOK_MD: + /* D path [ mode ] : make a directory */ + if (mkdir(cfg_args[1], (cfg_args[2] == NULL) ? 0755 : a2mode(cfg_args[2])) == -1) { + error = 1; + print("<D>irectory : mkdir() failed\n"); + } + continue; + case TOK_LN: + /* L from to : make a symlink */ + if (symlink(cfg_args[1], cfg_args[2]) == -1) { + error = 1; + print("<S>ymlink : symlink() failed\n"); + } + continue; + case TOK_BL: + /* B <mode> <uid> <gid> <major> <minor> <naming rule> : build a block device */ + case TOK_CH: + /* C <mode> <uid> <gid> <major> <minor> <naming rule> : build a character device */ + if (chdir(dev_name) == -1) { + print("<B>lock_dev/<C>har_dev : cannot chdir(/dev)\n"); + error = 1; + continue; + } + + multidev(a2mode(cfg_args[1]) | ((token == TOK_BL) ? S_IFBLK : S_IFCHR), + (uid_t)ATOL(cfg_args[2]), (gid_t)ATOL(cfg_args[3]), + ATOL(cfg_args[4]), ATOL(cfg_args[5]), cfg_args[6]); + chdir(root_dir); + continue; + case TOK_FI: + /* F <mode> <uid> <gid> <name> : build a fifo */ + if (chdir(dev_name) == -1) { + error = 1; + print("<F>ifo : cannot chdir(/dev)\n"); + } + + mknod_chown(a2mode(cfg_args[1]) | S_IFIFO, + (uid_t)ATOL(cfg_args[2]), (gid_t)ATOL(cfg_args[3]), + 0, 0, cfg_args[4]); + + chdir(root_dir); + continue; + case TOK_EC: { + /* ec <string> : echo a string */ + int l = strlen(cfg_args[1]); + cfg_args[1][l] = '\n'; + write(1, cfg_args[1], l + 1); + continue; + } + } /* end of switch() */ + + if (!pid1) { /* other options are reserved for pid 1 only */ + print("Command ignored since pid not 1\n"); + continue; + } + + switch (token) { + case TOK_MT: { + /* M dev[(major:minor)] mnt type [ {rw|ro} [ flags ] ]: mount dev on mnt (read-only) */ + char *maj, *min, *end; + char *mntdev; + int mntarg; + + /* if the device name doesn't begin with a slash, look for it + * in /proc/cmdline + */ + mntdev = cfg_args[1]; + if ((*mntdev != '/') && ((cmdline_arg = find_arg(mntdev)) != NULL)) { + mntdev = cmdline_arg; + print("<M>ount : using command line device\n"); + } + + maj = mntdev; /* handles /dev/xxx(maj:min) */ + while (*maj && *maj != '(') + maj++; + if (*maj) { + int imaj = 0, imin = 0; + dev_t dev; + + *(maj++) = 0; + min = end = maj; + while (*min && *min != ':') + min++; + + if (*min) { + *(min++) = 0; + end = min; + } + + while (*end && *end != ')') + end++; + + if (*end) + *end = 0; + if (*maj) + imaj = ATOL(maj); + if (*min) + imin = ATOL(min); + dev = makedev(imaj, imin); + if (mknod(mntdev, S_IFBLK|0600, dev) == -1) { /* makes the node as required */ + error = 1; + print("<M>ount : mknod() failed\n"); + } + } + + mntarg = MS_RDONLY; + if (cfg_args[4] != NULL && streq(cfg_args[4], "rw")) { + print("<M>ount : 'rw' flag found, mounting read/write\n"); + mntarg &= ~MS_RDONLY; + } + else { + print("<M>ount : 'rw' flag not found, mounting read only\n"); + } + + if (mount(mntdev, cfg_args[2], cfg_args[3], MS_MGC_VAL | mntarg, cfg_args[5]) == -1) { + error = 1; + print("<M>ount : error during mount()\n"); + } + + break; + } + case TOK_EX: + /* E cmd [cfg_args] : execute cmd with cfg_args, chrooted to dir */ + /* fall through TOK_RX */ + case TOK_RX: { + /* R dir cmd [cfg_args] : execute cmd with cfg_args, chrooted to dir */ + char **exec_args, *exec_dir; + int res; + + exec_args = cfg_args + 1; + if (token == TOK_EX) { + exec_dir = (char *)root_dir; + } + else { + exec_dir = cfg_args[1]; + exec_args++; + } + + res = fork(); + if (res == 0) { + chroot(exec_dir); + execve(exec_args[0], exec_args, environ); + print("<E>xec(child) : execve() failed\n"); + return 1; + } + else if (res > 0) { + print("<E>xec(parent) : waiting for termination\n"); + while (wait(&error) != res) + print("<E>xec(parent) : signal received\n"); + + error = !WIFEXITED(error); + print("<E>xec(parent) : child exited\n"); + } + else { + print("<E>xec : fork() failed\n"); + error = 1; + } + break; + } + case TOK_MA: + /* U <umask> : change umask */ + umask(a2mode(cfg_args[1])); + break; + case TOK_PR: + /* P <new_root> <put_old_relative> : pivot root */ + if (chdir(cfg_args[1]) == -1) { + error = 1; + print("<P>ivot : error during chdir(new root)\n"); + } + + if (pivot_root(".", cfg_args[2]) == -1) { + error = 1; + print("<P>ivot : error during pivot_root()\n"); + } + + chroot("."); + if (chdir(root_dir) == -1) { + error = 1; + print("<P>ivot : error during chdir(/)\n"); + } + + /* replace stdin/stdout/stderr with newer ones */ + reopen_console(); + break; + case TOK_MV: + /* K <old_dir> <new_dir> : keep directory <old_dir> after a pivot. */ + if (mount(cfg_args[1], cfg_args[2], cfg_args[1], MS_MGC_VAL | MS_BIND, NULL) == -1) { + error = 1; + print("<mv> : error during mount\n"); + } + /* fall through umount */ + case TOK_UM: + /* O <old_dir> : umount <old_dir> after a pivot. */ + if (umount(cfg_args[1]) == -1) { + error = 1; + print("<um> : error during umount\n"); + } + break; + case TOK_LO: { + /* l </dev/loopX> <file> : losetup /dev/loopX file */ + struct loop_info loopinfo; + int lfd, ffd; + + if ((lfd = open (cfg_args[1], O_RDONLY)) < 0) { + error = 1; + print("(l)osetup : error opening loop device\n"); + break; + } + if ((ffd = open (cfg_args[2], O_RDONLY)) < 0) { + error = 1; + print("(l)osetup : error opening image\n"); + goto losetup_close_all; + } + memset(&loopinfo, 0, sizeof (loopinfo)); + my_strlcpy(loopinfo.lo_name, cfg_args[2], LO_NAME_SIZE); + if (ioctl(lfd, LOOP_SET_FD, ffd) < 0) { + error = 1; + print("(l)osetup : error during LOOP_SET_FD\n"); + goto losetup_close_all; + } + if (ioctl(lfd, LOOP_SET_STATUS, &loopinfo) < 0) { + error = 1; + ioctl(lfd, LOOP_CLR_FD, 0); + print("(l)osetup : error during LOOP_SET_STATUS\n"); + goto losetup_close_all; + } + losetup_close_all: + close (lfd); close (ffd); + break; + } + default: + print("unknown cmd in /.preinit\n"); + break; + } + } /* while (token != TOK_EOF) */ + } else if (pid1) { + print("init/info : error while opening configuration file\n"); + + /* /.preinit was not found. In this case, we take default actions : + * - mount /proc + * - mount /var as tmpfs if it's empty and /tmp is a symlink + */ + if (mount(proc_dir, proc_dir, proc_fs, MS_MGC_VAL, NULL) == -1) + print("init/err: cannot mount /proc.\n"); + else + print("init/info: /proc mounted RW.\n"); + + /* we'll see if we want to build /var */ + if ((stat(var_tmp, &statf) == -1) && /* no /var/tmp */ + (stat(tmp_name, &statf) == 0) && S_ISLNK(statf.st_mode)) { /* and /tmp is a symlink */ + print("init/info: building /var.\n"); + if (mount(var_dir, var_dir, tmpfs_fs, MS_MGC_VAL, NULL) == -1) + print("init/err: cannot mount /var.\n"); + else { + int i; + print("init/info: /var has been mounted.\n"); + mkdir(var_dir, 0755); + mkdir(var_tmp, 01777); + mkdir(var_run, 0755); + print("init/info: /var has been built.\n"); + } + } + } + + if (rebuild) { + /* nothing more to do */ + return 0; + } + + /* handle the lilo command line "INIT=prog" */ + if ((cmdline_arg = find_arg("INIT")) != NULL) { + argv[0] = cmdline_arg; + argv[1] = NULL; + } + + print("init/debug: *argv = "); print (*argv); print("\n"); + umask(old_umask); + err = execve(*argv, argv, environ); + print("init/error : last execve() failed\n"); + sleep(200); + return err; +} diff --git a/init/mkdev b/init/mkdev Binary files differnew file mode 100755 index 0000000..f4a7c4b --- /dev/null +++ b/init/mkdev diff --git a/init/mkdev.c b/init/mkdev.c new file mode 100644 index 0000000..47e4aa0 --- /dev/null +++ b/init/mkdev.c @@ -0,0 +1,516 @@ +/* + WARNING ! THIS CODE IS OPTIMIZED FOR SIZE WITH COMPILED-IN ARGUMENTS. IT IS + SUBJECT TO BUFFER OVERFLOWS SO DON'T USE IT WITH RUNTIME ARGUMENTS !!! +*/ + +/* mkdev - from preinit-12 - Willy Tarreau <willy AT meta-x.org> + + usage : mkdev expression + + **** needs to rework the doc a bit since it's not up-to-date. **** + + L source dest + make a symlink from <source> to <dest> + D path [ mode ] + create a directory named <path> with the mode <mode>. If mode is left + undefined, 0755 is assumed. + B mode uid gid major minor naming_rule + create a set of block devices + C mode uid gid major minor naming_rule + create a set of char devices + F mode uid gid name + create a fifo + + The devices naming rules consist in strings mixed with numbering rules delimited with + brackets. Each numbering rule has 4 comma-separated fields : + - type of this string portion : 'c' for a single char, 'i' for an int, 'I' for an int + for which 0 is not printed, 'h' for an hex digit + - the range : + - chars: any concatenation of character ranges separated with a dash '-': 'a-fk-npq' + - ints : either an int or a range composed of 2 ints separated with a dash : '1-16' + - hex : same as int, but with hex digits (case insensitive) + - the scale : how much to add to the minor device for each step in the range. + + example : + L hda3 /dev/disk => symlinks /dev/disk to hda3 + D /var/tmp 1777 => creates a directory /var/tmp with mode 1777 + B 0600 0 0 3 1 hd[c,ab,64][i,1-16,1] => makes all hdaX and hdbX with X ranging from 1 to 16 + C 0600 0 5 2 0 pty[c,p-za-f,16][h,0-f,1] => makes all 256 pty* + +*/ + +#include <stdio.h> +#include <sys/types.h> +#include <fcntl.h> +#include <unistd.h> +#include <string.h> +#include <ctype.h> +#include <sys/mount.h> +#include <stdlib.h> +#include <sys/ioctl.h> +#include <linux/loop.h> + + +//#ifdef DEBUG +static void print(char *c) { + char *p = c; + while (*p) + p++; + write(0, c, p-c); +} +//#else +//#define print(a,...) do{}while(0) +//#endif + +typedef unsigned char uchar; + +#define UID_ROOT 0 +#define GID_ROOT 0 +#define GID_TTY 5 +#define GID_KMEM 9 + +/* used by naming rules */ +#define MAX_FIELDS 8 +#define MAX_DEVNAME_LEN 64 +#define MAX_CFG_ARGS 16 + +struct dev_varstr { + char type; + union { + struct { + char *set; + char *ptr; + char value; /* value to be printed */ + uchar index; /* index in the set */ + } chr; + struct { + uchar low; + uchar high; + uchar value; + } num; + } u; + uchar scale; +}; + +static char *cfg_args[MAX_CFG_ARGS]; +static char *cst_str[MAX_FIELDS]; +static char *var_str[MAX_FIELDS]; +static struct dev_varstr var[MAX_FIELDS]; + +/* makes a dev entry */ +static inline int mknod_chown(mode_t mode, uid_t uid, gid_t gid, uchar major, uchar minor, char *name) { + if (mknod(name, mode, makedev(major, minor)) == -1) { + print("init/error : mknod("); print(name); print(") failed\n"); + } + + if (chown(name, uid, gid) == -1) { + print("init/error : chown("); print(name); print(") failed\n"); + } +} + +/* breaks a 3-fields, comma-separated string into 3 fields */ +static inline int varstr_break(char *str, char *type, char **set, uchar *scale) { + int state; + char *res[3]; + + for (state = 0; state < 3; state++) { + res[state] = str; + while (*str && *str != ',') + str++; + if (*str) + *str++ = 0; + else if (state < 2) + return 1; + } + + *type = *res[0]; + *set = res[1]; + *scale = atol(res[2]); + return 0; +} + +/* reads a range from a string of the form "low-high" or "value". + * Returns 0 if OK, or 1 if error. + */ +static int int_range(char *from, uchar *low, uchar *high) { + char c; + *low = 0; + while ((c = *from) != '\0') { + if (isdigit(c)) + *low = *low * 10 + c - '0'; + else if (c == '-') { + low = high; + *low = 0; + } + else + return 1; + from++; + } + if (low != high) /* high has not been written to */ + *high = *low; + + return 0; +} + +/* reads a range from a hex string of the form "low-high" or "value". + * Returns 0 if OK, or 1 if error. + */ +static int hex_range(char *from, uchar *low, uchar *high) { + uchar c; + *low = 0; + while ((c = *from) != '\0') { + if (c == '-') { + low = high; /* all writes will now be done on <high> */ + *low = 0; + } + else { + if (c >= '0' && c <= '9') + c -= '0'; + else if (c >= 'a' && c <= 'f') + c -= 'a' - 10; + else if (c >= 'A' && c <= 'F') + c -= 'A' - 10; + else + return 1; + + // if (((uchar)(c -= '0') > 9) /* not a digit */ + // && (((uchar)(c -= 'A' - '0' - 10) < 0xa) || ((uchar)c > 0xf)) + // && (((uchar)(c -= 'a' - 'A') < 0xa) || ((uchar)c > 0xf))) + // return 1; + + *low = (*low << 4) + c; + } + from++; + } + if (low != high) /* high has not been written to */ + *high = *low; + + return 0; +} + +static inline char *addcst(char *dest, char *cst) { + while ((*dest++ = *cst++) != '\0'); + return dest - 1; +} + +static inline char *addchr(char *dest, char chr) { + *dest++ = chr; + *dest = '\0'; + return dest; +} + +static char *addint(char *dest, uchar num) { + int div; + int leading0 = 1; + for (div = 100; div > 0; div /= 10) { + if (!leading0 || (div == 1) || (num / div)) { + *dest++ = (num / div) + '0'; + leading0 = 0; + } + num %= div; + } + *dest = '\0'; + return dest; +} + +static char *addhex(char *dest, uchar num) { + uchar c; + if (num > 0x0F) { + c = num >> 4; + *dest++ = (c > 9) ? (c - 10 + 'a') : (c + '0'); + } + c = num & 0x0F; + *dest++ = (c > 9) ? (c - 10 + 'a') : (c + '0'); + *dest = '\0'; + return dest; +} + +/* builds a device name from the current <var> and <cst_str> arrays, + * and compute the corresponding minor number by adding all the relevant + * fields' values + */ +static void name_and_minor(char *name, uchar *minor, int fields) { + uchar min; + int f; + + min = 0; + for (f = 0; f < fields; f++) { + if (*cst_str[f]) + name = addcst(name, cst_str[f]); + switch (var[f].type) { + case 'c' : + name = addchr(name, var[f].u.chr.value); + min += var[f].u.chr.index * var[f].scale; + break; + case 'h' : + name = addhex(name, var[f].u.num.value); + goto recalc_int; + case 'i' : + name = addint(name, var[f].u.num.value); + goto recalc_int; + case 'I' : + if (var[f].u.num.value) + name = addint(name, var[f].u.num.value); + recalc_int: + min += (var[f].u.num.value - var[f].u.num.low) * var[f].scale; + break; + case 0 : + break; + default: + print("init/conf : field type must be c, h, i or I\n"); + } + } + if (minor) + *minor = min; +} + +/* increments the index for variable #f. When it overflows, it goes back to the + * beginning and a carry is returned for the next variable to be incremented. + * 0 is returned if no carry is returned, otherwise, 1 is returned. + */ +static int inc_var_index(int f) { + switch (var[f].type) { + case 'c' : + if ((var[f].u.chr.ptr[1] == '-') && (var[f].u.chr.value < var[f].u.chr.ptr[2])) { + var[f].u.chr.value++; + var[f].u.chr.index++; + return 0; + } else { /* we cannot increment within the current range */ + if (*++var[f].u.chr.ptr == '-') { + if (*++var[f].u.chr.ptr) + var[f].u.chr.ptr++; + } + if (!*var[f].u.chr.ptr) { /* no other range found */ + var[f].u.chr.value = *(var[f].u.chr.ptr = var[f].u.chr.set); + var[f].u.chr.index = 0; + return 1; + } + else { /* found a new range */ + var[f].u.chr.value = *var[f].u.chr.ptr; + var[f].u.chr.index++; + return 0; + } + } + case 'h': + case 'i': + case 'I': + if (var[f].u.num.value == var[f].u.num.high) { + var[f].u.num.value = var[f].u.num.low; + return 1; + } else { + var[f].u.num.value++; + return 0; + } + default: + return 1; /* an empty variable propagates carry */ + } +} + + +/* makes one or several device inodes depending on the rule <rule> */ +static void multidev(mode_t mode, uid_t uid, gid_t gid, uchar major, uchar minor, char *rule) { + char *p1, *p2; + int state; + int i; + + enum { + ST_STRING = 0, + ST_CONST + }; + + int field; /* each field is a couple of a cst string and a var string */ + + p1 = p2 = rule; + state = ST_STRING; + field = 0; + + cst_str[field] = var_str[field] = p2; /* be sure to point to something valid */ + + while (*p2) { + if (state == ST_STRING) { + if (*p2 == '[') { + state = ST_CONST; + cst_str[field] = p1; + *p2++ = 0; + p1 = p2; + } + else + p2++; + } + else if (state == ST_CONST) { + if (*p2 == ']') { + state = ST_STRING; + var_str[field++] = p1; + *p2++ = 0; + p1 = p2; + cst_str[field] = p1; + } + else + p2++; + } + } + + if (state == ST_STRING) { + if (p2 > p1) { + state = ST_CONST; + cst_str[field] = p1; + var_str[field++] = p2; + *p2++ = 0; + } + } + else { + print("var string incomplete\n"); + } + + /* now we must "compile" the variable fields */ + for (i = 0; i < field; i++) { + memset(&var[i], 0, sizeof(var[i])); + if (varstr_break(var_str[i], &var[i].type, &var[i].u.chr.set, &var[i].scale)) { + //print("empty variable field in string <"); print(var_str[i]); print(">\n"); + continue; + } + + switch (var[i].type) { + case 'c': + var[i].u.chr.value = *(var[i].u.chr.ptr = var[i].u.chr.set); + var[i].u.chr.index = 0; + break; + case 'h': + if (hex_range(var[i].u.chr.set, &var[i].u.num.low, &var[i].u.num.high)) { + //printf("error in hex range in <%s>\n", var_str[i]); + print("init/conf : error in hex range\n"); + continue; + } + var[i].u.num.value = var[i].u.num.low; + break; + case 'i': + case 'I': + if (int_range(var[i].u.chr.set, &var[i].u.num.low, &var[i].u.num.high)) { + print("init/conf : error in int range\n"); + //printf("error in int range in <%s>\n", var_str[i]); + continue; + } + var[i].u.num.value = var[i].u.num.low; + break; + default: + // unknown type + break; + } + } + + while (1) { + char name[MAX_DEVNAME_LEN]; + uchar minor_offset; + int f; + + name_and_minor(name, &minor_offset, field); + // printf("name = %s, minor = %d\n", name, minor + minor_offset); + + mknod_chown(mode, uid, gid, major, minor + minor_offset, name); + f = 0; + while (inc_var_index(f) && (f<field)) + f++; + + if (f >= field) + break; + } +} + +/* converts an octal permission mode into the mode_t equivalent */ +static mode_t a2mode(char *ascii) { + mode_t m = 0; + while ((unsigned)(*ascii - '0') < 8) { + m = (m << 3) | (*ascii - '0'); + ascii++; + } + return m; +} + +int main(int argc, char **argv) { + int err, arg; + char cmd; + + + if (argc > 1) + cmd = *argv[1]; + else { + print("Expect command: [BCDFL]\n"); + exit(0); + } + + argc-=2; argv+=2; + for (arg = 0; arg < MAX_CFG_ARGS; arg++) { + if (arg < argc) + cfg_args[arg] = argv[arg]; + else + cfg_args[arg] = NULL; + } + + + switch (cmd) { + case 'D': + /* D path [ mode ] : make a directory */ + if (cfg_args[0] != NULL) { + int mode = 0755; + if (cfg_args[1] != NULL) + mode = a2mode(cfg_args[1]); + + if (mkdir(cfg_args[0], mode) == -1) + print("mkdir() failed\n"); + } + else { + print("D path [ mode ]\n"); + } + break; + case 'L': + /* L from to : make a symlink */ + if (cfg_args[1] != NULL) { + if (symlink(cfg_args[0], cfg_args[1]) == -1) + print("symlink() failed\n"); + } + else { + print("L source dest\n"); + } + break; + case 'B': + /* B <mode> <uid> <gid> <major> <minor> <naming rule> : build a block device */ + if (cfg_args[5] == NULL) { + print("B mode uid gid major minor rule\n"); + break; + } + + multidev(a2mode(cfg_args[0]) | S_IFBLK, + (uid_t)atol(cfg_args[1]), (gid_t)atol(cfg_args[2]), + atol(cfg_args[3]), atol(cfg_args[4]), cfg_args[5]); + + break; + case 'C': + /* C <mode> <uid> <gid> <major> <minor> <naming rule> : build a character device */ + if (cfg_args[5] == NULL) { + print("C mode uid gid major minor rule\n"); + break; + } + + multidev(a2mode(cfg_args[0]) | S_IFCHR, + (uid_t)atol(cfg_args[1]), (gid_t)atol(cfg_args[2]), + atol(cfg_args[3]), atol(cfg_args[4]), cfg_args[5]); + + break; + case 'F': + /* F <mode> <uid> <gid> <name> : build a fifo */ + if (cfg_args[3] == NULL) { + print("F mode uid gid name\n"); + break; + } + + mknod_chown(a2mode(cfg_args[0]) | S_IFIFO, + (uid_t)atol(cfg_args[1]), (gid_t)atol(cfg_args[2]), + 0, 0, cfg_args[3]); + + break; + default: + print("Unknown command\n"); + break; + } + return 0; +} diff --git a/lcd/lcdtee b/lcd/lcdtee Binary files differnew file mode 100755 index 0000000..a94a9bd --- /dev/null +++ b/lcd/lcdtee diff --git a/lcd/lcdwrite b/lcd/lcdwrite Binary files differnew file mode 100755 index 0000000..80eac67 --- /dev/null +++ b/lcd/lcdwrite diff --git a/mii/Makefile b/mii/Makefile new file mode 100644 index 0000000..6ef0a2e --- /dev/null +++ b/mii/Makefile @@ -0,0 +1,16 @@ +OBJS=starfire-diag tulip-diag mii-diag +include ../include/rules.make +CC=gcc +CFLAGS+=-momit-leaf-frame-pointer + +all: $(OBJS) + +%-diag: %-diag.o libmii.o + $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $^ + strip -R .comment -R .note $@ + objdump -h $@ | grep -q '\.data[ ]*00000000' && strip -R .data $@ || true + sstrip $@ + +%.o: %.c + $(CC) -DLIBMII $(CFLAGS) -c -o $@ $< + diff --git a/mii/libmii.c b/mii/libmii.c new file mode 100644 index 0000000..24f0d72 --- /dev/null +++ b/mii/libmii.c @@ -0,0 +1,526 @@ +/* libmii.c: MII diagnostic and setup library.
+
+ Copyright 1997-2001 by Donald Becker.
+ This version released under the Gnu General Public License,
+ incorporated herein by reference.
+ Contact the author for use under other terms.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ References
+ http://www.scyld.com/expert/NWay.html
+ http://www.national.com/pf/DP/DP83840A.html
+*/
+
+static const char version[] =
+"libmii.c:v2.04 5/16/2001 Donald Becker (becker@scyld.com)\n"
+" http://www.scyld.com/diag/index.html\n";
+
+/* This library exports the following functions:
+ IOADDR: A token passed to the mdio_read() function.
+ PHY_ID: The MII transceiver address, passed uninterpreted to mdio_read().
+*/
+void show_mii_details(long ioaddr, int phy_id);
+int monitor_mii(long ioaddr, int phy_id);
+
+/* This library expects to be able to call the following functions: */
+extern int mdio_read(long ioaddr, int phy_id, int mii_reg_num);
+
+#include <unistd.h>
+#include <stdio.h>
+#include <time.h>
+#include <sys/time.h>
+
+typedef unsigned short u16;
+
+static const char *media_names[] = {
+ "10baseT", "10baseT-FD", "100baseTx", "100baseTx-FD", "100baseT4",
+ "Flow-control", 0,
+};
+
+static void ns83843(long ioaddr, int phy_id);
+static void qs6612(long ioaddr, int phy_id);
+static void smsc83c180(long ioaddr, int phy_id);
+static void tdk78q2120(long ioaddr, int phy_id);
+static void davicom_dm9101(long ioaddr, int phy_id);
+static void intel_i553(long ioaddr, int phy_id);
+static void enablesemi(long ioaddr, int phy_id);
+static void amd_pna(long ioaddr, int phy_id);
+static void amd_tx(long ioaddr, int phy_id);
+static void admtek(long ioaddr, int phy_id);
+static void lu3x31(long ioaddr, int phy_id);
+static void myson981(long ioaddr, int phy_id);
+
+struct mii_partnum {
+ const char *vendor; /* Vendor name. */
+ u16 phy_id0; /* Vendor ID (alternate ver. of ieee_oui[]) */
+ u16 phy_id1; /* Vendor ID (alternate ver. of ieee_oui[]) */
+ unsigned char ieee_oui[3]; /* IEEE-assigned organizationally unique ID */
+ char flags;
+ void (*(func))(long xcvr_if, int phy_id);/* Function to emit more info. */
+} static oui_map[] = {
+ {"Unknown transceiver type", 0x0000, 0x0000, {0,}, 0, NULL,},
+ {"National Semiconductor 83840A", 0x2000, 0x5c01, {0,}, 0, NULL,},
+ {"National Semiconductor 83843", 0x2000, 0x5c10, {0,}, 0, ns83843, },
+ {"Level One LXT970", 0x7810, 0x0000, {0,}, 0, NULL, },
+ {"Level One LXT971", 0x7810, 0x0001, {0,}, 0, NULL, },
+ {"Level One LXT971A",0x7810, 0x0003, {0,}, 0, NULL, },
+ {"Level One (unknown type)", 0, 0, {0x1e,0x04,0x00}, 0, NULL, },
+ {"Davicom DM9101", 0x0181, 0xB800, {0,}, 0, davicom_dm9101, },
+ {"Davicom (unknown type)", 0, 0, {0x00, 0x60, 0x6e}, 0, davicom_dm9101, },
+ {"Quality Semiconductor QS6612", 0x0181, 0x4410, {0,}, 0, qs6612},
+ {"Quality Semiconductor (unknown type)", 0,0, {0x00, 0x60, 0x51}, 0, NULL},
+ {"SMSC 83c180", 0x0282, 0x1C51, {0}, 0, smsc83c180, },
+ {"TDK Semiconductor 78Q2120", 0x0300, 0xE542, {0,}, 0, tdk78q2120, },
+ {"TDK Semiconductor 78Q2120", 0x0300, 0xE543, {0,}, 0, tdk78q2120, },
+ {"TDK transceiver (unknown type)", 0,0, {0x00, 0xc0, 0x39}, 0, tdk78q2120},
+ {"Intel (unknown type)", 0,0, {0x00, 0xf8, 0x00}, 0, intel_i553},
+ {"Enable Semiconductor EL40-331", 0x0043, 0x7411, {0,}, 0, enablesemi},
+ {"AMD 79c901A.1 HomePNA", 0x0000, 0x6B91, {0,}, 0, amd_pna},
+ {"AMD 79c901A.2 HomePNA", 0x0000, 0x6B92, {0,}, 0, amd_pna},
+ {"AMD 79c901A.3 HomePNA", 0x0000, 0x6B93, {0,}, 0, amd_pna},
+ {"AMD 79c901A.3 10baseT", 0x0000, 0x6B71, {0,}, 0, amd_tx},
+ {"AdHoc Technology AH101LF", 0x0022, 0x561B, {0,}, 0, tdk78q2120},
+ {"Altimata Communications AC101LF", 0x0022, 0x5523, {0,}, 0, tdk78q2120},
+ {"Altimata Comm (unknown type)", 0, 0, {0x00,0x10,0xA9}, 0, tdk78q2120},
+ {"ASIX (unknown type)", 0, 0, {0x00,0xC0,0xB4}, 0, tdk78q2120},
+ {"ADMtek AN983 Comet", 0x0022, 0x5410, {0,}, 0, admtek},
+ {"ADMtek AN985 Comet", 0x0022, 0x5513, {0,}, 0, admtek},
+ {"ADMtek (unknown type)", 0, 0, {0x00,0xe0,0x92}, 0, admtek},
+ {"Lucent LU6612", 0x0180, 0x7641, {0,}, 0, qs6612},
+ {"Lucent LU3X31", 0x0043, 0x7411, {0,}, 0, lu3x31},
+ {"LSI Logic (Seeq) 80225", 0, 0, {0x00,0xA0,0x7D}, 0, NULL},
+ {"Myson MTD981", 0x0302, 0xD000, {0,}, 0, myson981},
+ {"Myson (unknown type)", 0, 0, {0x00,0xC0,0xB4,}, 0, myson981},
+ {0, },
+};
+
+static u16 mii_val[32];
+
+void show_mii_details(long ioaddr, int phy_id)
+{
+ int mii_reg, i, vendor = 0;
+ u16 bmcr, bmsr, new_bmsr;
+
+ printf(" MII PHY #%d transceiver registers:", phy_id);
+ for (mii_reg = 0; mii_reg < 32; mii_reg++) {
+ mii_val[mii_reg] = mdio_read(ioaddr, phy_id, mii_reg);
+ printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "",
+ mii_val[mii_reg]);
+ }
+ printf(".\n");
+ if (mii_val[0] == 0xffff) {
+ printf(" No MII transceiver present!.\n");
+ return;
+ }
+ bmcr = mii_val[0];
+ bmsr = mii_val[1];
+ printf(" Basic mode control register 0x%4.4x:", bmcr);
+ if (bmcr & 0x1000)
+ printf(" Auto-negotiation enabled.\n");
+ else
+ printf(" Auto-negotiation disabled!\n"
+ " Speed fixed at 10%s mbps, %s-duplex.\n",
+ bmcr & 0x2000 ? "0" : "",
+ bmcr & 0x0100 ? "full":"half");
+ if (bmcr & 0x8000)
+ printf(" Transceiver currently being reset!\n");
+ if (bmcr & 0x4000)
+ printf(" Transceiver in loopback mode!\n");
+ if (bmcr & 0x0800)
+ printf(" Transceiver powered down!\n");
+ if (bmcr & 0x0400)
+ printf(" Transceiver isolated from the MII!\n");
+ if (bmcr & 0x0200)
+ printf(" Restarted auto-negotiation in progress!\n");
+ if (bmcr & 0x0080)
+ printf(" Internal Collision-Test enabled!\n");
+
+ new_bmsr = mdio_read(ioaddr, phy_id, 1);
+ printf(" Basic mode status register 0x%4.4x ... %4.4x.\n"
+ " Link status: %sestablished.\n"
+ " Capable of ",
+ bmsr, new_bmsr,
+ bmsr & 0x0004 ? "" :
+ (new_bmsr & 0x0004) ? "previously broken, but now re" : "not ");
+ if (bmsr & 0xF800) {
+ for (i = 15; i >= 11; i--)
+ if (bmsr & (1<<i))
+ printf(" %s", media_names[i-11]);
+ } else
+ printf("<Warning! No media capabilities>");
+
+ printf(".\n"
+ " %s to perform Auto-negotiation, negotiation %scomplete.\n",
+ bmsr & 0x0008 ? "Able" : "Unable",
+ bmsr & 0x0020 ? "" : "not ");
+
+ if (bmsr & 0x0010)
+ printf(" Remote fault detected!\n");
+ if (bmsr & 0x0002)
+ printf(" *** Link Jabber! ***\n");
+
+ if (mii_val[2] ^ mii_val[3]) { /* Eliminate 0x0000 and 0xffff IDs. */
+ unsigned char oui_0 = mii_val[2] >> 10;
+ unsigned char oui_1 = mii_val[2] >> 2;
+ unsigned char oui_2 = (mii_val[2] << 6) | (mii_val[3] >> 10);
+
+ printf(" Vendor ID is %2.2x:%2.2x:%2.2x:--:--:--, model %d rev. %d.\n",
+ oui_0, oui_1, oui_2,
+ ((mii_val[3] >> 4) & 0x3f), mii_val[3] & 0x0f);
+ for ( i = 0; oui_map[i].vendor; i++)
+ /* We match either the Phy ID or the IEEE OUI. */
+ if ((oui_map[i].phy_id0 == mii_val[2] &&
+ oui_map[i].phy_id1 == mii_val[3]) ||
+ (oui_map[i].ieee_oui[0] == oui_0 &&
+ oui_map[i].ieee_oui[1] == oui_1 &&
+ oui_map[i].ieee_oui[2] == oui_2)) {
+ printf(" Vendor/Part: %s.\n", oui_map[i].vendor);
+ vendor = i;
+ break;
+ }
+ if (oui_map[i].vendor == NULL)
+ printf(" No specific information is known about this transceiver"
+ " type.\n");
+ } else
+ printf(" This transceiver has no vendor identification.\n");
+
+ {
+ int nway_advert = mii_val[4];
+ int lkpar = mii_val[5];
+ printf(" I'm advertising %4.4x:", nway_advert);
+ for (i = 10; i >= 5; i--)
+ if (nway_advert & (1<<i))
+ printf(" %s", media_names[i-5]);
+ printf("\n Advertising %sadditional info pages.\n",
+ nway_advert & 0x8000 ? "" : "no ");
+ if ((nway_advert & 31) == 1)
+ printf(" IEEE 802.3 CSMA/CD protocol.\n");
+ else
+ printf(" Using an unknown (non 802.3) encapsulation.\n");
+ printf(" Link partner capability is %4.4x:",
+ lkpar);
+ for (i = 10; i >= 5; i--)
+ if (lkpar & (1<<i))
+ printf(" %s", media_names[i-5]);
+ printf(".\n Negotiation %s.\n",
+ lkpar & 0x4000 ? " completed" : "did not complete");
+ }
+ if (oui_map[vendor].func)
+ oui_map[vendor].func(ioaddr, phy_id);
+
+}
+
+int monitor_mii(long ioaddr, int phy_id)
+{
+ int i, last_event = 0;
+ unsigned short new_1, baseline_1 = mdio_read(ioaddr, phy_id, 1);
+ struct timeval tv, sleepval;
+ time_t cur_time;
+ char timebuf[12];
+
+ if (baseline_1 == 0xffff) {
+ fprintf(stderr, "No MII transceiver present to monitor.\n");
+ return -1;
+ }
+
+ gettimeofday(&tv, NULL);
+ cur_time = tv.tv_sec;
+ strftime(timebuf, sizeof(timebuf), "%H:%M:%S", localtime(&cur_time));
+
+ printf("Monitoring the MII transceiver status.\n"
+ "%s.%03d Baseline value of MII BMSR (basic mode status register)"
+ " is %4.4x.\n", timebuf, (int)tv.tv_usec/1000, baseline_1);
+ while (1) {
+ new_1 = mdio_read(ioaddr, phy_id, 1);
+ if (new_1 == 0xffff) {
+ fprintf(stderr, "The MII transceiver is no longer accessable!\n");
+ return -1;
+ }
+ if (new_1 != baseline_1) {
+ gettimeofday(&tv, NULL);
+ cur_time = tv.tv_sec;
+ strftime(timebuf, sizeof(timebuf), "%H:%M:%S",
+ localtime(&cur_time));
+ printf("%s.%03d MII BMSR now %4.4x: %4s link, NWay %s, "
+ "%3sJabber%s (%4.4x).\n",
+ timebuf, (int)tv.tv_usec/1000, new_1,
+ new_1 & 0x04 ? "Good" : "no",
+ new_1 & 0x20 ? "done" : "busy",
+ new_1 & 0x02 ? "" : "No ",
+ new_1 & 0x10 ? ", remote fault" : "",
+ mdio_read(ioaddr, phy_id, 5)
+ );
+ if (!(baseline_1 & 0x20) && (new_1 & 0x20)) {
+ int lkpar = mdio_read(ioaddr, phy_id, 5);
+ printf(" New link partner capability is %4.4x %4.4x:",
+ lkpar, mdio_read(ioaddr, phy_id, 6));
+ switch (lkpar) {
+ case 0x45e1: printf(" 10/100 switch w/ flow control"); break;
+ case 0x41e1: printf(" 10/100 HD+FD switch"); break;
+ case 0x40a1: printf(" 10/100 bridged repeater"); break;
+ case 0x4081: printf(" 100baseTx repeater w/autonegotation");
+ break;
+ case 0x0081: printf(" 100baseTx (no autonegotation)"); break;
+ case 0x4021: printf(" 10baseT repeater w/autonegotation");
+ break;
+ case 0x0021: printf(" 10baseT (no autonegotation)"); break;
+ default:
+ for (i = 9; i >= 5; i--)
+ if (lkpar & (1<<i))
+ printf(" %s", media_names[i-5]);
+ }
+ printf(".\n");
+ }
+ baseline_1 = new_1;
+ last_event = 0;
+ }
+ sleepval.tv_sec = 0;
+ sleepval.tv_usec = last_event++ > 30 ? 200000 : 1000;
+ select(0, 0, 0, 0, &sleepval); /* Or just sleep(1); */
+ }
+ printf(" Value of MII BMSR (basic mode status register) is %4.4x.\n",
+ mdio_read(ioaddr, phy_id, 1));
+ return 0;
+}
+
+/* Emit transceiver-specific info. */
+
+struct msg_tbl { int bitmask; char *msg; };
+
+static void msg_if_set(const int val, const struct msg_tbl msg_tbl[])
+{
+ int i;
+ for (i = 0; msg_tbl[i].bitmask; i++)
+ if (msg_tbl[i].bitmask & val)
+ printf(" %s\n", msg_tbl[i].msg);
+}
+
+static void qs6612(long ioaddr, int phy_id)
+{
+ printf(" QS6612 extra registers: Mode %4.4x.\n"
+ " Interrupt source %4.4x, mask %4.4x.\n"
+ " PHY control %4.4x.\n",
+ mii_val[17], mii_val[29], mii_val[30], mii_val[31]);
+ return;
+}
+
+static void ns83843(long ioaddr, int phy_id)
+{
+ printf(" NatSemi 83843 extra registers:\n"
+ " PHY status %4.4x\n"
+ " %s link, %d Mb/sec %s duplex\n"
+ " MII interrupts %sabled, %s pending.\n"
+ " Events since last read\n"
+ " Link disconnects %d\n"
+ " False carriers %d\n"
+ " Receive errors %d\n"
+ " Link beat is currently %sstable\n",
+ mii_val[0x10],
+ mii_val[10] & 0x0001 ? "Valid" : "Invalid",
+ mii_val[10] & 0x0002 ? 10 : 100,
+ mii_val[10] & 0x0004 ? "full" : "half",
+ mii_val[0x11] & 0x0002 ? "en":"dis",
+ mii_val[0x10] & 0x0100 ? "interrupt": "none",
+ mii_val[0x13], mii_val[0x14], mii_val[0x15],
+ mii_val[0x16] & 0x0010 ? "UN" : "");
+ return;
+}
+static void smsc83c180(long ioaddr, int phy_id)
+{
+ int mii_reg25 = mii_val[25];
+ printf(" SMSC 83c180 extra registers:\n"
+ " Auto-negotiation status 0x%4.4x.\n"
+ " 10baseT polarity is %s.\n"
+ " PHY address is %d.\n"
+ " Auto-negotiation %scomplete, 1%s0Mbps %s duplex.\n"
+ " Rx symbol errors since last read %d.\n",
+ mii_reg25,
+ mii_reg25 & 0x2000 ? "normal" : "reversed",
+ (mii_reg25>>8) & 0x1F,
+ mii_reg25 & 0x0080 ? "did not " : "",
+ mii_reg25 & 0x0020 ? "0" : "",
+ mii_reg25 & 0x0040 ? "full" : "half",
+ mdio_read(ioaddr, phy_id, 26));
+ return;
+}
+
+static const char *tdk_events[8] = {
+ "Jabber", "Rx error", "Negotiation page received", "Link detection fault",
+ "Link partner acknowledge", "Link status change", "Remote partner fault",
+ "Auto-Negotiation complete"};
+
+static const struct msg_tbl tdk_reg16[] = {
+ {0x8000, " Transceiver is in repeater mode!"},
+ {0x4000, " Interrupt pin set to active high."},
+ {0x2000, " Reserved bit 12 is unexpectedly set."},
+ {0x1000, " Transmit pins are internally disconnected."},
+ {0x0800, " 10baseT signal quality test is disabled."},
+ {0x0400, " 10baseT loopback mode."},
+ {0, 0},
+};
+
+static void tdk78q2120(long ioaddr, int phy_id)
+{
+ int mii_reg16 = mii_val[16];
+ int mii_reg17 = mii_val[17];
+ int mii_reg18 = mii_val[18];
+ int i;
+ printf(" TDK format vendor-specific registers 16..18 are "
+ "0x%4.4x 0x%4.4x 0x%4.4x\n", mii_reg16, mii_reg17, mii_reg18);
+ printf(" Link polarity is %s %s.\n"
+ "%s%s"
+ " Auto-negotiation %s, 1%s0Mbps %s duplex.\n"
+ " Rx link in %s state, PLL %s.\n",
+ mii_reg16 & 0x0020 ? "OVERRIDDEN to" : "detected as",
+ mii_reg16 & 0x0010 ? "reversed" : "normal",
+ mii_reg16 & 0x0002 ?
+ " 100baseTx Coding and scrambling is disabled!\n":"",
+ mii_reg16 & 0x0001 ? " Rx_CLK power-save mode is enabled!\n":"",
+ mii_reg18 & 0x1000 ? "had no common media" : "complete",
+ mii_reg18 & 0x0400 ? "0" : "",
+ mii_reg18 & 0x0800 ? "full" : "half",
+ mii_reg18 & 0x0200 ? "pass" : "fail",
+ mii_reg18 & 0x0100 ? "slipped since last read" : "locked");
+
+ msg_if_set(mii_reg16, tdk_reg16);
+ if (mii_reg17 & 0x00ff) {
+ printf(" Events since last read:");
+ for (i = 0; i < 8; i++)
+ if (mii_reg17 & (1 << i))
+ printf(" %s", tdk_events[i]);
+ } else
+ printf(" No new link status events.");
+
+ if (mii_reg17 & 0xff00) {
+ printf("\n Events that will raise an interrupt:");
+ for (i = 0; i < 8; i++)
+ if (mii_reg17 & (0x100 << i))
+ printf(" %s", tdk_events[i]);
+ }
+ printf("\n");
+ return;
+}
+
+static void davicom_dm9101(long ioaddr, int phy_id)
+{
+ printf(" Davicom vendor specific registers: 0x%4.4x 0x%4.4x 0x%4.4x.\n",
+ mii_val[16], mii_val[17], mii_val[18]);
+}
+static void intel_i553(long ioaddr, int phy_id)
+{
+ printf(" This transceiver is 100baseT4 only! Register 16 is %4.4x.\n",
+ mii_val[16]);
+}
+/* http://www.enablesemi.com/cgi-bin/byteserve/Products/Docs/3VCardBus.pdf */
+static void enablesemi(long ioaddr, int phy_id)
+{
+ printf(" Isolated %d times, %d false carrier events, %d Rx errors.\n",
+ mii_val[18], mii_val[19], mii_val[21]);
+ printf(" Cable polarity is %s, 100Mb PLL is %slocked.\n",
+ mii_val[28]&0x8000 ? "reversed" : "normal",
+ mii_val[27]&0x2000 ? "" : "un");
+}
+/* The amd79c901 contains both PNA and 10/100 management registers.
+ http://www.amd.com/products/npd/techdocs/22304.pdf
+*/
+static void amd_pna(long ioaddr, int phy_id)
+{
+ printf(" HomePNA transceiver in %s speed, %s power mode.\n",
+ mii_val[16] & 4 ? "high" : "low",
+ mii_val[16] & 2 ? "high" : "low");
+ printf(" HomePNA noise level %d, peak power %d..\n",
+ mii_val[25] >> 8, mii_val[25] & 0xff);
+}
+static void amd_tx(long ioaddr, int phy_id)
+{
+ int mii_reg25 = mii_val[25];
+ printf(" AMD vendor specific registers: 0x%4.4x 0x%4.4x 0x%4.4x.\n",
+ mii_val[16], mii_val[17], mii_val[18]);
+ printf(" The link is %s in 10%s %s duplex mode, autonegotiation state "
+ "has%s changed.\n",
+ mii_reg25 & 8 ? "up" : "down",
+ mii_reg25 & 1 ? "0baseTx" : "baseT",
+ mii_reg25 & 4 ? "full" : "half",
+ mii_reg25 & 2 ? "" : " not");
+}
+
+static const struct msg_tbl admtek_reg21[] = {
+ {0x4000, " Link test diabled: Ignoring lack of 10baseT link beat."},
+ {0x2000, " Link forced up."},
+ {0x1000, " Tx jabber check disabled."},
+ {0x0080, " Transmitting 'Far End Fault'!"},
+ {0x0040, " Rx error count full."},
+ {0x0008, " Remote loop back enabled."},
+ {0, 0},
+};
+
+static void admtek(long ioaddr, int phy_id)
+{
+
+ printf(" ADMtek vendor specific registers information:\n"
+ " Cable length is approximately %d meters.\n"
+ " The receiver has lost lock %d times since last check and "
+ "had %d error events.\n",
+ ((mii_val[20] & 0x00f0) >> 4)*10,
+ mii_val[23], mii_val[23]);
+ msg_if_set(mii_val[21], admtek_reg21);
+ tdk78q2120(ioaddr, phy_id);
+}
+
+static void lu3x31(long ioaddr, int phy_id)
+{
+ printf(" Lucent vendor specific registers 17: 0x%4.4x"
+ " 29: 0x%4.4x 30: 0x%4.4x 31: 0x%4.4x.\n",
+ mii_val[17], mii_val[29], mii_val[30], mii_val[31]);
+}
+
+static const struct msg_tbl myson_reg16[] = {
+ {0x0080, " Far end fault enabled."},
+ {0x0040, " Transformer ratio 1.25:1."},
+ {0x0020, " Polarity correction diabled."},
+ {0x0010, " Link is forced up regardless of link beat."},
+ {0x0004, " Bypass Jabber check."},
+ {0x0001, " 100baseFx mode selected."},
+ {0, 0},
+};
+
+static void myson981(long ioaddr, int phy_id)
+{
+ int i, mii_reg17 = mii_val[17];
+
+ printf(" Myson mtd981 extra registers: %4.4x %4.4x %4.4x %4.4x.\n",
+ mii_val[16], mii_val[17], mii_val[18], mii_val[19]);
+ msg_if_set(mii_val[16] & 0xC800, tdk_reg16);
+ msg_if_set(mii_val[16], myson_reg16);
+
+ if (mii_reg17 & 0x00ff) {
+ printf(" Events since last read:");
+ for (i = 0; i < 8; i++)
+ if (mii_reg17 & (1 << i))
+ printf(" %s", tdk_events[i]);
+ } else
+ printf(" No new link status events.");
+ if (mii_reg17 & 0xff00) {
+ printf("\n Events that will raise an interrupt:");
+ for (i = 0; i < 8; i++)
+ if (mii_reg17 & (0x100 << i))
+ printf(" %s", tdk_events[i]);
+ }
+ printf("\n");
+
+ return;
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "cc -O -Wall -c libmii.c"
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * End:
+ */
diff --git a/mii/mii-diag.c b/mii/mii-diag.c new file mode 100644 index 0000000..384fb5b --- /dev/null +++ b/mii/mii-diag.c @@ -0,0 +1,457 @@ +/* Mode: C;
+ * mii-diag.c: Examine and set the MII registers of a network interfaces.
+
+ Usage: mii-diag [-vw] interface.
+
+ Notes:
+ The compile-command is at the end of this source file.
+ This program only works with drivers that implement MII ioctl() calls.
+
+ Written/copyright 1997-2001 by Donald Becker <becker@scyld.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.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ References
+ http://scyld.com/expert/mii-status.html
+ http://scyld.com/expert/NWay.html
+ http://www.national.com/pf/DP/DP83840.html
+*/
+
+static char version[] =
+"mii-diag.c:v2.02 5/21/2001 Donald Becker (becker@scyld.com)\n"
+" http://www.scyld.com/diag/index.html\n";
+
+static const char usage_msg[] =
+"Usage: mii-diag [-aDfrRvVw] [-AF <to-advertise>] [--watch] <interface>.\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 <net/if.h>
+#ifdef use_linux_libc5
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#endif
+
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+//#ifndef SIOCGMIIPHY
+#define SIOCGMIIPHY (SIOCDEVPRIVATE) /* Get the PHY in use. */
+#define SIOCGMIIREG (SIOCDEVPRIVATE+1) /* Read a PHY register. */
+#define SIOCSMIIREG (SIOCDEVPRIVATE+2) /* Write a PHY register. */
+#define SIOCGPARAMS (SIOCDEVPRIVATE+3) /* Read operational parameters. */
+#define SIOCSPARAMS (SIOCDEVPRIVATE+4) /* Set operational parameters. */
+//#endif
+
+struct option longopts[] = {
+ /* { name has_arg *flag val } */
+ {"all-interfaces", 0, 0, 'a'}, /* Show all interfaces. */
+ {"Advertise", 1, 0, 'A'}, /* Change the capabilities advertised. */
+ {"debug", 0, 0, 'D'}, /* Increase the debug level. */
+ {"force", 0, 0, 'f'}, /* Force the operation. */
+ {"parameters", 0, 0, 'G'}, /* Write general settings value. */
+ {"phy", 1, 0, 'p'}, /* Set the PHY (MII address) to report. */
+ {"restart", 0, 0, 'r'}, /* Restart the link negotiation */
+ {"Reset", 0, 0, 'R'}, /* Reset the transceiver. */
+ {"status", 0, 0, 's'}, /* Non-zero exit status w/ no link beat. */
+ {"help", 0, 0, '?'}, /* Give help */
+ {"verbose", 0, 0, 'v'}, /* Report each action taken. */
+ {"version", 0, 0, 'V'}, /* Emit version information. */
+ {"watch", 0, 0, 'w'}, /* Constantly monitor the port. */
+ { 0, 0, 0, 0 }
+};
+
+/* Usually in libmii.c, but trivial substitions are below. */
+extern int show_mii_details(long ioaddr, int phy_id);
+extern void monitor_mii(long ioaddr, int phy_id);
+
+/* Command-line flags. */
+unsigned int opt_a = 0, /* Show-all-interfaces flag. */
+ opt_f = 0, /* Force the operation. */
+ opt_G = 0, opt_G_value = 0,
+ verbose = 0, /* Verbose flag. */
+ debug = 0,
+ opt_version = 0,
+ opt_restart = 0,
+ opt_reset = 0,
+ opt_status = 0,
+ opt_watch = 0;
+static int nway_advertise = -1;
+static int fixed_speed = -1;
+static int override_phy = -1;
+int skfd = -1; /* AF_INET socket for ioctl() calls. */
+struct ifreq ifr;
+
+int do_one_xcvr(int skfd);
+int show_basic_mii(long ioaddr, int phy_id);
+int mdio_read(int skfd, int phy_id, int location);
+void mdio_write(int skfd, int phy_id, int location, int value);
+static int parse_advertise(const char *capabilities);
+
+
+int
+main(int argc, char **argv)
+{
+ int c, errflag = 0;
+ char **spp, *ifname;
+
+ while ((c = getopt_long(argc, argv, "aA:DfF:G:p:rRsvVw?", longopts, 0)) != EOF)
+ switch (c) {
+ case 'a': opt_a++; break;
+ case 'A': nway_advertise = parse_advertise(optarg); break;
+ case 'D': debug++; break;
+ case 'f': opt_f++; break;
+ case 'F': fixed_speed = parse_advertise(optarg); break;
+ case 'G': opt_G++; opt_G_value = atoi(optarg); break;
+ case 'p': override_phy = atoi(optarg); break;
+ case 'r': opt_restart++; break;
+ case 'R': opt_reset++; break;
+ case 's': opt_status++; break;
+ case 'v': verbose++; break;
+ case 'V': opt_version++; break;
+ case 'w': opt_watch++; break;
+ case '?': errflag++;
+ }
+ if (errflag) {
+ fprintf(stderr, usage_msg);
+ return 2;
+ }
+
+ if (verbose || opt_version)
+ printf(version);
+
+ /* Open a basic socket. */
+ if ((skfd = socket(AF_INET, SOCK_DGRAM,0)) < 0) {
+ perror("socket");
+ exit(-1);
+ }
+
+ if (debug)
+ 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) {
+ ifname = "eth0";
+ fprintf(stderr, "Using the default interface 'eth0'.\n");
+ } else {
+ /* Copy the interface name. */
+ spp = argv + optind;
+ ifname = *spp++;
+ }
+
+ if (ifname == NULL) {
+ ifname = "eth0";
+ fprintf(stderr, "Using the default interface 'eth0'.\n");
+ }
+
+ /* Get the vitals from the interface. */
+ strncpy(ifr.ifr_name, ifname, IFNAMSIZ);
+ if (ioctl(skfd, SIOCGMIIPHY, &ifr) < 0) {
+ fprintf(stderr, "SIOCGMIIPHY on %s failed: %s\n", ifname,
+ strerror(errno));
+ (void) close(skfd);
+ return 1;
+ }
+
+ do_one_xcvr(skfd);
+
+ (void) close(skfd);
+ return 0;
+}
+
+int do_one_xcvr(int skfd)
+{
+ u16 *data = (u16 *)(&ifr.ifr_data);
+ unsigned phy_id = data[0];
+
+ if (override_phy >= 0) {
+ printf("Using the specified MII PHY index %d.\n", override_phy);
+ phy_id = override_phy;
+ }
+
+ if (opt_G) {
+ /* Set an undefined general-purpose value.
+ Modify this code section to do special hacks such as
+ mdio_write(skfd, phy_id, 19, opt_G_value);
+ */
+ u32 *data = (u32 *)(&ifr.ifr_data);
+ data[0] = opt_G_value;
+ if (ioctl(skfd, SIOCSPARAMS, &ifr) < 0) {
+ fprintf(stderr, "SIOCSPARAMS on %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+ return -1;
+ }
+ }
+
+ if (opt_reset) {
+ printf("Resetting the transceiver...\n");
+ mdio_write(skfd, phy_id, 0, 0x8000);
+ }
+ /* Note: PHY addresses > 32 are pseudo-MII devices, usually built-in. */
+ if (phy_id < 64 && nway_advertise >= 0) {
+ printf(" Setting the media capability advertisement register of "
+ "PHY #%d to 0x%4.4x.\n", phy_id, nway_advertise | 1);
+ mdio_write(skfd, phy_id, 4, nway_advertise | 1);
+ mdio_write(skfd, phy_id, 0, 0x1000);
+ }
+
+ if (opt_restart) {
+ printf("Restarting negotiation...\n");
+ mdio_write(skfd, phy_id, 0, 0x0000);
+ mdio_write(skfd, phy_id, 0, 0x1200);
+ }
+ /* To force 100baseTx-HD do mdio_write(skfd, phy_id, 0, 0x2000); */
+ if (fixed_speed >= 0) {
+ int reg0_val = 0;
+ if (fixed_speed & 0x0180) /* 100mpbs */
+ reg0_val |= 0x2000;
+ if (fixed_speed & 0x0140) /* Full duplex */
+ reg0_val |= 0x0100;
+ printf("Setting the speed to \"fixed\", Control register %4.4x.\n",
+ reg0_val);
+ mdio_write(skfd, phy_id, 0, reg0_val);
+ }
+
+ show_basic_mii(skfd, phy_id);
+#ifdef LIBMII
+ if (verbose)
+ show_mii_details(skfd, phy_id);
+#else
+ if (verbose || debug) {
+ int mii_reg, mii_val;
+ printf(" MII PHY #%d transceiver registers:", phy_id);
+ for (mii_reg = 0; mii_reg < 32; mii_reg++) {
+ mii_val = mdio_read(skfd, phy_id, mii_reg);
+ printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "",
+ mii_val);
+ }
+ printf("\n");
+ }
+#endif
+
+ if (opt_watch)
+ monitor_mii(skfd, phy_id);
+ if (opt_status &&
+ (mdio_read(skfd, phy_id, 1) & 0x0004) == 0)
+ exit(2);
+ return 0;
+}
+
+int mdio_read(int skfd, int phy_id, int location)
+{
+ u16 *data = (u16 *)(&ifr.ifr_data);
+
+ data[0] = phy_id;
+ data[1] = location;
+
+ if (ioctl(skfd, SIOCGMIIREG, &ifr) < 0) {
+ fprintf(stderr, "SIOCGMIIREG on %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+ return -1;
+ }
+ return data[3];
+}
+
+void mdio_write(int skfd, int phy_id, int location, int value)
+{
+ u16 *data = (u16 *)(&ifr.ifr_data);
+
+ data[0] = phy_id;
+ data[1] = location;
+ data[2] = value;
+
+ if (ioctl(skfd, SIOCSMIIREG, &ifr) < 0) {
+ fprintf(stderr, "SIOCSMIIREG on %s failed: %s\n", ifr.ifr_name,
+ strerror(errno));
+ }
+}
+
+/* Parse the command line argument for advertised capabilities. */
+static int parse_advertise(const char *capabilities)
+{
+ const char *mtypes[] = {
+ "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD",
+ "10baseT", "10baseT-FD", "10baseT-HD", 0,
+ };
+ int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,};
+ int i;
+ if ( ! capabilities) {
+ fprintf(stderr, "You passed -A 'NULL'. You must provide a media"
+ " list to advertise!\n");
+ return -1;
+ }
+ if (debug)
+ fprintf(stderr, "Advertise string is '%s'.\n", capabilities);
+ for (i = 0; mtypes[i]; i++)
+ if (strcasecmp(mtypes[i], capabilities) == 0)
+ return cap_map[i];
+ if ((i = strtol(capabilities, NULL, 16)) <= 0xffff)
+ return i;
+ fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities);
+ return -1;
+}
+
+/* Trivial versions if we don't link against libmii.c */
+static const char *media_names[] = {
+ "10baseT", "10baseT-FD", "100baseTx", "100baseTx-FD", "100baseT4",
+ "Flow-control", 0,
+};
+/* Various non-good bits in the command register. */
+static const char *bmcr_bits[] = {
+ " Internal Collision-Test enabled!\n", "", /* 0x0080,0x0100 */
+ " Restarted auto-negotiation in progress!\n",
+ " Transceiver isolated from the MII!\n",
+ " Transceiver powered down!\n", "", "",
+ " Transceiver in loopback mode!\n",
+ " Transceiver currently being reset!\n",
+};
+
+int show_basic_mii(long ioaddr, int phy_id)
+{
+ int mii_reg, i;
+ u16 mii_val[32];
+ u16 bmcr, bmsr, new_bmsr, nway_advert, lkpar;
+
+ for (mii_reg = 0; mii_reg < 8; mii_reg++)
+ mii_val[mii_reg] = mdio_read(ioaddr, phy_id, mii_reg);
+ if ( ! verbose) {
+ printf("Basic registers of MII PHY #%d: ", phy_id);
+ for (mii_reg = 0; mii_reg < 8; mii_reg++)
+ printf(" %4.4x", mii_val[mii_reg]);
+ printf(".\n");
+ }
+
+ if (mii_val[0] == 0xffff) {
+ printf(" No MII transceiver present!.\n");
+ return -1;
+ }
+ /* Descriptive rename. */
+ bmcr = mii_val[0];
+ bmsr = mii_val[1];
+ nway_advert = mii_val[4];
+ lkpar = mii_val[5];
+
+ if (lkpar & 0x4000) {
+ int negotiated = nway_advert & lkpar & 0x3e0;
+ int max_capability = 0;
+ /* Scan for the highest negotiated capability, highest priority
+ (100baseTx-FDX) to lowest (10baseT-HDX). */
+ int media_priority[] = {8, 9, 7, 6, 5}; /* media_names[i-5] */
+ printf(" The autonegotiated capability is %4.4x.\n", negotiated);
+ for (i = 0; media_priority[i]; i++)
+ if (negotiated & (1 << media_priority[i])) {
+ max_capability = media_priority[i];
+ break;
+ }
+ if (max_capability)
+ printf("The autonegotiated media type is %s.\n",
+ media_names[max_capability - 5]);
+ else
+ printf("No common media type was autonegotiated!\n"
+ "This is extremely unusual and typically indicates a "
+ "configuration error.\n" "Perhaps the advertised "
+ "capability set was intentionally limited.\n");
+ }
+ printf(" Basic mode control register 0x%4.4x:", bmcr);
+ if (bmcr & 0x1000)
+ printf(" Auto-negotiation enabled.\n");
+ else
+ printf(" Auto-negotiation disabled, with\n"
+ " Speed fixed at 10%s mbps, %s-duplex.\n",
+ bmcr & 0x2000 ? "0" : "",
+ bmcr & 0x0100 ? "full":"half");
+ for (i = 0; i < 9; i++)
+ if (bmcr & (0x0080<<i))
+ printf(bmcr_bits[i]);
+
+ new_bmsr = mdio_read(ioaddr, phy_id, 1);
+ if ((bmsr & 0x0016) == 0x0004)
+ printf( " You have link beat, and everything is working OK.\n");
+ else
+ printf(" Basic mode status register 0x%4.4x ... %4.4x.\n"
+ " Link status: %sestablished.\n",
+ bmsr, new_bmsr,
+ bmsr & 0x0004 ? "" :
+ (new_bmsr & 0x0004) ? "previously broken, but now re" : "not ");
+ if (verbose) {
+ printf(" This transceiver is capable of ");
+ if (bmsr & 0xF800) {
+ for (i = 15; i >= 11; i--)
+ if (bmsr & (1<<i))
+ printf(" %s", media_names[i-11]);
+ } else
+ printf("<Warning! No media capabilities>");
+ printf(".\n");
+ printf(" %s to perform Auto-negotiation, negotiation %scomplete.\n",
+ bmsr & 0x0008 ? "Able" : "Unable",
+ bmsr & 0x0020 ? "" : "not ");
+ }
+
+ if (bmsr & 0x0010)
+ printf(" Remote fault detected!\n");
+ if (bmsr & 0x0002)
+ printf(" *** Link Jabber! ***\n");
+
+ if (lkpar & 0x4000) {
+ printf(" Your link partner advertised %4.4x:",
+ lkpar);
+ for (i = 5; i >= 0; i--)
+ if (lkpar & (0x20<<i))
+ printf(" %s", media_names[i]);
+ printf("%s.\n", lkpar & 0x0400 ? ", w/ 802.3X flow control" : "");
+ } else if (lkpar & 0x00A0)
+ printf(" Your link partner is generating %s link beat (no"
+ " autonegotiation).\n",
+ lkpar & 0x0080 ? "100baseTx" : "10baseT");
+ else if ( ! (bmcr & 0x1000))
+ printf(" Link partner information is not exchanged when in"
+ " fixed speed mode.\n");
+ else if ( ! (new_bmsr & 0x004))
+ ; /* If no partner, do not report status. */
+ else if (lkpar == 0x0001 || lkpar == 0x0000) {
+ printf(" Your link partner does not do autonegotiation, and this "
+ "transceiver type\n does not report the sensed link "
+ "speed.\n");
+ } else
+ printf(" Your link partner is strange, status %4.4x.\n", lkpar);
+
+ printf(" End of basic transceiver information.\n\n");
+ return 0;
+}
+
+#ifndef LIBMII
+extern void monitor_mii(long ioaddr, int phy_id)
+{
+ fprintf(stderr, "\nThis version of 'mii-diag' has not been compiled with "
+ "the libmii.c library \n required for the media monitor option.\n");
+}
+#endif /* not compiled for LIBMII */
+
+/*
+ * Local variables:
+ * version-control: t
+ * kept-new-versions: 5
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * tab-width: 4
+ * compile-command: "gcc -Wall -Wstrict-prototypes -O mii-diag.c -DLIBMII libmii.c -o mii-diag"
+ * simple-compile-command: "gcc mii-diag.c -o mii-diag"
+ * End:
+ */
diff --git a/mii/starfire-diag.c b/mii/starfire-diag.c new file mode 100644 index 0000000..5be6570 --- /dev/null +++ b/mii/starfire-diag.c @@ -0,0 +1,640 @@ +/* starfire-diag.c: Diagnostic and setup for the Adaptec Starfire DuraLAN.
+
+ This is a diagnostic and EEPROM setup program for PCI adapters
+ based on the following chips:
+ Adaptec 6915 "Starfire"
+ This file contains the complete diagnostic code.
+
+ Copyright 1998-2000 by Donald Becker.
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Contact the author for use under other terms.
+
+ This program must be compiled with "-O"!
+ See the bottom of this file for the suggested compile-command.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Support and updates available at
+ http://www.scyld.com/diag/index.html
+ http://scyld.com/expert/mii-status.html
+ http://scyld.com/expert/NWay.html
+
+ Common-sense licensing statement: Using any portion of this program in
+ your own program means that you must give credit to the original author
+ and release the resulting code under the GPL.
+*/
+
+static char *version_msg =
+"starfire-diag.c:v2.01 7/26/2000 Donald Becker (becker@scyld.com)\n"
+" http://www.scyld.com/diag/index.html\n";
+static char *usage_msg =
+"Usage: etherdiag [-aEefFmqrRtvVwW] [-p <IOport>] [-[AF] <media>]\n";
+
+#if ! defined(__OPTIMIZE__)
+#warning You must compile this program with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <errno.h>
+
+#if defined(__linux__) && __GNU_LIBRARY__ == 1
+#include <asm/io.h> /* Newer libraries use <sys/io.h> instead. */
+#else
+#include <sys/io.h>
+#endif
+
+/* No libmii.h or libflash.h yet. */
+extern int show_mii_details(long ioaddr, int phy_id);
+extern int monitor_mii(long ioaddr, int phy_id);
+
+extern int flash_show(long addr_ioaddr, long data_ioaddr);
+extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename);
+extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename);
+extern int (*flash_in_hook)(long addr, int offset);
+extern void (*flash_out_hook)(long addr, int offset, int val);
+
+/* We should use __u8 .. __u32, but they are not always defined. */
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+
+struct option longopts[] = {
+ /* { name has_arg *flag val } */
+ {"Advertise", 1, 0, 'A'},
+ {"base-address", 1, 0, 'p'},
+ {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */
+ {"help", 0, 0, 'h'}, /* Give help */
+ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */
+ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */
+ {"force-detection", 0, 0, 'f'},
+ {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */
+ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */
+ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */
+ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */
+ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */
+ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */
+ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */
+ {"test", 0, 0, 'T'}, /* Do register and SRAM test. */
+ {"verbose", 0, 0, 'v'}, /* Verbose mode */
+ {"version", 0, 0, 'V'}, /* Display version number */
+ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */
+ { 0, 0, 0, 0 }
+};
+
+extern int starfire_diag(int vend_id, int dev_id, long ioaddr, int part_idx);
+
+/* Chip-specific flags. Yes, it's grungy to have the enum here. */
+
+/* The table of known chips.
+ Because of the bogus /proc/pci interface we must have both the exact
+ name and a PCI vendor/device IDs.
+ This table is searched in order: place specific entries followed by
+ 'catch-all' general entries. */
+struct pcidev_entry {
+ char *proc_pci_name;
+ char *part_name;
+ int vendor, device, device_mask;
+ int flags;
+ int io_size;
+ int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_num);
+} pcidev_tbl[] = {
+ { "Adaptec Unknown device", "Adaptec Starfire 6915",
+ 0x9004, 0x6915, 0xffff, 0, 256, starfire_diag},
+ { 0, 0, 0, 0},
+};
+
+int verbose = 1, opt_f = 0, debug = 0;
+int show_regs = 0, show_eeprom = 0, show_mii = 0;
+unsigned int opt_a = 0, /* Show-all-interfaces flag. */
+ opt_restart = 0,
+ opt_reset = 0,
+ opt_watch = 0,
+ opt_G = 0;
+unsigned int opt_GPIO = 0; /* General purpose I/O setting. */
+int do_write_eeprom = 0, do_test = 0;
+int nway_advertise = 0, fixed_speed = -1;
+int new_default_media = -1;
+/* Valid with libflash only. */
+static unsigned int opt_flash_show = 0;
+static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL;
+
+static unsigned char new_hwaddr[6], set_hwaddr = 0;
+
+static int scan_proc_pci(int card_num);
+static int parse_media_type(const char *capabilities);
+static int get_media_index(const char *name);
+
+
+int
+main(int argc, char **argv)
+{
+ int port_base = 0, chip_type = 0;
+ int errflag = 0, show_version = 0;
+ int emergency_rewrite = 0;
+ int c, longind;
+ int card_num = 0;
+ extern char *optarg;
+
+ while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:mp:qrRst:vVwWH:BL:S:",
+ longopts, &longind))
+ != -1)
+ switch (c) {
+ case '#': card_num = atoi(optarg); break;
+ case 'a': show_regs++; opt_a++; break;
+ case 'A': nway_advertise = parse_media_type(optarg); break;
+ case 'D': debug++; break;
+ case 'e': show_eeprom++; break;
+ case 'E': emergency_rewrite++; break;
+ case 'f': opt_f++; break;
+ case 'F': new_default_media = get_media_index(optarg);
+ if (new_default_media < 0)
+ errflag++;
+ break;
+ case 'G': opt_G++; opt_GPIO = strtol(optarg, NULL, 16); break;
+ case 'H':
+ {
+ int hwaddr[6], i;
+ if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x",
+ hwaddr, hwaddr + 1, hwaddr + 2,
+ hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) {
+ for (i = 0; i < 6; i++)
+ new_hwaddr[i] = hwaddr[i];
+ set_hwaddr++;
+ } else
+ errflag++;
+ break;
+ }
+ case 'm': show_mii++; break;
+ case 'p':
+ port_base = strtol(optarg, NULL, 16);
+ break;
+ case 'q': if (verbose) verbose--; break;
+ case 'r': opt_restart++; break;
+ case 'R': opt_reset++; break;
+ case 't': chip_type = atoi(optarg); break;
+ case 'v': verbose++; break;
+ case 'V': show_version++; break;
+ case 'w': do_write_eeprom++; break;
+ case 'W': opt_watch++; break;
+ case 'B': opt_flash_show++; break;
+ case 'L': opt_flash_loadfile = optarg; break;
+ case 'S': opt_flash_dumpfile = optarg; break;
+ case '?':
+ errflag++;
+ }
+ if (errflag) {
+ fprintf(stderr, usage_msg);
+ return 3;
+ }
+
+ if (verbose || show_version)
+ printf(version_msg);
+
+ if (chip_type < 0
+ || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) {
+ int i;
+ fprintf(stderr, "Valid numeric chip types are:\n");
+ for (i = 0; pcidev_tbl[i].part_name; i++) {
+ fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name);
+ }
+ return 3;
+ }
+
+ /* Get access to all of I/O space. */
+ if (iopl(3) < 0) {
+ perror("Network adapter diagnostic: iopl()");
+ fprintf(stderr, "This program must be run as root.\n");
+ return 2;
+ }
+
+ /* Try to read a likely port_base value from /proc/pci. */
+ if (port_base) {
+ printf("Assuming a %s adapter at %#x.\n",
+ pcidev_tbl[chip_type].part_name, port_base);
+ pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type);
+ } else if ( scan_proc_pci(card_num) == 0) {
+ fprintf(stderr,
+ "Unable to find a recognized card in /proc/pci.\nIf there is"
+ " a card in the machine, explicitly set the I/O port"
+ " address\n using '-p <ioaddr> -t <chip_type_index>'\n"
+ " Use '-t -1' to see the valid chip types.\n");
+ return ENODEV;
+ }
+
+ if (show_regs == 0 && show_eeprom == 0 && show_mii == 0)
+ printf(" Use '-a' or '-aa' to show device registers,\n"
+ " '-e' to show EEPROM contents, -ee for parsed contents,\n"
+ " or '-m' or '-mm' to show MII management registers.\n");
+
+ return 0;
+}
+
+
+/* Generic (all PCI diags) code to find cards. */
+
+static char bogus_iobase[] =
+"This chip has not been assigned a valid I/O address, and will not function.\n"
+" If you have warm-booted from another operating system, a complete \n"
+" shut-down and power cycle may restore the card to normal operation.\n";
+
+static char bogus_irq[] =
+"This chip has not been assigned a valid IRQ, and will not function.\n"
+" This must be fixed in the PCI BIOS setup. The device driver has no way\n"
+" of changing the PCI IRQ settings.\n";
+
+static int scan_proc_bus_pci(int card_num)
+{
+ int card_cnt = 0, chip_idx = 0;
+ int port_base;
+ char buffer[514];
+ unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1;
+ int i;
+ FILE *fp = fopen("/proc/bus/pci/devices", "r");
+
+ if (fp == NULL) {
+ if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n");
+ return -1;
+ }
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (debug > 1)
+ fprintf(stderr, " Parsing line -- %s", buffer);
+ if (sscanf(buffer, "%x %x %x %x %x",
+ &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0)
+ break;
+ for (i = 0; pcidev_tbl[i].vendor; i++) {
+ if (pci_devid !=
+ (pcidev_tbl[i].vendor << 16) + pcidev_tbl[i].device)
+ continue;
+ chip_idx = i;
+ card_cnt++;
+ /* Select the I/O address. */
+ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1;
+ if (card_num == 0 || card_num == card_cnt) {
+ printf("Index #%d: Found a %s adapter at %#x.\n",
+ card_cnt, pcidev_tbl[chip_idx].part_name,
+ port_base);
+ if (irq == 0 || irq == 255)
+ printf(bogus_irq);
+ if (port_base)
+ pcidev_tbl[chip_idx].diag_func(0,0,port_base, i);
+ else
+ printf(bogus_iobase);
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ return card_cnt;
+}
+
+static int scan_proc_pci(int card_num)
+{
+ int card_cnt = 0, chip_idx = 0;
+ char chip_name[40];
+ FILE *fp;
+ int port_base;
+
+ if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0)
+ return card_cnt;
+ card_cnt = 0;
+
+ fp = fopen("/proc/pci", "r");
+ if (fp == NULL)
+ return 0;
+ {
+ char buffer[514];
+ int pci_bus, pci_device, pci_function, vendor_id, device_id;
+ int state = 0;
+ if (debug) printf("Done open of /proc/pci.\n");
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (debug > 1)
+ fprintf(stderr, " Parse state %d line -- %s", state, buffer);
+ if (sscanf(buffer, " Bus %d, device %d, function %d",
+ &pci_bus, &pci_device, &pci_function) > 0) {
+ chip_idx = 0;
+ state = 1;
+ continue;
+ }
+ if (state == 1) {
+ if (sscanf(buffer, " Ethernet controller: %39[^\n]",
+ chip_name) > 0) {
+ int i;
+ if (debug)
+ printf("Named ethernet controller %s.\n", chip_name);
+ for (i = 0; pcidev_tbl[i].proc_pci_name; i++)
+ if (strncmp(pcidev_tbl[i].proc_pci_name, chip_name,
+ strlen(pcidev_tbl[i].proc_pci_name))
+ == 0) {
+ state = 2;
+ chip_idx = i;
+ continue;
+ }
+ continue;
+ }
+ /* Handle a /proc/pci that does not recognize the card. */
+ if (sscanf(buffer, " Vendor id=%x. Device id=%x",
+ &vendor_id, &device_id) > 0) {
+ int i;
+ if (debug)
+ printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n",
+ vendor_id, device_id);
+ for (i = 0; pcidev_tbl[i].vendor; i++)
+ if (vendor_id == pcidev_tbl[i].vendor &&
+ (device_id & pcidev_tbl[i].device_mask)
+ == pcidev_tbl[i].device)
+ break;
+ if (pcidev_tbl[i].vendor == 0)
+ continue;
+ chip_idx = i;
+ state = 2;
+ }
+ }
+ if (state == 2) {
+ if (sscanf(buffer, " I/O at %x", &port_base) > 0) {
+ card_cnt++;
+ state = 3;
+ if (card_num == 0 || card_num == card_cnt) {
+ printf("Index #%d: Found a %s adapter at %#x.\n",
+ card_cnt, pcidev_tbl[chip_idx].part_name,
+ port_base);
+ if (port_base)
+ pcidev_tbl[chip_idx].diag_func
+ (vendor_id, device_id, port_base, chip_idx);
+ else
+ printf(bogus_iobase);
+ }
+ }
+ }
+ }
+ }
+ fclose(fp);
+ return card_cnt;
+}
+
+/* Convert a text media name to a NWay capability word. */
+static int parse_media_type(const char *capabilities)
+{
+ const char *mtypes[] = {
+ "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD",
+ "10baseT", "10baseT-FD", "10baseT-HD", 0,
+ };
+ int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,};
+ int i;
+ if (debug)
+ fprintf(stderr, "Advertise string is '%s'.\n", capabilities);
+ for (i = 0; mtypes[i]; i++)
+ if (strcasecmp(mtypes[i], capabilities) == 0)
+ return cap_map[i];
+ if ((i = strtol(capabilities, NULL, 16)) <= 0xffff)
+ return i;
+ fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities);
+ return 0;
+}
+
+/* Return the index of a valid media name.
+ 0x0800 Power up autosense (check speed only once)
+ 0x8000 Dynamic Autosense
+*/
+/* A table of media names to indices. This matches the Digital Tulip
+ SROM numbering, primarily because that is the most complete list.
+ Other chips will have to map these number to their internal values.
+*/
+struct { char *name; int value; } mediamap[] = {
+ { "10baseT", 0 },
+ { "10base2", 1 },
+ { "AUI", 2 },
+ { "100baseTx", 3 },
+ { "10baseT-FDX", 0x204 },
+ { "100baseTx-FDX", 0x205 },
+ { "100baseT4", 6 },
+ { "100baseFx", 7 },
+ { "100baseFx-FDX", 8 },
+ { "MII", 11 },
+ { "Autosense", 0x0800 },
+ { 0, 0 },
+};
+
+static int get_media_index(const char *name)
+{
+ int i;
+ for (i = 0; mediamap[i].name; i++)
+ if (strcasecmp(name, mediamap[i].name) == 0)
+ return i;
+ if (isdigit(*name) && atoi(name) >= 00)
+ return atoi(name);
+ fprintf(stderr, "Invalid interface specified: it must be one of\n ");
+ for (i = 0; mediamap[i].name; i++)
+ fprintf(stderr, " %s", mediamap[i].name);
+ fprintf(stderr, ".\n");
+ return -1;
+}
+
+
+/* Chip-specific section. */
+
+/* The chip-specific section for the Adaptec Starfire diagnostic. */
+
+static int read_eeprom(long ioaddr, int location);
+int mdio_read(long ioaddr, int phy_id, int location);
+void mdio_write(long ioaddr, int phy_id, int location, int value);
+
+/* Offsets to the various registers.
+ All accesses need not be longword aligned. */
+enum starfire_offsets {
+ GenCtrl=0x50070,
+ IntrClear=0x50084, IntrStatus=0x50084, IntrEnable=0x50088,
+ MIICtrl=0x52000, StationAddr=0x50120, EEPROMCtrl=0x51000,
+ TxRingPtr=0x50098, HiPriTxRingPtr=0x50094, /* Low and High priority. */
+ TxRingAddrHi=0x5009C, /* 64 bit address extension. */
+ TxProducerIdx=0x500A0, TxConsumerIdx=0x500A4,
+ TxThreshold=0x500B0, TxMode=0x55000,
+};
+
+/* Non-interrupting events. */
+const char *event_names[16] = {
+ "Tx Abort", "Rx frame complete", "Transmit done",
+};
+struct config_name { int val, mask; const char*name;}
+static rcvr_mode[] = {
+ {0x44, 0xff, "Normal unicast and perfect multicast filtering"},
+ {0x34, 0xff, "Normal unicast and hashed multicast"},
+ {0x03, 0x02, "Normal unicast and all multicast"},
+ {0x01, 0x01, "Promiscuous"},
+ {0x00, 0x00, "Unknown/invalid"},
+};
+
+/* Values read from the EEPROM, and the new image. */
+#define EEPROM_SIZE 32
+unsigned int eeprom_contents[EEPROM_SIZE];
+unsigned int new_ee_contents[EEPROM_SIZE];
+
+int starfire_diag(int vendor_id, int device_id, long ioaddr, int part_idx)
+{
+ int i;
+
+ if (verbose || show_regs) {
+ int MAC_config, MAC_addr;
+ int rx_mode = inl(ioaddr + 0xf4);
+ int pci_stats = inl(ioaddr + 0x48);
+ if (opt_a) {
+ printf("%s chip registers at %#lx",
+ pcidev_tbl[part_idx].part_name, ioaddr);
+ for (i = 0; i < pcidev_tbl[part_idx].io_size; i += 4) {
+ if ((i & 0x1f) == 0)
+ printf("\n 0x%3.3X:", i);
+ if (!opt_f && i == 0x80)
+ printf(" **INTR**");
+ else
+ printf(" %8.8x", inl(ioaddr + i));
+ }
+ printf("\n");
+ }
+ printf(" Queue states\n"
+ " Tx producer index %d, consumer index %d.\n"
+ " Rx consumer index %d, producer index %d.\n",
+ inw(ioaddr + 0xa0), inw(ioaddr + 0xa4),
+ inw(ioaddr + 0xea), inw(ioaddr + 0xe8));
+ printf(" PCI statistics\n");
+ printf(" PCI Bus maximum latency was %d nsec, peak interrupt latency "
+ "%d usec.\n",
+ (pci_stats>>24)*480, (pci_stats & 0xff) *30);
+ printf(" PCI accesses: %d slave cycles, %d master bursts.\n",
+ inl(ioaddr + 0x48) & 0xffff, inl(ioaddr + 0x4C) & 0xffff);
+ printf(" Interrupts pending: %8.8x\n", inl(ioaddr + 0x84));
+ for (i = 0; rcvr_mode[i].mask; i++)
+ if ((rx_mode & rcvr_mode[i].mask) == rcvr_mode[i].val) break;
+ printf(" Receive mode is 0x%8.8x: %s.\n", rx_mode, rcvr_mode[i].name);
+ outl(0x50120, ioaddr + 0x68);
+ MAC_addr = inl(ioaddr + 0x6c);
+ printf(" MAC address is --:--:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ (MAC_addr >> 24) & 0xff, (MAC_addr >> 16) & 0xff,
+ (MAC_addr >> 8) & 0xff, (MAC_addr >> 0) & 0xff);
+ outl(0x55000, ioaddr + 0x68);
+ MAC_config = inl(ioaddr + 0x6c);
+ printf(" MAC Config 1 is %8.8x: %s-duplex.\n", MAC_config,
+ MAC_config & 0x02 ? "full" : "half");
+ if (opt_a > 2) {
+ printf(" Statistics registers: ");
+ for (i = 0; i < 0x100; i+=4) {
+ outl(0x57000+i, ioaddr + 0x68);
+ printf(" %8.8x%s", inl(ioaddr + 0x6c),
+ i%16 == 15 ? "\n " : "");
+ }
+ printf("\n");
+ }
+ }
+
+ for (i = 0; i < EEPROM_SIZE; i++)
+ eeprom_contents[i] = read_eeprom(ioaddr, i);
+
+ if (show_eeprom) {
+ u32 sum = 0;
+ u8 *ee = (u8*)eeprom_contents;
+ if (show_eeprom > 1) {
+ printf("EEPROM contents:");
+ for (i = 0; i < EEPROM_SIZE; i++) {
+ if ((i & 7) == 0)
+ printf("\n0x%3.3x: ", i);
+ printf(" %8.8x", eeprom_contents[i]);
+ }
+ printf("\n");
+ }
+ printf("EEPROM Subsystem IDs, Vendor %2.2x%2.2x Device %2.2x%2.2x.\n",
+ ee[7], ee[6], ee[9], ee[8]);
+ printf("EEPROM Station address is ");
+ for (i = 20; i > 15; i--)
+ printf("%2.2x:", ee[i]);
+ printf("%2.2x.\n", ee[i]);
+ for (i = 0; i < EEPROM_SIZE-1; i++)
+ sum ^= eeprom_contents[i];
+ printf("EEPROM Checksum is %8.8x.\n", sum);
+ for (i = 0, sum=0; i < EEPROM_SIZE*4 - 2; i++)
+ sum += ee[i];
+ printf("EEPROM Checksum is %8.8x.\n", sum);
+ }
+ if (show_mii) {
+ int phys[4], phy, phy_idx = 0;
+ for (phy = 0; phy < 32 && phy_idx < 4; phy++) {
+ int mii_status = mdio_read(ioaddr, phy, 1);
+ if (mii_status != 0xffff &&
+ mii_status != 0x0000) {
+ phys[phy_idx++] = phy;
+ printf(" MII PHY found at address %d, status 0x%4.4x.\n",
+ phy, mii_status);
+ }
+ }
+ if (phy_idx == 0)
+ printf(" ***WARNING***: No MII transceivers found!\n");
+ for (phy = 0; phy < phy_idx; phy++) {
+ int mii_reg;
+ printf(" MII PHY #%d transceiver registers:", phys[phy]);
+ for (mii_reg = 0; mii_reg < 32; mii_reg++)
+ printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "",
+ mdio_read(ioaddr, phys[phy], mii_reg));
+ printf(".\n");
+ }
+#ifdef LIBMII
+ show_mii_details(ioaddr, phys[0]);
+ if (show_mii > 1)
+ monitor_mii(ioaddr, phys[0]);
+#endif
+ }
+
+ return 0;
+}
+
+static int read_eeprom(long ioaddr, int location)
+{
+ outl(EEPROMCtrl + location*4, ioaddr + 0x68);
+ return inl(ioaddr + 0x6C);
+}
+
+#ifdef notused
+static void write_eeprom(long ioaddr, int location, int value)
+{
+ outl(EEPROMCtrl + location*4, ioaddr + 0x68);
+ outl(value, ioaddr + 0x6C);
+ return;
+}
+#endif
+
+/* MII Managemen Data I/O accesses.
+ These routines assume the MDIO controller is idle, and do not exit until
+ the command is finished. */
+
+int mdio_read(long ioaddr, int phy_id, int location)
+{
+ int result, boguscnt=1000;
+
+ outl(MIICtrl + (phy_id<<7) + location*4, ioaddr + 0x68);
+ do
+ result = inl(ioaddr + 0x6C);
+ while ((result & 0xC0000000) != 0x80000000 && --boguscnt >= 0);
+ return result & 0xffff;
+}
+
+void mdio_write(long ioaddr, int phy_id, int location, int value)
+{
+ outl(MIICtrl + (phy_id<<7) + location*4, ioaddr + 0x68);
+ outl(value, ioaddr + 0x6C);
+ return;
+}
+
+/*
+ * Local variables:
+ * compile-command: "cc -O -Wall -o starfire-diag starfire-diag.c"
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/mii/tulip-diag.c b/mii/tulip-diag.c new file mode 100644 index 0000000..7036b26 --- /dev/null +++ b/mii/tulip-diag.c @@ -0,0 +1,1656 @@ +/* tulip-diag.c: Diagnostic and setup for Digital DC21x4*-based ethercards.
+
+ This is a diagnostic and EEPROM setup program for PCI Ethernet adapters
+ based on the following chips:
+ Intel (nee Digital) "Tulip" series chips: 21040/041/140/142/143/145,
+ Work-alikes from Lite-On, LinkSys, Macronix, ASIX, Compex, STmicro,
+ ADMtek, Davicom and (ugh) Xircom.
+
+ Copyright 1998-2000 by Donald Becker.
+ This software may be used and distributed according to the terms of
+ the GNU General Public License (GPL), incorporated herein by reference.
+ Contact the author for use under other terms.
+
+ This program must be compiled with "-O"!
+ See the bottom of this file for the suggested compile-command.
+
+ The author may be reached as becker@scyld.com, or C/O
+ Scyld Computing Corporation
+ 410 Severn Ave., Suite 210
+ Annapolis MD 21403
+
+ Support and updates available at
+ http://www.scyld.com/diag/index.html
+ http://scyld.com/expert/mii-status.html
+ http://scyld.com/expert/NWay.html
+
+ Common-sense licensing statement: Using any portion of this program in
+ your own program means that you must give credit to the original author
+ and release the resulting code under the GPL.
+*/
+
+static char *version_msg =
+"tulip-diag.c:v2.08 5/15/2001 Donald Becker (becker@scyld.com)\n"
+" http://www.scyld.com/diag/index.html\n";
+static char *usage_msg =
+"Usage: tulip-diag [-aEefFmqrRtvVwW] [-p <IOport>] [-[AF] <media>]\n";
+
+#if ! defined(__OPTIMIZE__)
+#warning You must compile this program with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
+#endif
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <string.h>
+#include <strings.h>
+#include <errno.h>
+
+#include <asm/types.h>
+#include <asm/unaligned.h>
+
+#if defined(__linux__) && __GNU_LIBRARY__ == 1
+#include <asm/io.h> /* Newer libraries use <sys/io.h> instead. */
+#else
+#include <sys/io.h>
+#endif
+
+/* No libmii.h or libflash.h yet. */
+extern int show_mii_details(long ioaddr, int phy_id);
+extern int monitor_mii(long ioaddr, int phy_id);
+
+extern int flash_show(long addr_ioaddr, long data_ioaddr);
+extern int flash_dump(long addr_ioaddr, long data_ioaddr, char *filename);
+extern int flash_program(long addr_ioaddr, long data_ioaddr, char *filename);
+extern int (*flash_in_hook)(long addr, int offset);
+extern void (*flash_out_hook)(long addr, int offset, int val);
+
+/* We should use __u8 .. __u32, but they are not always defined. */
+typedef unsigned int u32;
+typedef unsigned short u16;
+typedef unsigned char u8;
+
+struct option longopts[] = {
+ /* { name has_arg *flag val } */
+ {"Advertise", 1, 0, 'A'},
+ {"base-address", 1, 0, 'p'},
+ {"show_all_registers", 0, 0, 'a'}, /* Print all registers. */
+ {"help", 0, 0, 'h'}, /* Give help */
+ {"show-eeprom", 0, 0, 'e'}, /* Dump EEPROM contents (-ee valid). */
+ {"emergency-rewrite", 0, 0, 'E'}, /* Re-write a corrupted EEPROM. */
+ {"force-detection", 0, 0, 'f'},
+ {"new-interface", 1, 0, 'F'}, /* New interface (built-in, AUI, etc.) */
+ {"new-hwaddr", 1, 0, 'H'}, /* Set a new hardware address. */
+ {"show-mii", 0, 0, 'm'}, /* Dump MII management registers. */
+ {"port-base", 1, 0, 'p'}, /* Use the specified I/O address. */
+ {"quiet", 0, 0, 'q'}, /* Decrease verbosity */
+ {"reset", 0, 0, 'R'}, /* Reset the transceiver. */
+ {"chip-type", 1, 0, 't'}, /* Assume the specified chip type index. */
+ {"verbose", 0, 0, 'v'}, /* Verbose mode */
+ {"version", 0, 0, 'V'}, /* Display version number */
+ {"write-EEPROM", 1, 0, 'w'},/* Actually write the EEPROM with new vals */
+ { 0, 0, 0, 0 }
+};
+
+extern int tulip_diag(int vend_id, int dev_id, long ioaddr, int part_idx);
+
+enum tulip_flags {
+ DC21041_EEPROM=1, DC21040_EEPROM=2, DC21140_EEPROM=4, PNIC_EEPROM=8,
+ CSR12_IS_GPIO=0x10, PNIC_MTABLE=0x20,
+ DC21143_MII=0x100, PNIC_MII=0x200, COMET_MII=0x400, HAS_NWAY=0x800,
+ ASIX_MACADDR=0x1000, COMET_MACADDR=0x2000, PNIC2_MACADDR=0x4000,
+ IS_CONEXANT=0x8000, COMET_HPNA=0x10000, IS_DAVICOM=0x20000,
+};
+
+/* The table of known chips.
+ Because of the bogus /proc/pci interface we must have both the exact
+ name from the kernel, a common name and the PCI vendor/device IDs.
+ This table is searched in order: place specific entries followed by
+ 'catch-all' general entries. */
+struct pcidev_entry {
+ const char *part_name;
+ const char *proc_pci_name;
+ int vendor, device, device_mask;
+ int flags;
+ int io_size;
+ int (*diag_func)(int vendor_id, int device_id, long ioaddr, int part_idx);
+} pcidev_tbl[] = {
+ { "Digital Tulip series", "Digital Tulip, unknown type",
+ 0x1011, 0x0000, 0xffff, 0, 128, tulip_diag },
+ { "Digital DC21040 Tulip", "DEC DC21040",
+ 0x1011, 0x0002, 0xffff, DC21040_EEPROM, 128, tulip_diag },
+ { "Digital DC21041 Tulip", "DEC DC21041",
+ 0x1011, 0x0014, 0xffff, DC21041_EEPROM | HAS_NWAY, 128, tulip_diag },
+ { "Digital DS21140 Tulip", "DEC DC21140",
+ 0x1011, 0x0009, 0xffff, CSR12_IS_GPIO, 128, tulip_diag },
+ { "Digital DS21143 Tulip", "DEC DC21142",
+ 0x1011, 0x0019, 0xffff, DC21143_MII | HAS_NWAY, 128, tulip_diag },
+ { "Intel 21145 Tulip", 0,
+ 0x8086, 0x0039, 0xffff, DC21143_MII | HAS_NWAY, 128, tulip_diag },
+ { "Lite-On 82c168 PNIC", "Lite-on LNE100TX",
+ 0x11AD, 0x0002, 0xffff, CSR12_IS_GPIO|PNIC_EEPROM|PNIC_MII, 256, tulip_diag },
+ { "Lite-On PNIC-II", 0, 0x11AD, 0xc115, 0xffff,
+ PNIC_MTABLE | HAS_NWAY | PNIC2_MACADDR, 256, tulip_diag },
+ { "Macronix 98713 PMAC", "Macronix MX98713",
+ 0x10d9, 0x0512, 0xffff, CSR12_IS_GPIO, 256, tulip_diag },
+ { "Macronix 98715 PMAC", "Macronix MX98715 / MX98725",
+ 0x10d9, 0x0531, 0xffff, 0, 256, tulip_diag },
+ { "Macronix MX98715 / MX98725", "Macronix 98725 PMAC",
+ 0x10d9, 0x0531, 0xffff, 0, 256, tulip_diag },
+ { "ASIX AX88140", 0,
+ 0x125B, 0x1400, 0xffff, CSR12_IS_GPIO | ASIX_MACADDR, 128, tulip_diag },
+ { "Compex TX9881", "Compex TX9881",
+ 0x11F6, 0x9881, 0xffff, 0, 128, tulip_diag },
+ { "ADMtek AL981 Comet", 0,
+ 0x1317, 0x0981, 0xffff, COMET_MII | COMET_MACADDR, 256, tulip_diag },
+ { "ADMtek AL985 Centaur-P", 0,
+ 0x1317, 0x0985, 0xffff, COMET_MACADDR, 256, tulip_diag },
+ { "ADMtek AL985 Centaur-C", 0,
+ 0x1317, 0x1985, 0xffff, COMET_MACADDR, 256, tulip_diag },
+ { "ADMtek Comet-II", 0,
+ 0x1317, 0x9511, 0xffff, COMET_MACADDR | COMET_HPNA, 256, tulip_diag },
+ { "ADMtek AL985 Centaur (Linksys CardBus v2)", 0,
+ 0x13d1, 0xab02, 0xffff, COMET_MACADDR, 256, tulip_diag },
+ { "ADMtek AL985 Centaur (Linksys CardBus)", 0,
+ 0x13d1, 0xab03, 0xffff, COMET_MACADDR, 256, tulip_diag },
+ { "STMicro STE10/100 Comet", 0,
+ 0x104a, 0x0981, 0xffff, COMET_MACADDR, 256, tulip_diag },
+ { "STMicro STE10/100A Comet", 0,
+ 0x104a, 0x2774, 0xffff, COMET_MACADDR, 256, tulip_diag },
+ { "Accton EN1217/EN2242 (ADMtek Comet)", 0,
+ 0x1113, 0x1216, 0xffff, COMET_MACADDR, 256, tulip_diag },
+ { "Davicom DM9102", 0,
+ 0x1282, 0x9102, 0xffff, CSR12_IS_GPIO, 128, tulip_diag },
+ { "Davicom DM9100", 0,
+ 0x1282, 0x9100, 0xffff, CSR12_IS_GPIO, 128, tulip_diag },
+ { "Davicom DM9100 series (unknown model)", 0,
+ 0x1282, 0x9100, 0xfff0, CSR12_IS_GPIO | IS_DAVICOM, 128, tulip_diag },
+ { "Conexant LANfinity", 0,
+ 0x14f1, 0x1803, 0xffff, IS_CONEXANT, 256, tulip_diag },
+ { 0, 0, 0, 0},
+};
+
+int verbose = 1, opt_f = 0, debug = 0;
+int show_regs = 0, show_eeprom = 0, show_mii = 0;
+unsigned int opt_a = 0, /* Show-all-interfaces flag. */
+ opt_restart = 0,
+ opt_reset = 0,
+ opt_watch = 0,
+ opt_G = 0;
+unsigned int opt_GPIO = 0; /* General purpose I/O setting. */
+int do_write_eeprom = 0, do_test = 0;
+int nway_advertise = 0, fixed_speed = -1;
+int new_default_media = -1;
+/* Valid with libflash only. */
+static unsigned int opt_flash_show = 0;
+static char *opt_flash_dumpfile = NULL, *opt_flash_loadfile = NULL;
+
+static unsigned char new_hwaddr[6], set_hwaddr = 0;
+static int emergency_rewrite = 0;
+
+static int scan_proc_pci(int card_num);
+static int parse_media_type(const char *capabilities);
+static int get_media_index(const char *name);
+
+int
+main(int argc, char **argv)
+{
+ int port_base = 0, chip_type = 0;
+ int errflag = 0, show_version = 0;
+ int c, longind;
+ int card_num = 0;
+ extern char *optarg;
+
+ while ((c = getopt_long(argc, argv, "#:aA:DeEfF:G:mp:qrRst:vVwWH:BL:S:",
+ longopts, &longind))
+ != -1)
+ switch (c) {
+ case '#': card_num = atoi(optarg); break;
+ case 'a': show_regs++; opt_a++; break;
+ case 'A': nway_advertise = parse_media_type(optarg); break;
+ case 'D': debug++; break;
+ case 'e': show_eeprom++; break;
+ case 'E': emergency_rewrite++; break;
+ case 'f': opt_f++; break;
+ case 'F': new_default_media = get_media_index(optarg);
+ if (new_default_media < 0)
+ errflag++;
+ break;
+ case 'G': opt_G++; opt_GPIO = strtoul(optarg, NULL, 16); break;
+ case 'H':
+ {
+ int hwaddr[6], i;
+ if (sscanf(optarg, "%2x:%2x:%2x:%2x:%2x:%2x",
+ hwaddr, hwaddr + 1, hwaddr + 2,
+ hwaddr + 3, hwaddr + 4, hwaddr + 5) == 6) {
+ for (i = 0; i < 6; i++)
+ new_hwaddr[i] = hwaddr[i];
+ set_hwaddr++;
+ } else
+ errflag++;
+ break;
+ }
+ case 'm': show_mii++; break;
+ case 'p':
+ port_base = strtoul(optarg, NULL, 16);
+ break;
+ case 'q': if (verbose) verbose--; break;
+ case 'r': opt_restart++; break;
+ case 'R': opt_reset++; break;
+ case 't': chip_type = atoi(optarg); break;
+ case 'v': verbose++; break;
+ case 'V': show_version++; break;
+ case 'w': do_write_eeprom++; break;
+ case 'W': opt_watch++; break;
+ case 'B': opt_flash_show++; break;
+ case 'L': opt_flash_loadfile = optarg; break;
+ case 'S': opt_flash_dumpfile = optarg; break;
+ case '?':
+ errflag++;
+ }
+ if (errflag) {
+ fprintf(stderr, usage_msg);
+ return 3;
+ }
+
+ if (verbose || show_version)
+ printf(version_msg);
+
+ if (chip_type < 0
+ || chip_type >= sizeof(pcidev_tbl)/sizeof(pcidev_tbl[0]) - 1) {
+ int i;
+ fprintf(stderr, "Valid numeric chip types are:\n");
+ for (i = 0; pcidev_tbl[i].part_name; i++) {
+ fprintf(stderr, " %d\t%s\n", i, pcidev_tbl[i].part_name);
+ }
+ return 3;
+ }
+
+ /* Get access to all of I/O space. */
+ if (iopl(3) < 0) {
+ perror("Network adapter diagnostic: iopl()");
+ fprintf(stderr, "This program must be run as root.\n");
+ return 2;
+ }
+
+ /* Try to read a likely port_base value from /proc/pci. */
+ if (port_base) {
+ printf("Assuming a %s adapter at %#x.\n",
+ pcidev_tbl[chip_type].part_name, port_base);
+ pcidev_tbl[chip_type].diag_func(0, 0, port_base, chip_type);
+ } else if ( scan_proc_pci(card_num) == 0) {
+ fprintf(stderr,
+ "Unable to find a recognized card in /proc/pci.\nIf there is"
+ " a card in the machine, explicitly set the I/O port"
+ " address\n using '-p <ioaddr> -t <chip_type_index>'\n"
+ " Use '-t -1' to see the valid chip types.\n");
+ return ENODEV;
+ }
+
+ if (show_regs == 0 && show_eeprom == 0 && show_mii == 0)
+ printf(" Use '-a' or '-aa' to show device registers,\n"
+ " '-e' to show EEPROM contents, -ee for parsed contents,\n"
+ " or '-m' or '-mm' to show MII management registers.\n");
+
+ return 0;
+}
+
+
+/* Generic (all PCI diags) code to find cards. */
+
+static char bogus_iobase[] =
+"This chip has not been assigned a valid I/O address, and will not function.\n"
+" If you have warm-booted from another operating system, a complete \n"
+" shut-down and power cycle may restore the card to normal operation.\n";
+
+static char bogus_irq[] =
+"This chip has not been assigned a valid IRQ, and will not function.\n"
+" This must be fixed in the PCI BIOS setup. The device driver has no way\n"
+" of changing the PCI IRQ settings.\n"
+" See http://www.scyld.com/expert/irq-conflict.html for more information.\n";
+
+static int scan_proc_bus_pci(int card_num)
+{
+ int card_cnt = 0, chip_idx = 0;
+ int port_base;
+ char buffer[514];
+ unsigned int pci_bus, pci_devid, irq, pciaddr0, pciaddr1;
+ int i;
+ FILE *fp = fopen("/proc/bus/pci/devices", "r");
+
+ if (fp == NULL) {
+ if (debug) fprintf(stderr, "Failed to open /proc/bus/pci/devices.\n");
+ return -1;
+ }
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (debug > 1)
+ fprintf(stderr, " Parsing line -- %s", buffer);
+ if (sscanf(buffer, "%x %x %x %x %x",
+ &pci_bus, &pci_devid, &irq, &pciaddr0, &pciaddr1) <= 0)
+ break;
+ for (i = 0; pcidev_tbl[i].vendor; i++) {
+ if ((pci_devid >> 16) != pcidev_tbl[i].vendor
+ || (pci_devid & pcidev_tbl[i].device_mask) !=
+ pcidev_tbl[i].device)
+ continue;
+ chip_idx = i;
+ card_cnt++;
+ /* Select the I/O address. */
+ port_base = pciaddr0 & 1 ? pciaddr0 & ~1 : pciaddr1 & ~1;
+ if (card_num == 0 || card_num == card_cnt) {
+ printf("Index #%d: Found a %s adapter at %#x.\n",
+ card_cnt, pcidev_tbl[chip_idx].part_name,
+ port_base);
+ if (irq == 0 || irq == 255)
+ printf(bogus_irq);
+ if (port_base)
+ pcidev_tbl[chip_idx].diag_func(0,0,port_base, i);
+ else
+ printf(bogus_iobase);
+ break;
+ }
+ }
+ }
+ fclose(fp);
+ return card_cnt;
+}
+
+static int scan_proc_pci(int card_num)
+{
+ int card_cnt = 0, chip_idx = 0;
+ char chip_name[40];
+ FILE *fp;
+ int port_base;
+
+ if ((card_cnt = scan_proc_bus_pci(card_num)) >= 0)
+ return card_cnt;
+ card_cnt = 0;
+
+ fp = fopen("/proc/pci", "r");
+ if (fp == NULL)
+ return 0;
+ {
+ char buffer[514];
+ int pci_bus, pci_device, pci_function, vendor_id, device_id;
+ int state = 0;
+ if (debug) printf("Done open of /proc/pci.\n");
+ while (fgets(buffer, sizeof(buffer), fp)) {
+ if (debug > 1)
+ fprintf(stderr, " Parse state %d line -- %s", state, buffer);
+ if (sscanf(buffer, " Bus %d, device %d, function %d",
+ &pci_bus, &pci_device, &pci_function) > 0) {
+ chip_idx = 0;
+ state = 1;
+ continue;
+ }
+ if (state == 1) {
+ if (sscanf(buffer, " Ethernet controller: %39[^\n]",
+ chip_name) > 0) {
+ int i;
+ if (debug)
+ printf("Named ethernet controller %s.\n", chip_name);
+ for (i = 0; pcidev_tbl[i].part_name; i++)
+ if (pcidev_tbl[i].proc_pci_name &&
+ strncmp(pcidev_tbl[i].proc_pci_name, chip_name,
+ strlen(pcidev_tbl[i].proc_pci_name))
+ == 0) {
+ state = 2;
+ chip_idx = i;
+ continue;
+ }
+ continue;
+ }
+ /* Handle a /proc/pci that does not recognize the card. */
+ if (sscanf(buffer, " Vendor id=%x. Device id=%x",
+ &vendor_id, &device_id) > 0) {
+ int i;
+ if (debug)
+ printf("Found vendor 0x%4.4x device ID 0x%4.4x.\n",
+ vendor_id, device_id);
+ for (i = 0; pcidev_tbl[i].vendor; i++)
+ if (vendor_id == pcidev_tbl[i].vendor &&
+ (device_id & pcidev_tbl[i].device_mask)
+ == pcidev_tbl[i].device)
+ break;
+ if (pcidev_tbl[i].vendor == 0)
+ continue;
+ chip_idx = i;
+ state = 2;
+ }
+ }
+ if (state == 2) {
+ if (sscanf(buffer, " I/O at %x", &port_base) > 0) {
+ card_cnt++;
+ state = 3;
+ if (card_num == 0 || card_num == card_cnt) {
+ printf("Index #%d: Found a %s adapter at %#x.\n",
+ card_cnt, pcidev_tbl[chip_idx].part_name,
+ port_base);
+ if (port_base)
+ pcidev_tbl[chip_idx].diag_func
+ (vendor_id, device_id, port_base, chip_idx);
+ else
+ printf(bogus_iobase);
+ }
+ }
+ }
+ }
+ }
+ fclose(fp);
+ return card_cnt;
+}
+
+/* Convert a text media name to a NWay capability word. */
+static int parse_media_type(const char *capabilities)
+{
+ const char *mtypes[] = {
+ "100baseT4", "100baseTx", "100baseTx-FD", "100baseTx-HD",
+ "10baseT", "10baseT-FD", "10baseT-HD", 0,
+ };
+ int cap_map[] = { 0x0200, 0x0180, 0x0100, 0x0080, 0x0060, 0x0040, 0x0020,};
+ int i;
+ if (debug)
+ fprintf(stderr, "Advertise string is '%s'.\n", capabilities);
+ for (i = 0; mtypes[i]; i++)
+ if (strcasecmp(mtypes[i], capabilities) == 0)
+ return cap_map[i];
+ if ((i = strtoul(capabilities, NULL, 16)) <= 0xffff)
+ return i;
+ fprintf(stderr, "Invalid media advertisement '%s'.\n", capabilities);
+ return 0;
+}
+
+/* Return the index of a valid media name.
+ 0x0800 Power up autosense (check speed only once)
+ 0x8000 Dynamic Autosense
+*/
+/* A table of media names to indices. This matches the Digital Tulip
+ SROM numbering, primarily because that is the most complete list.
+ Other chips will have to map these number to their internal values.
+*/
+struct { char *name; int value; } mediamap[] = {
+ { "10baseT", 0 },
+ { "10base2", 1 },
+ { "AUI", 2 },
+ { "100baseTx", 3 },
+ { "10baseT-FDX", 0x204 },
+ { "100baseTx-FDX", 0x205 },
+ { "100baseT4", 6 },
+ { "100baseFx", 7 },
+ { "100baseFx-FDX", 8 },
+ { "MII", 11 },
+ { "HomePNA", 18 },
+ { "Autosense", 0x0800 },
+ { 0, 0 },
+};
+
+static int get_media_index(const char *name)
+{
+ int i;
+ for (i = 0; mediamap[i].name; i++)
+ if (strcasecmp(name, mediamap[i].name) == 0) {
+ if (debug)
+ fprintf(stderr, "Using media index %d for '%s'.\n", i, name);
+ return i;
+ }
+ if (name && atoi(name) >= 00)
+ return atoi(name);
+ fprintf(stderr, "Invalid interface specified: it must be one of\n ");
+ for (i = 0; mediamap[i].name; i++)
+ fprintf(stderr, " %s", mediamap[i].name);
+ fprintf(stderr, ".\n");
+ return -1;
+}
+
+
+/* Chip-specific section. */
+
+int tulip_diag(int vendor_id, int device_id, long ioaddr, int part_idx);
+int mdio_read(long ioaddr, int phy_id, int location);
+void mdio_write(long ioaddr, int phy_id, int location, int value);
+static void mdio_sync(long ioaddr);
+static void setup_nway_xcvr(long ioaddr);
+static void tulip_eeprom(long ioaddr, int flags);
+static int read_eeprom(long ioaddr, int location, int addr_len);
+static void parse_eeprom(unsigned char *ee_data, int part_idx);
+static void liteon_eeprom(unsigned char *ee_data, int part_idx);
+static void admtek_eeprom(unsigned char *ee_data, int part_idx);
+static void conexant_eeprom(unsigned char *ee_data, int part_idx);
+static void davicom_eeprom(unsigned char *ee_data, int part_idx);
+static unsigned int calculate_checksum1(u16 *eeprom_contents, int len);
+static unsigned int ether_crc_le(void *ptr, int length);
+int do_update(long ioaddr, unsigned short *ee_values, int index,
+ char *field_name, int new_value);
+static void check_for_intel_cb(long ioaddr, unsigned short *eeprom_contents);
+
+
+/* Offsets to the Command and Status Registers, "CSRs". All accesses
+ must be longword instructions and quadword aligned.
+ I know these are not descriptive, but they are the commonly used names
+ for the Tulip design.
+*/
+enum tulip_offsets {
+ CSR0=0, CSR1=0x08, CSR2=0x10, CSR3=0x18, CSR4=0x20, CSR5=0x28,
+ CSR6=0x30, CSR7=0x38, CSR8=0x40, CSR9=0x48, CSR10=0x50, CSR11=0x58,
+ CSR12=0x60, CSR13=0x68, CSR14=0x70, CSR15=0x78 };
+
+static const char *tx_state[8] = {
+ "Stopped", "Reading a Tx descriptor", "Waiting for Tx to finish",
+ "Loading Tx FIFO", "<invalid Tx state>", "Processing setup information",
+ "Idle", "Closing Tx descriptor" };
+static const char *rx_state[8] = {
+ "Stopped", "Reading a Rx descriptor", "Waiting for Rx to finish",
+ "Waiting for packets", "Suspended -- no Rx buffers",
+ "Closing Rx descriptor",
+ "Unavailable Rx buffer -- Flushing Rx frame",
+ "Transferring Rx frame into memory", };
+static const char *bus_error[8] = {
+ "Parity Error", "Master Abort", "Target abort", "Unknown 3",
+ "Unknown 4", "Unknown 5", "Unknown 6", "Unknown 7"};
+const char *intr_names[16] ={
+ "Tx done", "Tx complete", "Tx out of buffers", "Transmit Jabber",
+ "Link passed", "Tx FIFO Underflow", "Rx Done", "Receiver out of buffers",
+ "Receiver stopped", "Receiver jabber", "Link changed", "Timer expired",
+ "Link failed", "PCI bus error", "Early Rx", "Abnormal summary",
+};
+
+#define EEPROM_SIZE 256 /* Size may be 256x16 for CardBus. */
+
+static int has_mii = 0;
+static int current_part_idx = 0; /* Global, for mdio_{read,write,sync}() */
+static int default_media_offset = -1;
+
+/* Values read from the EEPROM, and the new image to write. */
+static unsigned short eeprom_contents[EEPROM_SIZE];
+static unsigned short new_ee_contents[EEPROM_SIZE];
+
+/* Support for Flash operations. */
+static int tulip_flash_in(long ioaddr, int offset) {
+ outl(offset, ioaddr + CSR10);
+ outl(0x5000, ioaddr + CSR9);
+ return inl(ioaddr + CSR9) & 0xff;
+}
+#ifdef LIBFLASH
+static void tulip_flash_out(long ioaddr, int offset, int val) {
+ outl(offset, ioaddr + CSR10);
+ outl(0x3000 | val, ioaddr + CSR9);
+}
+#endif
+
+int tulip_diag(int vendor_id, int device_id, long ioaddr, int part_idx)
+{
+ int flags = pcidev_tbl[part_idx].flags; /* Capabilities. */
+ int if_active = 0;
+ int i;
+
+ /* It's mostly safe to use the Tulip EEPROM and MDIO register during
+ operation. But warn the user, and make then pass '-f'. */
+ if (opt_a && !opt_f && (inl(ioaddr + CSR6) & 0x2002) != 0) {
+ printf(" * A potential Tulip chip has been found, but it appears to "
+ "be active.\n * Either shutdown the network, or use the"
+ " '-f' flag to see all values.\n");
+ if_active = 1;
+ }
+
+ /* We always have registers up to CSR15.
+ We may always safely read up to CSR7.
+ We must be stopped or have '-f' to show CSR8-CSR15, since we might
+ clear the missed packet count and other status.
+ Chips with registers above CSR15 usually space them on 4 byte
+ boundaries instead of 8 byte boundaries.
+ */
+ if (show_regs) {
+ printf("%s chip registers at %#lx:\n 0x00:",
+ pcidev_tbl[part_idx].part_name, ioaddr);
+ for (i = 0; i < 64; i += 8)
+ printf(" %8.8x", inl(ioaddr + i));
+ printf("\n");
+ }
+ if (show_regs && (!if_active || opt_f)) {
+ int num_regs = pcidev_tbl[part_idx].io_size;
+ printf(" 0x40:");
+ for (; i < 128; i += 8)
+ printf(" %8.8x", inl(ioaddr + i));
+ if (i < num_regs) {
+ /* Extended registers are _not_ quadword aligned. */
+ printf("\n Extended registers:");
+ for (; i < num_regs; i += 4) {
+ if (i % 32 == 0) printf("\n %2.2x:", i);
+ printf(" %8.8x", inl(ioaddr + i));
+ }
+ }
+ printf("\n");
+ }
+ if (!opt_f && inl(ioaddr + CSR5) == 0xffffffff) {
+ printf(" * A recognized chip has been found, but it does not appear"
+ " to exist in\n * I/O space. Use the"
+ " '-f' flag to see the register values anyway.\n");
+ return 1;
+ } else {
+ int csr5 = inl(ioaddr + CSR5);
+ int csr6 = inl(ioaddr + CSR6);
+
+ if (flags & (DC21040_EEPROM | DC21041_EEPROM))
+ printf(" Port selection is %s-duplex.\n",
+ csr6 & 0x0200 ? "full" : "half");
+ else if (flags & COMET_MACADDR) { /* ADMtek chips. */
+ printf(" Comet duplex is reported in the MII status registers.\n");
+ } else if (flags & PNIC2_MACADDR) { /* The PNIC-II chip. */
+ int csr14 = inl(ioaddr + CSR14);
+ printf(" Port selection is %s, %s-duplex.\n",
+ csr14 & 0x80 ? "N-Way autonegotiation" :
+ csr6 & 0x00040000 ? "100baseTx" : "10mpbs-serial",
+ csr6 & 0x0200 ? "full" : "half");
+ } else
+ printf(" Port selection is %s%s, %s-duplex.\n",
+ ! (csr6 & 0x00040000) ? "10mpbs-serial" :
+ (csr6 & 0x00800000 ? "100mbps-SYM/PCS" : "MII"),
+ (csr6 & 0x01800000)==0x01800000 ? " 100baseTx scrambler":"",
+ csr6 & 0x0200 ? "full" : "half");
+ printf(" Transmit %s, Receive %s, %s-duplex.\n",
+ csr6 & 0x2000 ? "started" : "stopped",
+ csr6 & 0x0002 ? "started" : "stopped",
+ csr6 & 0x0200 ? "full" : "half");
+ printf(" The Rx process state is '%s'.\n",
+ rx_state[(csr5 >> 17) & 7]);
+ printf(" The Tx process state is '%s'.\n",
+ tx_state[(csr5 >> 20) & 7]);
+ if (csr5 & 0x2000)
+ printf(" PCI bus error!: %s.\n",
+ bus_error[(csr5 >> 23) & 7]);
+ if (csr6 & 0x00200000)
+ printf(" The transmit unit is set to store-and-forward.\n");
+ else {
+ const short tx_threshold[2][4] = {{ 72, 96, 128, 160 },
+ {128,256, 512, 1024}};
+ printf(" The transmit threshold is %d.\n",
+ tx_threshold[(csr6&0x00440000) == 0x00040000][(csr6>>14) & 3]);
+ }
+ if (csr5 & 0x18000) {
+ printf(" Interrupt sources are pending! CSR5 is %8.8x.\n", csr5);
+ for (i = 0; i < 15; i++)
+ if (csr5 & (1<<i))
+ printf(" %s indication.\n", intr_names[i]);
+ }
+ }
+
+ if (flags & HAS_NWAY)
+ printf(" The NWay status register is %8.8x.\n", inl(ioaddr + CSR12));
+
+ if (flags & COMET_MACADDR) {
+ printf(" Comet MAC address registers %8.8x %8.8x\n"
+ " Comet multicast filter %8.8x%8.8x.\n",
+ inl(ioaddr + 0xA4), inl(ioaddr + 0xA8),
+ inl(ioaddr + 0xAC), inl(ioaddr + 0xB0));
+ } else if (flags & PNIC2_MACADDR) {
+ /* Grrr, damn Lite-On cannot use a consistent byte order. */
+ printf(" The current PNIC-II MAC address is "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x (%8.8x %8.8x).\n",
+ inb(ioaddr + 0xB8), inb(ioaddr + 0xB9), inb(ioaddr + 0xB2),
+ inb(ioaddr + 0xB3), inb(ioaddr + 0xB0), inb(ioaddr + 0xB1),
+ inl(ioaddr + 0xB8), inl(ioaddr + 0xB0));
+ printf(" The current PNIC-II WOL address is "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ inb(ioaddr + 0xBA), inb(ioaddr + 0xBB), inb(ioaddr + 0xC2),
+ inb(ioaddr + 0xC3), inb(ioaddr + 0xC0), inb(ioaddr + 0xC1));
+ }
+
+ /* Below this point might be unsafe while the interface is active. */
+ if (if_active && ! opt_f)
+ return 1;
+
+ if (flags & ASIX_MACADDR) {
+ printf(" The MAC/filter registers are ");
+ for (i = 0; i < 4; i++) {
+ outl(i, ioaddr + CSR13);
+ printf(" %8.8x", inl(ioaddr + CSR14));
+ }
+ printf(".\n");
+ }
+
+ if (opt_GPIO) {
+ printf("Setting the GPIO register %8.8x.\n", opt_GPIO);
+ outl(opt_GPIO, ioaddr + CSR15);
+ }
+ tulip_eeprom(ioaddr, flags);
+
+ /* Show up to four (not just the on-board) PHYs. */
+ if ((has_mii && verbose) || show_mii) {
+ int phys[4], phy, phy_idx = 0;
+ current_part_idx = part_idx; /* Hack, set a global */
+ mdio_sync(ioaddr);
+ for (phy = 1; phy <= 32 && phy_idx < 4; phy++) {
+ int mii_status = mdio_read(ioaddr, phy & 0x1f, 1);
+ if (mii_status != 0xffff &&
+ mii_status != 0x0000) {
+ phys[phy_idx++] = phy & 0x1f;
+ printf(" MII PHY found at address %d, status 0x%4.4x.\n",
+ phy & 0x1f, mii_status);
+ }
+ }
+ if (phy_idx) {
+ if (nway_advertise > 0) {
+ printf(" Setting the media capability advertisement register"
+ " of PHY #%d to 0x%4.4x.\n",
+ phys[0], nway_advertise | 1);
+ mdio_write(ioaddr, phys[0], 4, nway_advertise | 1);
+ }
+ if (opt_restart) {
+ printf("Restarting negotiation...\n");
+ mdio_write(ioaddr, phys[0], 0, 0x0000);
+ mdio_write(ioaddr, phys[0], 0, 0x1200);
+ }
+ /* Force 100baseTx-HD by mdio_write(ioaddr,phys[0], 0, 0x2000); */
+ if (fixed_speed >= 0) {
+ int reg0_val = 0;
+ reg0_val |= (fixed_speed & 0x0180) ? 0x2000 : 0;
+ reg0_val |= (fixed_speed & 0x0140) ? 0x0100 : 0;
+ printf("Setting the speed to \"fixed\", %4.4x.\n", reg0_val);
+ mdio_write(ioaddr, phys[0], 0, reg0_val);
+ }
+ }
+ if (phy_idx == 0)
+ printf(" No MII transceivers found!\n");
+#ifdef LIBMII
+ else {
+ if (show_mii > 1)
+ show_mii_details(ioaddr, phys[0]);
+ if (opt_watch || show_mii > 2)
+ monitor_mii(ioaddr, phys[0]);
+ }
+#else
+ else for (phy = 0; phy < phy_idx; phy++) {
+ int mii_reg;
+ printf(" MII PHY #%d transceiver registers:", phys[phy]);
+ for (mii_reg = 0; mii_reg < 32; mii_reg++)
+ printf("%s %4.4x", (mii_reg % 8) == 0 ? "\n " : "",
+ mdio_read(ioaddr, phys[phy], mii_reg));
+ printf(".\n");
+ }
+#endif
+ }
+ if (flags & HAS_NWAY)
+ setup_nway_xcvr(ioaddr);
+
+#ifdef LIBFLASH
+ flash_in_hook = tulip_flash_in;
+ flash_out_hook = tulip_flash_out;
+ if (opt_flash_show)
+ flash_show(ioaddr, 0);
+ if (opt_flash_dumpfile)
+ if (flash_dump(ioaddr, 0, opt_flash_dumpfile) < 0) {
+ fprintf(stderr, "Failed to save the old Flash BootROM image into"
+ " file '%s'.\n", opt_flash_dumpfile);
+ return 3;
+ }
+ if (opt_flash_loadfile) {
+ outl(0x3000, ioaddr + CSR9);
+ if (flash_program(ioaddr, 0, opt_flash_loadfile) < 0) {
+ fprintf(stderr, "Failed to load the new Flash BootROM image from"
+ " file '%s'.\n", opt_flash_loadfile);
+ return 4;
+ }
+ }
+#else
+ if (opt_flash_loadfile || opt_flash_dumpfile || opt_flash_show)
+ printf("Flash operations not configured into this program.\n");
+ if (opt_flash_show) {
+ printf("The first few boot ROM bytes are:");
+ for (i = 0; i < 8; i++)
+ printf(" %2.2x", tulip_flash_in(ioaddr, i));
+ printf(".\n");
+ }
+#endif
+
+ return 0;
+}
+
+#include <ctype.h>
+static void tulip_eeprom(long ioaddr, int flags)
+{
+ int eeprom_words = 64;
+ int i;
+
+ /* Read the EEPROM. */
+ memset(eeprom_contents, 0, sizeof(eeprom_contents));
+ if (flags & DC21040_EEPROM) {
+ outl(0, ioaddr + CSR9); /* Reset the pointer with a dummy write. */
+ for (i = 0; i < 128; i++) {
+ int value, boguscnt = 100000, sum = 0;
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ ((unsigned char *)eeprom_contents)[i] = value;
+ if (i < 6)
+ sum += value & 0xff;
+ }
+ } else if (flags & PNIC_EEPROM) {
+ for (i = 0; i < eeprom_words; i++) {
+ int value, boguscnt = 100000;
+ unsigned short sum;
+ outl(0x600 | i, ioaddr + 0x98);
+ do
+ value = inl(ioaddr + CSR9);
+ while (value < 0 && --boguscnt > 0);
+ ((unsigned short *)eeprom_contents)[i] = value;
+ sum += value & 0xffff;
+ }
+ } else {
+ u16 *eew = (u16 *)eeprom_contents;
+ u16 andsum = 0xffff;
+ int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+ eeprom_words = ee_addr_size == 8 ? 256 : 64;
+
+ if (show_eeprom)
+ printf("EEPROM %d words, %d address bits.\n",
+ eeprom_words, ee_addr_size);
+
+ for (i = 0; i < eeprom_words; i++)
+ andsum &= (eew[i] = read_eeprom(ioaddr, i, ee_addr_size));
+ if (andsum == 0xffff)
+ printf("WARNING: The EEPROM is missing or erased!\n");
+ }
+
+ /* The user will usually want to see the interpreted EEPROM contents. */
+ if (show_eeprom || verbose > 1) {
+ if (flags & DC21040_EEPROM)
+ ;
+ else if (flags & PNIC_MTABLE)
+ liteon_eeprom((unsigned char *)eeprom_contents, flags);
+ else if (flags & COMET_MACADDR) /* All ADMtek chips. */
+ admtek_eeprom((unsigned char *)eeprom_contents, flags);
+ else if (flags & IS_CONEXANT)
+ conexant_eeprom((unsigned char *)eeprom_contents, flags);
+ else if (flags & IS_CONEXANT)
+ davicom_eeprom((unsigned char *)eeprom_contents, flags);
+ else
+ parse_eeprom((unsigned char *)eeprom_contents, flags);
+
+ if (show_eeprom > 1) {
+ int block_crc = (calculate_checksum1(eeprom_contents, 8)>>8) & 0xff;
+ int full_crc =
+ (ether_crc_le((void*)eeprom_contents, 126) ^ 0xffff) & 0xffff;
+ printf("EEPROM contents (%d words):", eeprom_words);
+ for (i = 0; i < eeprom_words; i += 8) {
+ int j;
+ printf("\n0x%2.2x: ", i);
+ for (j = 0; j < 8; j++)
+ printf(" %4.4x", eeprom_contents[i + j]);
+ if (show_eeprom > 2) {
+ printf(" ");
+ for (j = 0; j < 8; j++) {
+ int ew = eeprom_contents[i + j];
+ printf("%c%c",
+ isalnum(ew & 0xff) ? ew & 0xff : '_',
+ isalnum(ew >> 8) ? ew >> 8 : '_' );
+ }
+ }
+ }
+ printf("\n ID block CRC %#2.2x (vs. %#2.2x).\n"
+ " Full contents CRC 0x%4.4x (read as 0x%4.4x).\n",
+ block_crc, eeprom_contents[8] & 0xff,
+ full_crc, eeprom_contents[63]);
+ }
+ }
+ /* Check for a bogus Intel CardBus card. */
+ if (eeprom_contents[0] == 0x8086 && eeprom_contents[1] == 0x0001 &&
+ eeprom_contents[2] == 0x0087)
+ check_for_intel_cb(ioaddr, eeprom_contents);
+ if (new_default_media >= 0) {
+ if (default_media_offset > 0)
+ do_update(ioaddr, eeprom_contents, default_media_offset/2,
+ "Default Media", mediamap[new_default_media].value);
+ }
+}
+
+/* Reading a serial EEPROM is a "bit" grungy, but we work our way through:->.*/
+/* This code is a "nasty" timing loop, but PC compatible machines are
+ *supposed* to delay an ISA-compatible period for the SLOW_DOWN_IO macro. */
+#define eeprom_delay() inl(ee_addr)
+
+/* EEPROM_Ctrl bits. */
+#define EE_SHIFT_CLK 0x02 /* EEPROM shift clock. */
+#define EE_CS 0x01 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_WRITE_0 0x4801
+#define EE_WRITE_1 0x4805
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_ENB (0x4800 | EE_CS)
+
+/* The EEPROM commands include the alway-set leading bit. */
+#define EE_WRITE_CMD (5)
+#define EE_READ_CMD (6)
+#define EE_ERASE_CMD (7)
+
+/* Note: this routine returns extra data bits for size detection. */
+static int read_eeprom(long ioaddr, int location, int addr_len)
+{
+ int i;
+ unsigned retval = 0;
+ long ee_addr = ioaddr + CSR9;
+ int read_cmd = location | (EE_READ_CMD << addr_len);
+
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ outl(EE_ENB, ee_addr);
+
+ if (debug > 2)
+ printf(" EEPROM read at %d ", location);
+
+ /* Shift the read command bits out. */
+ for (i = 4 + addr_len; i >= 0; i--) {
+ short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0;
+ outl(EE_ENB | dataval, ee_addr);
+ eeprom_delay();
+ outl(EE_ENB | dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ if (debug > 2)
+ printf("%X", inl(ee_addr) & 15);
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ }
+ outl(EE_ENB, ee_addr);
+ if (debug > 2)
+ printf(" :%X:", inl(ee_addr) & 15);
+
+ for (i = 16; i > 0; i--) {
+ outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ if (debug > 2)
+ printf("%X", inl(ee_addr) & 15);
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outl(EE_ENB, ee_addr);
+ eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ if (debug > 2)
+ printf(" EEPROM value at %d is %5.5x.\n", location, retval);
+ return retval;
+}
+
+/* This executes a generic EEPROM command, typically a write or write enable.
+ It returns the data output from the EEPROM, and thus may also be used for
+ reads. */
+static int do_eeprom_cmd(long ioaddr, int cmd, int cmd_len)
+{
+ unsigned retval = 0;
+ long ee_addr = ioaddr + CSR9;
+
+ if (debug > 1)
+ printf(" EEPROM op 0x%x: ", cmd);
+
+ outl(EE_ENB | EE_SHIFT_CLK, ee_addr);
+
+ /* Shift the command bits out. */
+ do {
+ short dataval = (cmd & (1 << cmd_len)) ? EE_WRITE_1 : EE_WRITE_0;
+ outl(dataval, ee_addr);
+ eeprom_delay();
+ if (debug > 2)
+ printf("%X", inl(ee_addr) & 15);
+ outl(dataval | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ retval = (retval << 1) | ((inl(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ } while (--cmd_len >= 0);
+ outl(EE_ENB, ee_addr);
+
+ /* Terminate the EEPROM access. */
+ outl(EE_ENB & ~EE_CS, ee_addr);
+ if (debug > 1)
+ printf(" EEPROM result is 0x%5.5x.\n", retval);
+ return retval;
+}
+
+/* Read and write the MII registers using software-generated serial
+ MDIO protocol. It is just different enough from the EEPROM protocol
+ to not share code. The maxium data clock rate is 2.5 Mhz. */
+#define mdio_delay() inl(mdio_addr) /* Extra bus turn-around as a delay. */
+
+#define MDIO_SHIFT_CLK 0x10000
+#define MDIO_DATA_WRITE0 0x00000
+#define MDIO_DATA_WRITE1 0x20000
+#define MDIO_ENB 0x00000 /* Ignore the 0x02000 databook setting. */
+#define MDIO_ENB_IN 0x40000
+#define MDIO_DATA_READ 0x80000
+
+/* Syncronize the MII management interface by shifting 32 one bits out. */
+static void mdio_sync(long ioaddr)
+{
+ long mdio_addr = ioaddr + CSR9;
+ int i;
+
+ if (pcidev_tbl[current_part_idx].flags & (PNIC_MII|COMET_MII))
+ return;
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return;
+}
+
+int mdio_read(long ioaddr, int phy_id, int location)
+{
+ int i;
+ int read_cmd = (0xf6 << 10) | (phy_id << 5) | location;
+ int retval = 0, saved_0xfc = 0;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (verbose > 2) /* Debug: 5 */
+ printf(" mdio_read(%#lx, %d, %d)..", ioaddr, phy_id, location);
+ if (pcidev_tbl[current_part_idx].flags & PNIC_MII) {
+ int i = 1000;
+ outl(0x60020000 + (phy_id<<23) + (location<<18), ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ inl(ioaddr + 0xA0);
+ while (--i > 0)
+ if ( ! ((retval = inl(ioaddr + 0xA0)) & 0x80000000))
+ break;
+ if (debug)
+ printf("Register at %#lx is %#x (%#x).\n", ioaddr,
+ inl(ioaddr + 0xA0), retval & 0xffff);
+ return retval & 0xffff;
+ }
+ if (pcidev_tbl[current_part_idx].flags & COMET_MII) {
+ if (phy_id == 1) {
+ if (location < 7)
+ return inl(ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ return inl(ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ return inl(ioaddr + 0xD4 + ((location-29)<<2));
+ }
+ return 0xffff;
+ }
+ if (pcidev_tbl[current_part_idx].flags & COMET_HPNA) {
+ saved_0xfc = inl(ioaddr + 0xfc);
+ if (phy_id == 1) outl(0x00, ioaddr + 0xfc);
+ else if (phy_id == 2) outl(0x24, ioaddr + 0xfc);
+ }
+
+ /* Establish sync by sending at least 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the read command bits out. */
+ for (i = 17; i >= 0; i--) {
+ int dataval = (read_cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ if (verbose > 3) /* Debug: 5 */
+ printf("%d", (read_cmd & (1 << i)) ? 1 : 0);
+
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ if (verbose > 3) printf(" %x", (inl(mdio_addr) >> 16) & 0x0f);
+ mdio_delay();
+ }
+ if (verbose > 3) printf("-> %x", (inl(mdio_addr) >> 16) & 0x0f);
+
+ /* Read the two transition, 16 data, and wire-idle bits. */
+ for (i = 19; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ retval = (retval << 1) | ((inl(mdio_addr) & MDIO_DATA_READ) ? 1 : 0);
+ if (verbose > 3) printf(" %x", (inl(mdio_addr) >> 16) & 0x0f);
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ if (verbose > 3) printf(" == %4.4x.\n", retval);
+ if (pcidev_tbl[current_part_idx].flags & COMET_HPNA)
+ outl(saved_0xfc, ioaddr + 0xfc);
+ return (retval>>1) & 0xffff;
+}
+
+void mdio_write(long ioaddr, int phy_id, int location, int value)
+{
+ int i;
+ int cmd = (0x5002 << 16) | (phy_id << 23) | (location<<18) | value;
+ long mdio_addr = ioaddr + CSR9;
+
+ if (pcidev_tbl[current_part_idx].flags & COMET_MII) {
+ if (phy_id == 1) {
+ if (location < 7)
+ outl(value, ioaddr + 0xB4 + (location<<2));
+ else if (location == 17)
+ outl(value, ioaddr + 0xD0);
+ else if (location >= 29 && location <= 31)
+ outl(value, ioaddr + 0xD4 + ((location-29)<<2));
+ }
+ return;
+ }
+ /* Establish sync by sending 32 logic ones. */
+ for (i = 32; i >= 0; i--) {
+ outl(MDIO_ENB | MDIO_DATA_WRITE1, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | MDIO_DATA_WRITE1 | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Shift the command bits out. */
+ for (i = 31; i >= 0; i--) {
+ int dataval = (cmd & (1 << i)) ? MDIO_DATA_WRITE1 : 0;
+ outl(MDIO_ENB | dataval, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB | dataval | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ /* Clear out extra bits. */
+ for (i = 2; i > 0; i--) {
+ outl(MDIO_ENB_IN, mdio_addr);
+ mdio_delay();
+ outl(MDIO_ENB_IN | MDIO_SHIFT_CLK, mdio_addr);
+ mdio_delay();
+ }
+ return;
+}
+
+#include <sys/time.h>
+
+const char *nway_state[8] = {
+ "Autonegotiation disabled", "Transmit disabled", "Ability detect",
+ "Acknowledge detect", "Complete acknowledge", "Negotiation complete",
+ "Link check", "Invalid state"
+};
+
+static void setup_nway_xcvr(long ioaddr)
+{
+ int csr12 = inl(ioaddr + CSR12);
+ int i;
+ printf(" Internal autonegotiation state is '%s'.\n",
+ nway_state[(csr12 >> 12) & 7]);
+ if (opt_restart) { /* Restart NWay. */
+ int csr6 = inl(ioaddr + CSR6) & 0xFDFF;
+ if (nway_advertise > 0) {
+ int csr_setting = ((nway_advertise & 0x0380) << 9) |
+ ((nway_advertise & 0x0020) << 1);
+ if (verbose)
+ printf("Setting 21142 N-Way advertisement to %4.4x "
+ "(%x).\n", nway_advertise, csr_setting );
+ outl(0x000FFBF | csr_setting, ioaddr + CSR14);
+ outl((nway_advertise & 0x0040 ? 0x82420200 : 0x82420000) | csr6,
+ ioaddr + CSR6);
+ } else {
+ outl(0x0003FFFF, ioaddr + CSR14);
+ outl(0x82420200 | csr6, ioaddr + CSR6);
+ }
+#if 0
+ printf(" Writing the CSR15 direction bits.\n");
+ outl(0x08af0000, ioaddr + CSR15);
+ outl(0x00050000, ioaddr + CSR15);
+#endif
+ if (opt_reset) {
+ printf(" Resetting the 21143 SIA registers.\n");
+ outl(0x0000, ioaddr + CSR13);
+ outl(0x0001, ioaddr + CSR13);
+ }
+ outl(0x1000, ioaddr + CSR12); /* Start NWay. */
+ csr12 = inl(ioaddr + CSR12);
+ printf(" Internal autonegotiation state is now '%s' CSR12 %x.\n"
+ " CSR13 %x CSR14 %x CSR15 %x.\n",
+ nway_state[(csr12 >> 12) & 7],
+ csr12, inl(ioaddr + CSR13),
+ inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ for (i = 0; i < 400; i++) {
+ struct timeval sleepval;
+ sleepval.tv_sec = 0;
+ sleepval.tv_usec = 10000;
+ select(0, 0, 0, 0, &sleepval); /* Or just sleep(1); */
+ if (csr12 != inl(ioaddr + CSR12)) {
+ csr12 = inl(ioaddr + CSR12);
+ printf(" Internal autonegotiation state is now '%s', "
+ "CSR12 %x.\n"
+ " CSR5 %x CSR13 %x CSR14 %x CSR15 %x.\n",
+ nway_state[(csr12 >> 12) & 7],
+ csr12, inl(ioaddr + CSR5), inl(ioaddr + CSR13),
+ inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ }
+ }
+ printf(" Final autonegotiation state is '%s', CSR12 %x.\n"
+ " CSR5 %x CSR13 %x CSR14 %x CSR15 %x.\n",
+ nway_state[(inl(ioaddr + CSR12) >> 12) & 7],
+ inl(ioaddr + CSR12), inl(ioaddr + CSR5), inl(ioaddr + CSR13),
+ inl(ioaddr + CSR14), inl(ioaddr + CSR15));
+ /* We must explicitly switch to 100mbps mode. */
+ if (((nway_advertise > 0 ? nway_advertise : 0x01e1) &
+ inl(ioaddr + CSR12) >> 16) & 0x0180)
+ outl(0x83860200, ioaddr + CSR6);
+ }
+}
+
+/* Calculate the EEPROM checksums. */
+
+#define CRC1_POLYNOMIAL 0x07 /* x^8 + x^2 + x^1 + 1 */
+static unsigned int
+calculate_checksum1(unsigned short *eeprom, int len)
+{
+ u16 crc = 0xffff;
+ int i, bit;
+
+ for (i = 0; i <= len; i++) /* Note: loc. 18 is the sum. */
+ for (bit = 15; bit >= 0; bit--) {
+ /* Note: bits ordered as read from EEPROM */
+ crc <<= 1;
+ if (((eeprom[i]>>bit) ^ (crc >> 8)) & 1)
+ crc ^= CRC1_POLYNOMIAL;
+ }
+ return crc;
+}
+
+static unsigned const ethernet_polynomial_le = 0xedb88320U;
+static unsigned int ether_crc_le(void *ptr, int length)
+{
+ unsigned char *data = ptr;
+ unsigned int crc = 0xffffffff; /* Initial value. */
+ while(--length >= 0) {
+ unsigned char current_octet = *data++;
+ int bit;
+ for (bit = 8; --bit >= 0; current_octet >>= 1) {
+ if ((crc ^ current_octet) & 1) {
+ crc >>= 1;
+ crc ^= ethernet_polynomial_le;
+ } else
+ crc >>= 1;
+ }
+ }
+ return crc;
+}
+
+int do_update(long ioaddr, unsigned short *ee_values,
+ int index, char *field_name, int new_value)
+{
+ if (ee_values[index] == new_value)
+ return 0;
+ if (do_write_eeprom) {
+ int ee_addr_size = read_eeprom(ioaddr, 0xff, 8) & 0x40000 ? 8 : 6;
+ int i;
+ u16 newval;
+ printf("Writing new %s entry 0x%4.4x to offset %d.\n",
+ field_name, new_value, index);
+ /* Enable programming modes. */
+ do_eeprom_cmd(ioaddr, (0x4f << (ee_addr_size-4)), 3+ee_addr_size);
+ /* Do the actual write. */
+ do_eeprom_cmd(ioaddr,
+ (((EE_WRITE_CMD<<ee_addr_size)|index) << 16) | new_value,
+ 3 + ee_addr_size + 16);
+ /* Poll for write finished. */
+ outl(EE_ENB, ioaddr + CSR9);
+ for (i = 0; i < 10000; i++) /* Typical 2000 ticks */
+ if (inl(ioaddr + CSR9) & EE_DATA_READ)
+ break;
+ if (debug)
+ printf(" Write finished after %d ticks.\n", i);
+ /* Disable programming. */
+ do_eeprom_cmd(ioaddr, (0x40 << (ee_addr_size-4)), 3 + ee_addr_size);
+ /* And read the result. */
+ newval = do_eeprom_cmd(ioaddr,
+ (((EE_READ_CMD<<ee_addr_size)|index) << 16)
+ | 0xffff, 3 + ee_addr_size + 16);
+ printf(" New %s value at offset %d is %4.4x.\n",
+ field_name, index, newval);
+ } else
+ printf(" Would write new %s entry 0x%4.4x to offset %d, the "
+ "current value is 0x%4.4x.\n",
+ field_name, new_value, index, ee_values[index]);
+ ee_values[index] = new_value;
+ return 1;
+}
+
+
+/* Parse and emit the information from the EEPROM table. */
+
+static const char * const medianame[32] = {
+ "10baseT", "10base2", "AUI", "100baseTx",
+ "10baseT-Full Duplex", "100baseTx Full Duplex", "100baseT4", "100baseFx",
+ "100baseFx-Full Duplex", "MII 10baseT", "MII 10baseT-Full Duplex", "MII",
+ "", "MII 100baseTx", "MII 100baseTx-Full Duplex", "MII 100baseT4",
+ "MII 100baseFx-HDX", "MII 100baseFx-FDX", "Home-PNA 1Mbps", "",
+};
+
+struct mediainfo {
+ struct mediainfo *next;
+ int info_type;
+ struct non_mii { char media, csr12val, bitnum, flags;} non_mii;
+ unsigned char *mii;
+};
+
+static void parse_eeprom(unsigned char *ee_data, int flags)
+{
+ unsigned char csr12;
+ unsigned char *p;
+ int count, sum, media_idx, i;
+ int default_media;
+
+ for (i = 0, sum = 0xff; i < 6; i++)
+ sum &= ee_data[i];
+ if (sum == 0xff) {
+ printf(" This interface is missing the EEPROM.\n This is likely the "
+ "non-primary interface on a multiport board.\n");
+ return;
+ }
+ /* Detect an old-style (SA only) EEPROM layout. */
+ if (memcmp(ee_data, ee_data + 16, 8) == 0) {
+ /* Should actually do a fix-up based on the vendor half of the station
+ address prefix here. Or least use that information to report which
+ transceiver will work. */
+ printf(" * An old-style EEPROM layout was found.
+ * The old-style layout does not contain transceiver control information.
+ * This board may not work, or may work only with a subset of transceiver
+ * options or data rates.\n");
+ return;
+ } else if (ee_data[27] == 0) {
+ printf(" A simplifed EEPROM data table was found.\n"
+ " The EEPROM does not contain transceiver control information.\n");
+ return;
+ }
+
+ printf("PCI Subsystem IDs, vendor %2.2x%2.2x, device %2.2x%2.2x.\n"
+ "CardBus Information Structure at offset %2.2x%2.2x%2.2x%2.2x.\n",
+ ee_data[1], ee_data[0], ee_data[3], ee_data[2],
+ ee_data[7], ee_data[6], ee_data[5], ee_data[4]);
+
+ printf("Ethernet MAC Station Address "
+ "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X.\n",
+ ee_data[20], ee_data[21], ee_data[22],
+ ee_data[23], ee_data[24], ee_data[25]);
+
+ if (ee_data[19] != 1)
+ printf("This table is for a multiport card with %d controllers.\n",
+ ee_data[19]);
+
+ printf("EEPROM transceiver/media description table.\n");
+ if (ee_data[27] == 0)
+ return;
+ default_media_offset = ee_data[27];
+ p = (void *)ee_data + ee_data[27];
+ default_media = get_unaligned((u16 *)p);
+ p += 2;
+ printf("Leaf node at offset %d, default media type %4.4x (%s).\n",
+ ee_data[27], default_media, default_media & 0x0800 ? "Autosense"
+ : medianame[default_media & 31]);
+ if (flags & CSR12_IS_GPIO) {
+ csr12 = *p++;
+ printf(" CSR12 direction setting bits 0x%2.2x.\n", csr12);
+ }
+ count = *p++;
+ printf(" %d transceiver description blocks:\n", count);
+
+ for (media_idx = 0; media_idx < count; media_idx++) {
+ if (flags & 0x01) {
+ printf(" 21041 media index %2.2x (%s).\n",
+ p[0] & 0x3f, medianame[p[0] & 31]);
+ if (p[0] & 0x40) {
+ printf(" CSR Register override settings for this media:"
+ " %2.2x%2.2x %2.2x%2.2x %2.2x%2.2x.\n",
+ p[2], p[1], p[4], p[3], p[6], p[5]);
+ p += 7;
+ } else
+ p += 1;
+ } else if (p[0] & 0x80) { /* Extended block */
+ int blk_type = p[1];
+ if (show_eeprom)
+ printf(" Media %s, block type %d, length %d.\n",
+ p[1] & 1 ? "MII" : medianame[p[2] & 31],
+ blk_type, p[0] & 0x7f);
+ switch (blk_type) {
+ case 0:
+ printf(" AUI or SYM transceiver for %s (media type %d).\n"
+ " CSR12 control port setting %#2.2x,"
+ " command 0x%2.2x 0x%2.2x.\n",
+ medianame[p[2] & 31], p[2], p[3], p[5], p[4]);
+ if (p[5] & 0x80) {
+ printf(" No media-active status available.\n");
+ break;
+ }
+ printf(" Media detection by looking for a %d on bit %d of"
+ " the CSR12 control port.\n",
+ (p[4] & 0x80) ? 0 : 1, (p[4] >> 1) & 7);
+ break;
+ case 1: /* 21140 MII PHY*/
+ case 3: { /* 21142 MII PHY */
+ int init_length = p[3];
+ u16 *misc_info;
+
+ printf(" MII interface PHY %d (media type 11).\n", p[2]);
+ if (blk_type == 3) { /* 21142 */
+ u16 *init_sequence = (u16*)(p+4);
+ u16 *reset_sequence = &((u16*)(p+5))[init_length];
+ int reset_length = p[4 + init_length*2];
+ misc_info = reset_sequence + reset_length;
+ printf(" 21143 MII initialization sequence is %d "
+ "words:", init_length);
+ for (i = 0; i < init_length; i++)
+ printf(" %4.4x", get_unaligned(init_sequence + i));
+ printf(".\n 21143 MII reset sequence is %d words:",
+ reset_length);
+ for (i = 0; i < reset_length; i++)
+ printf(" %4.4x", get_unaligned(reset_sequence + i));
+ printf(".\n");
+ } else {
+ u8 *init_sequence = p + 4;
+ u8 *reset_sequence = p + 5 + init_length;
+ int reset_length = p[4 + init_length];
+ misc_info = (u16*)(reset_sequence + reset_length);
+ if (reset_length) {
+ printf(" 21140 MII Reset sequence is %d words:",
+ reset_length);
+ for (i = 0; i < reset_length; i++)
+ printf(" %2.2x", reset_sequence[i]);
+ } else
+ printf(" No MII reset sequence.");
+ if (init_length) {
+ printf(".\n 21140 MII initialization sequence is "
+ "%d words:", init_length);
+ for (i = 0; i < init_length; i++)
+ printf(" %2.2x", init_sequence[i]);
+ printf(".\n");
+ } else
+ printf(" No MII initialization sequence.\n");
+ }
+
+ printf(" Media capabilities are %4.4x, advertising %4.4x.\n"
+ " Full-duplex map %4.4x, Threshold map %4.4x.\n",
+ get_unaligned(misc_info + 0),
+ get_unaligned(misc_info + 1) | 1,
+ get_unaligned(misc_info + 2),
+ get_unaligned(misc_info + 3));
+ if (blk_type == 3) { /* 21142 */
+ if ((*(u8 *)(misc_info+4)) > 0)
+ printf(" MII interrupt on GPIO pin %d.\n",
+ (*(u8 *)(misc_info+3)) - 1);
+ else
+ printf(" No MII interrupt.\n");
+ }
+ has_mii++;
+ break;
+ }
+ case 2: /* 21142 SYM or AUI */
+ case 4:
+ printf(" %s transceiver for %s (media type %d).\n",
+ blk_type == 2 ? "Serial" : "SYM",
+ medianame[p[2] & 31], p[2]);
+ if ( ! show_eeprom)
+ break;
+ if (p[2] & 0x40)
+ printf(" CSR13 %2.2x%2.2x CSR14 %2.2x%2.2x"
+ " CSR15 %2.2x%2.2x.\n GP pin direction "
+ "%2.2x%2.2x GP pin data %2.2x%2.2x.\n",
+ p[4], p[3], p[6], p[5], p[8], p[7], p[10], p[9],
+ p[12], p[11]);
+ else
+ printf(" GP pin direction %2.2x%2.2x "
+ "GP pin data %2.2x%2.2x.\n",
+ p[4], p[3], p[6], p[5]);
+ if (blk_type == 4) {
+ if (p[8] & 0x80)
+ printf(" No media detection indication (command "
+ "%2.2x %2.2x).\n", p[8], p[7]);
+ else
+ printf(" Media detection by looking for a %d on "
+ "general purpose pin %d.\n",
+ (p[7] & 0x80) ? 0 : 1, (p[7] >> 1) & 7);
+ }
+ break;
+ case 5:
+ printf(" Transceiver Reset, sequence length %d:", p[2]);
+ for( i = 0; i < p[2]; i++)
+ printf(" %2.2x%2.2x", p[i*2 + 4], p[i*2 + 3]);
+ printf(".\n");
+ break;
+ case 6:
+ printf(" Disconnect reset, sequence length %d:", p[3]);
+ for( i = 0; i < p[3]; i++)
+ printf(" %2.2x%2.2x", p[i*2 + 5], p[i*2 + 4]);
+ printf(".\n");
+ break;
+ default:
+ printf(" UNKNOW MEDIA DESCRIPTION BLOCK TYPE!\n ");
+ for(i = 1; i <= (p[0] & 0x1f); i++)
+ printf(" %2.2x", p[i]);
+ printf(".\n");
+ break;
+ }
+ p += (p[0] & 0x3f) + 1;
+ } else { /* "Compact" blocks (aka design screw-up). */
+ printf(" 21140 Non-MII transceiver for media %d (%s).\n"
+ " CSR12 control port setting %#2.2x,"
+ " command %#2.2x %#2.2x.\n",
+ p[0], medianame[p[0] & 31], p[1], p[3], p[2]);
+ if (p[3] & 0x80) {
+ printf(" No media-active status available.\n");
+ } else
+ printf(" Media detection by looking for a %d on bit %d of"
+ " the CSR12 control port.\n",
+ (p[2] & 0x80) ? 0 : 1, (p[2] >> 1) & 7);
+ p += 4;
+ }
+ }
+
+ if (ee_data[19] >= 4) { /* Show the Magic Packet block. */
+ int b = 128 - 32; /* Magic Packet block offset */
+ int magic_cmd = ee_data[b + 12];
+ printf(" The Magic Packet address is "
+ "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X.\n",
+ ee_data[b + 6], ee_data[b + 7], ee_data[b + 8],
+ ee_data[b + 9], ee_data[b + 10], ee_data[b + 11]);
+ if (magic_cmd & 2)
+ printf(" The Magic Packet password is "
+ "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X.\n",
+ ee_data[b + 0], ee_data[b + 1], ee_data[b + 2],
+ ee_data[b + 3], ee_data[b + 4], ee_data[b + 5]);
+ }
+}
+
+static void liteon_eeprom(unsigned char *ee_data, int part_idx)
+{
+ printf(" Ethernet MAC Station Address "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ ee_data[20], ee_data[21], ee_data[22],
+ ee_data[23], ee_data[24], ee_data[25]);
+ /* Note: This code matches the documentation, but I suspect that it is
+ the documentation that is byte-reversed. */
+ printf(" Wake-On-LAN ID bytes "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ ee_data[27], ee_data[26], ee_data[29], ee_data[28],
+ ee_data[59], ee_data[58]);
+ printf(" PCI Subsystem IDs Vendor %2.2x%2.2x Device %2.2x%2.2x\n",
+ ee_data[93], ee_data[92], ee_data[90], ee_data[91]);
+}
+
+static struct alist { int num; const char *name; }
+admtek_media[] = { {0x0000, "10baseT"}, {0x0001, "BNC"}, {0x0002, "AUI"},
+ {0x0003, "100baseTx"}, {0x0004, "100baseT4"},
+ {0x0005, "100baseFx"}, {0x0010, "10baseT-FDX"},
+ {0x0013, "100baseTx-FDX"}, {0x0015, "100baseFx-FDX"},
+ {0x0100, "Autonegotiation"},{0x0200, "Power-on autosense"},
+ {0x0400, "Autosense"}, {0xFFFF, "Default"}, {0, ""}, };
+static void admtek_eeprom(unsigned char *ee_data, int part_idx)
+{
+ unsigned short *eew = (void *)ee_data;
+ int i;
+ printf(" Ethernet MAC Station Address "
+ "%2.2x:%2.2x:%2.2x:%2.2x:%2.2x:%2.2x.\n",
+ ee_data[8], ee_data[9], ee_data[10],
+ ee_data[11], ee_data[12], ee_data[13]);
+ for (i = 0; admtek_media[i].name; i++)
+ if (admtek_media[i].num == eew[0x09]) {
+ printf(" Default connection type '%s'.\n", admtek_media[i].name);
+ break;
+ }
+ if (admtek_media[i].name == NULL)
+ printf(" Unknown default connection type '%#x'.\n", eew[0x09]);
+ printf(" PCI IDs Vendor %4.4x Device %4.4x "
+ " Subsystem %4.4x %4.4x\n",
+ eew[0x11], eew[0x10], eew[0x13], eew[0x12]);
+ printf(" PCI min_grant %d max_latency %d.\n",
+ ee_data[0x28], ee_data[0x29]);
+ printf(" CSR18 power-up setting 0x%4.4x****.\n", eew[0x17]);
+}
+
+static void conexant_eeprom(unsigned char *ee_data, int part_idx)
+{
+ printf("Conexant EEPROM format is undocumented.\n");
+}
+
+static void davicom_eeprom(unsigned char *ee_data, int part_idx)
+{
+ printf("PCI Subsystem IDs, vendor %2.2x%2.2x, device %2.2x%2.2x.\n"
+ "CardBus Information Structure at offset %2.2x%2.2x%2.2x%2.2x.\n",
+ ee_data[1], ee_data[0], ee_data[3], ee_data[2],
+ ee_data[7], ee_data[6], ee_data[5], ee_data[4]);
+ printf(" Checksum: calculated %4.4x vs %4.4x from EEPROM.\n",
+ ~ether_crc_le(ee_data, 126) & 0xffff, ee_data[63]);
+}
+
+static void check_for_intel_cb(long ioaddr, unsigned short *eeprom_contents)
+{
+ unsigned const char cis_addr_prefix[4] = {0x22, 0x08, 0x04, 0x06};
+ unsigned const short media_ctrl_tbl[] = {
+ 0x0103, 0x1100, 0x3322, 0x5544, 0x1e00, 0x0000, 0x0800, 0x8604,
+ 0x0002, 0x08af, 0x00a5, 0x0286, 0xaf04, 0xa508, 0x8800, 0x0304,
+ 0x08af, 0x00a5, 0x8061, 0x0488, 0xaf05, 0xa508, 0x6100, };
+ unsigned char cis_addr_tuple[10];
+ int i;
+
+ printf("You have an Intel CardBus card with an incomplete EEPROM.\n");
+ for (i = 0; i < 10; i++)
+ cis_addr_tuple[i] = tulip_flash_in(ioaddr, 0xeb + i);
+ if (memcmp(cis_addr_tuple, cis_addr_prefix, 4)) {
+ printf(" I could not locate the station address.\n");
+ return;
+ }
+ printf("The station address is ");
+ for (i = 0; i < 5; i++)
+ printf("%2.2x:", cis_addr_tuple[4 + i]);
+ printf("%2.2x\n", cis_addr_tuple[4 + i]);
+ memcpy(new_ee_contents, eeprom_contents, 18);
+ memcpy(new_ee_contents + 9, media_ctrl_tbl, sizeof(media_ctrl_tbl));
+ memcpy(new_ee_contents + 10, cis_addr_tuple + 4, 6);
+ new_ee_contents[63] = (ether_crc_le(eeprom_contents, 126) ^ 0xffff) & 0xffff;
+ printf("New EEPROM contents would be:");
+ for (i = 0; i < 64; i++)
+ printf("%s %4.4x", (i & 7) == 0 ? "\n ":"", new_ee_contents[i]);
+ printf("\n ID CRC %#2.2x (vs. %#2.2x), complete CRC %4.4x.\n",
+ (calculate_checksum1(new_ee_contents, 8) >> 8) & 0xff,
+ new_ee_contents[8] & 0xff, new_ee_contents[63]);
+ if (do_write_eeprom) {
+ for (i = 0; i < 64; i++)
+ do_update(ioaddr, eeprom_contents, i, "Intel media table update",
+ new_ee_contents[i]);
+ }
+}
+
+/*
+ * Local variables:
+ * compile-command: "cc -O -Wall -Wstrict-prototypes -o tulip-diag tulip-diag.c `[ -f libmii.c ] && echo -DLIBMII libmii.c` `[ -f libflash.c ] && echo -DLIBFLASH libflash.c`"
+ * simple-compile-command: "cc -O -o tulip-diag tulip-diag.c"
+ * tab-width: 4
+ * c-indent-level: 4
+ * c-basic-offset: 4
+ * End:
+ */
diff --git a/mktmp/Makefile b/mktmp/Makefile new file mode 100644 index 0000000..d915af2 --- /dev/null +++ b/mktmp/Makefile @@ -0,0 +1,9 @@ +OBJS=mktmp +include ../include/rules.make +CFLAGS+=-momit-leaf-frame-pointer + +%: %.c + $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $< + strip -R .comment -R .note $@ + objdump -h $@ | grep -q '\.data[ ]*00000000' && strip -R .data $@ || true + sstrip $@ diff --git a/mktmp/mktmp b/mktmp/mktmp Binary files differnew file mode 100755 index 0000000..7ca7eb4 --- /dev/null +++ b/mktmp/mktmp diff --git a/mktmp/mktmp.c b/mktmp/mktmp.c new file mode 100644 index 0000000..3230ff6 --- /dev/null +++ b/mktmp/mktmp.c @@ -0,0 +1,136 @@ +/* + * mklock - create a secured lock entry with given data + * (c) 2003 - willy tarreau - willy@ant-computing.com + * + * You may use, copy and redistribute with no restriction. Use at your own + * risk, I will not be held responsible for any loss or damage. + * + * usage : + * # mklock <directory> [data] + * + * This will create a symlink under <directory>, either pointing to <data> if + * <data> is specified, or pointing to /proc/<getppid()> if no data is given. + * This way, the link will automatically be broken as soon as the father dies. + * The name of the link will be generated randomly until no conflict happens + * with an existing entry. The full pathname of the resulting link is returned + * to stdout so that a script can easily use it. + * This method ensures the use of a secure lock. + * + * Example : + * # file=`mklock /tmp $$` + */ +#include <stdio.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> + +#define writetxt(fd, text) write(fd, text, strlen(text)) +#define LOCK_PREFIX ".lock." +#define PROC_PREFIX "/proc/" +#define MAX_PID_DIGITS 10 /* 10 digits do code a 32bit pid in decimal */ + +const char lock_prefix[] = LOCK_PREFIX; +const char proc_prefix[] = PROC_PREFIX; + +/* writes <l> in at most 9 decimal digits to <to> */ +void ultoa(char *to, unsigned long l) { + unsigned long div = 1000000000; + int zero = 1; + while (div > 0) { + *to = (l / div % 10) + '0'; + div /= 10; + zero &= (*to == '0'); + if (!zero) + to++; + } + *to = 0; +} + +/* writes <l> as 8 hex digits to <to> */ +void ultoh(char *to, unsigned long l) { + int shift = 32; + while ((shift -= 4) >= 0) { + int digit = (l >> shift) & 0xf; + if (digit > 9) + digit += 'A' - '9' - 1; + *to++ = digit + '0'; + } + *to = 0; +} + +void usage() { + writetxt(2, "Usage: mklock [ -d ] [ -p prefix ] <directory> [data]\n"); + exit(1); +} + +main(int argc, char **argv) { + char *text, *prefix; + char *directory; + char *fullname; + int len, num = 0, ret; + int use_dir = 0; + int plen; + + prefix = lock_prefix; + + argv++; argc--; + + while (argc > 0 && **argv == '-') { + if (!strcmp(*argv, "-d")) { + use_dir = 1; + } + else if (!strcmp(*argv, "-p")) { + if (argc > 1) { + argv++; argc--; + prefix = argv[0]; + } + else + usage(); + } + argv++; argc--; + } + + if (argc < 1) + usage(); + + plen = strlen(prefix); + directory = argv[0]; + len = strlen(directory); + while (len > 0 && directory[len - 1] == '/') + directory[--len] = 0; + + fullname = (char *)calloc(1, len + 1 + plen + 10); + memcpy(fullname, directory, len); + fullname[len++] = '/'; + memcpy(fullname + len, prefix, plen + 1); + len += plen; + + argv++; argc--; + + if (argc > 0) /* use this arg as where the link points to */ + text = argv[0]; + else { /* point to /proc/<getppid()> */ + text = (char *)malloc(strlen(PROC_PREFIX) + MAX_PID_DIGITS + 1); + memcpy(text, proc_prefix, strlen(PROC_PREFIX) + 1); + ultoa(text + strlen(PROC_PREFIX), getppid()); + } + + do { + /* try to create the entry with an increasing suffix until we succeed */ + ultoh(fullname+len, num++); + + if (use_dir) + ret = mkdir(fullname, 0700); + else + ret = symlink(text, fullname); + + if (ret == 0) { + fullname[len + 8]='\n'; + /* success, return the link or directory name */ + write(1, fullname, len + 9); + return 0; + } + } while (errno == EEXIST); + /* other error, let's return 2 */ + return 2; +} diff --git a/remount/Makefile b/remount/Makefile new file mode 100644 index 0000000..718de45 --- /dev/null +++ b/remount/Makefile @@ -0,0 +1,12 @@ +OBJS=remountr remountw +include ../include/rules.make +CFLAGS+=-fomit-frame-pointer + +remountw : remountr + ln -s $^ $@ + +%: %.c + $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $< + strip -R .comment -R .note $@ + objdump -h $@ | grep -q '\.data[ ]*00000000' && strip -R .data $@ || true + sstrip $@ diff --git a/remount/remountr b/remount/remountr Binary files differnew file mode 100755 index 0000000..eee0129 --- /dev/null +++ b/remount/remountr diff --git a/remount/remountr.c b/remount/remountr.c new file mode 100644 index 0000000..f45c39a --- /dev/null +++ b/remount/remountr.c @@ -0,0 +1,25 @@ +#include <stdio.h> + +const char mount_str[] = "/bin/mount"; +const char remount_str[] = "remount"; +const char slash_str[] = "/"; +const char ro_str[] = "-ro"; +const char wo_str[] = "-wo"; + +int main (int argc, char **argv) { + char *flag, *mntpnt; + + if (argv[0][strlen(argv[0])-1] == 'w') + flag = wo_str; + else + flag = ro_str; + + setreuid(0, 0); + if (argc > 1) + mntpnt = argv[1]; + else + mntpnt = slash_str; + + return execl(mount_str, mount_str, flag, remount_str, mntpnt, NULL); +} + diff --git a/remount/remountw b/remount/remountw new file mode 120000 index 0000000..5bc7a05 --- /dev/null +++ b/remount/remountw @@ -0,0 +1 @@ +remountr
\ No newline at end of file diff --git a/scripts/flxadd b/scripts/flxadd new file mode 100755 index 0000000..4723957 --- /dev/null +++ b/scripts/flxadd @@ -0,0 +1,350 @@ +#!/bin/sh + +yesno () { + echo -n "$1 [$2] : "; read + if [ "$REPLY" = "" ]; then + REPLY=$2; + fi + if [[ ( "$REPLY" = "O" ) || ( "$REPLY" = "o" ) || \ + ( "$REPLY" = "y" ) || ( "$REPLY" = "Y" ) ]]; then + REPLY="O" + return 0 + fi + return 1 +} + +update_sig () { + file=$1 +} + +update_dep () { + file=$1 +} + +if [ -z "$PKGROOT" ] ; then PKGROOT=/var/install; fi +T=/tmp/flx.inst.$$ +T1=$T/f1 +T2=$T/f2 +T3=$T/f3 +T4=$T/f4 +T5=$T/f5 +rm -rf $T ; mkdir $T ; touch $T3 +touch $T5 + +if [ -f $PKGROOT/depend.lst ] ; then + . $PKGROOT/depend.lst +fi + +force=0 +lookfordepend=1 +while [ $# -gt 0 ] ; do + case $1 in + -t) # install most recent + doitfor=time + ;; + -f) # force reinstall + force=1 + ;; + -f*) # force n reinstall recursive level + force=${1#-f} + ;; + -s) # install most recent + doitfor=size + ;; + -nd) # no dependence + lookfordepend=0 + ;; + -r) # change root dir + shift + ROOT=$1 + ;; + -v) # view only + mode=view + ;; + -I) # read from input + cat >> $T1 + ;; + *) echo $1 >> $T1 ;; + esac + shift +done + +exec 3>&0 +# lire l'existant et s'en servir de base +if [ -f $ROOT/etc/formilux/sig.dat ] ; then + grep -v ^d $ROOT/etc/formilux/sig.dat | awk '{ print $8 }' > $T3 +elif [ -f $ROOT/etc/formilux/depend.dat ] ; then + cat $ROOT/etc/formilux/depend.dat | cut -f1 -d' ' | cut -f1 -d'('> $T3 +# find . ! -type d > $T3 +fi +# lecture des fichiers de dependance de manière infinie +while [ -f $T1 ] ; do + # lecture sur la dernière liste non résolue +while read ; do + if [ -z "$REPLY" -o "${REPLY// /}" = "" ] ; then continue; fi + if [ "${REPLY/*\$*/\$}" = '$' ] ; then + REPLY=`eval echo "$REPLY"` + for i in $REPLY ; do + echo $i >> $T2 + done + continue + fi + set $REPLY + depend=${1##*\(} + depend=${depend%%\)} + if [ "$depend" = "$1" ] ; then depend="" ; fi + file=`echo "${1%\(*\)}" | sed -e 's/\./\\./g' -e 's/*/.*/g' -e 's/\[/\\\[/g' -e 's/^\///' ` + # looking for existing + if [ "$force" -lt 0 ] && grep -q "^\(.*/\)\?$file$" $T3 ; then continue ; fi + # looking for already installed + if grep -q "^\(.*/\)\?$file$" $T5 ; then continue ; fi +# if [ -e $ROOT/$file ] ; then +# update_sig $file +# update_dep $file +# continue +# fi + request=$1 + echo -n "Looking for $request ... " + m="[^ ]\+ \+" + if [ "$depend" ] ; then + lfile=`find $PKGROOT/ -name "$depend.lst" | xargs grep -sH "^\($m\)\{7\}\([^ ]*/\)\?$file\( .*\)\?$" | tr -s ' ' :` + else + lfile=`find $PKGROOT/ -name "*.lst" | xargs grep -sH "^\($m\)\{7\}\([^ ]*/\)\?$file\( .*\)\?$" | tr -s ' ' :` + fi + n=1 + + if [ `echo $lfile | wc -w` -gt 1 ] ; then + if [ "$doitfor" = time ] ; then + n=1 + oldtime=0 + for i in $lfile ; do + set ${i//:/ } + Rtype=$2 + if [ ${#Rtype} = 10 ] ; then + Rtime=$7 + else + Rtime=$8 + fi + if [ $Rtime -gt $oldtime ] ; then + oldtime=$Rtime + oldn=$n + fi + n=$[ n + 1 ] + done + n=$oldn + elif [ "$doitfor" = size ] ; then + n=1 + oldsize=99999999 + for i in $lfile ; do + set ${i//:/ } + Rtype=$2 + if [ ${#Rtype} = 10 ] ; then + Rsize=$5 + else + Rsize=$6 + fi + if [ $Rsize -gt $oldsize ] ; then + oldsize=$Rsize + oldn=$n + fi + n=$[ n + 1 ] + done + n=$oldn + else + rep=n + all="" + echo + while [ "$rep" != O ] ; do + n=1 + for i in $lfile ; do + if [ -n "$all" ] ; then + all="$all,$n" + else + all=$n + fi + set ${i//:/ } + Rsrc=$1 + Rtype=$2 + if [ ${#Rtype} = 10 ] ; then + Rlink=$9 + Rtime=$7 + Rsize=$5 + Rfile=$8 + else + Rlink=${10} + Rtime=$8 + Rsize=$6 + Rfile=$9 + fi + if [ "$Rlink" ] ; then + echo "$n : $Rfile ($Rsize bytes,${Rtime}s,$Tlink) in $Rsrc" + else + echo "$n : $Rfile ($Rsize bytes,${Rtime}s) in $Rsrc" + fi + n=$[ n + 1 ] + done + echo -n "Which of these packages ? (separated by ',', 'a' for all) : " + read n <&3 + if [ "$n" = "a" ] ; then n=$all ; fi + yesno "Selection [$n] is ok (y/n)? " y <&3 + rep=$REPLY + done + echo -n " * Looking for $request ... " + fi + fi + if [ `echo $lfile | wc -w` -eq 0 -o "$n" = "" ] ; then + echo "missing." + echo "$file" >> $T4 + else + for line in `echo $lfile | cut -f$n -d' '` ; do + set ${line//:/ } + Rsrc=$1 + Rtype=$2 + if [ ${#Rtype} = 10 ] ; then + Rfile=$8 + Rlink=$9 + else + Rfile=$9 + Rlink=${10} + fi + grep -F "$Rfile" $1 >> $T/sig.dat + d=$T/`dirname $1` + if [ ! -d $d ] ; then mkdir -p $d ; fi + f1=`dirname $Rsrc`/`basename $Rsrc .lst`.dep + f2=`echo $Rsrc|sed 's/-[0-9].*\.lst//'`.dep + unset dep + if [ $lookfordepend = 1 ] ; then + if [ -f $f1 ] ; then + # grep "^$Rfile " $f1 | cut -f2- -d' ' | tr ' ' '\12' | tee -a $T2 + dep="$dep `grep "^\(.*/\)\?$Rfile " $f1 | cut -f2- -d' '`" + fi + if [ -f $f2 ] ; then + # grep "^$file " $f2 | cut -f2- -d' ' | tr ' ' '\12' | tee -a $T2 + dep="$dep `grep "^\(.*/\)\?$file " $f2 | cut -f2- -d' '`" + fi + if [ "$dep" ] ; then + dep="`echo "$dep" | tr ' ' '\012' | sort -u | tee -a $T2`" + fi + fi + # file=`eval echo "$file" | sed -e 's/\[/\\\[/g' ` + pkg=`basename $Rsrc .lst` + echo "$Rfile" >> $T/$Rsrc # where to find file + file=$Rfile + if [ "`echo $file | cut -c1`" = '/' ] ; then + echo "skipping (file $file begins with '/')" + continue + #elif [ "`echo $file | cut -c1-2`" != './' ] ; then + # file="./$file" + fi + echo $file >> $T5 # files that are already scan + if [ "$Rlink" ] ; then # link dependency + echo + echo -n " - Link '$Rlink' to '$file' -> " + if [ "`echo $Rlink | cut -c1`" = / ] ; then + echo "$Rlink" >> $T2 + echo "dependency link '$Rlink'" + else + d=`dirname $file`/$Rlink + d=`dirname $d` + d=`basename $d` + echo "$d/`basename $Rlink`" >> $T2 + echo "dependency link '$d/`basename $Rlink`'" + fi + echo -n " * Looking for $request ... " + fi + done + echo "done." + echo "$file($pkg) `echo "$dep" | tr '\012' ' '`" >> $T/depend.dat + fi + done < $T1 + force=$[ force - 1 ] + rm -f $T1 + if [ -f $T2 ] ; then mv -f $T2 $T1 ; fi +done + +echo "Files search done." +# untar data defined from designed package file +find $T -name "*.lst" | while read ; do + tgz=/`dirname $REPLY|cut -f4- -d/`/`basename $REPLY .lst` + pkg=`basename $REPLY .lst` + if [ "$mode" = view ] ; then + opt=Utv + else + opt=Uxv + fi + if [ -f $tgz.tgz ] ; then + (cd $ROOT/ ; tar z${opt}Uf $tgz.tgz -T $REPLY ) + elif [ -f $tgz.tar.gz ] ; then + (cd $ROOT/ ; tar z${opt}Uf $tgz.tar.gz -T $REPLY ) + elif [ -f $tgz.tar.bz2 ] ; then + (cd $ROOT/ tar j${opt}Uf $tgz.tar.bz2 -T $REPLY ) + fi +done + +if [ -e $T4 ] ; then + echo "Missing files are:" + cat $T4 +fi + +if [ ! -d $ROOT/etc/formilux ] ; then + mkdir -p -m 0755 $ROOT/etc/formilux +fi + +function update_depend { + if [ -e $T/depend.dat ] ; then + if [ -e $ROOT/etc/formilux/depend.dat ] ; then + sort -u $ROOT/etc/formilux/depend.dat > $T4 + while read ; do + set -- `echo "$REPLY" | sed 's/[() ]/ /'` + line="`grep "^$1[( )]" $T/depend.dat`" + if [ $? = 0 ] ; then + echo "$line" >> $T/newdepend.dat + else + echo "$REPLY" >> $T/newdepend.dat + fi + done < $T4 + # sort -u $T/depend.dat $T/newdepend.dat | diff -u -0 $T4 - + sort -i $T/depend.dat $T/newdepend.dat > $ROOT/etc/formilux/depend.dat + else + sort $T/depend.dat > $ROOT/etc/formilux/depend.dat + fi + fi +} + +function update_sig2 { + if [ -e $T/sig.dat ] ; then + if [ -e $ROOT/etc/formilux/sig.dat ] ; then + grep -v ^d $T/sig.dat | awk '{print $8}' | xargs signfs -f $ROOT/etc/formilux/sig.dat -c --ignore-date | \ + grep "^\(-\|+\|>\)" | cut -c3- > $T4 + cat $T4 > $ROOT/etc/formilux/sig.dat + else + sort +7 $T/sig.dat > $ROOT/etc/formilux/sig.dat + fi + fi +} + +function update_sig { + if [ -e $T/sig.dat ] ; then + if [ -e $ROOT/etc/formilux/sig.dat ] ; then + sort +7 -u $ROOT/etc/formilux/sig.dat > $T4 + while read ; do + set -- $REPLY + line="`grep " $8\([ ].\+\)\?$" $T/sig.dat`" + if [ $? = 0 ] ; then + echo "$line" >> $T/newsig.dat + else + echo "$REPLY" >> $T/newsig.dat + fi + done < $T4 + # sort +7 -u $T/sig.dat $T/newsig.dat | diff -u -0 $T4 - + sort +7 -u $T/sig.dat $T/newsig.dat > $ROOT/etc/formilux/sig.dat + else + sort +7 $T/sig.dat > $ROOT/etc/formilux/sig.dat + fi + fi +} + +update_sig2 + +rm -rf $T + diff --git a/scripts/flxfix b/scripts/flxfix new file mode 100755 index 0000000..ef09a90 --- /dev/null +++ b/scripts/flxfix @@ -0,0 +1,85 @@ +#!/bin/bash + +# flxfix - 2003/01/31 - Willy Tarreau <willy@ant-computing.com> +# Generates a shell script from a difference between two trees so that the last +# one becomes as close to the first one as possible. +# usage: +# flx check <reference> <tobefixed> | flxfix [ -R ] > fix.sh +# Use -R to swap the two trees + +# usage : fixperms $perm $uid $gid $date $name +function fixperms { + echo touch -t \"`date -d "Jan 1 00:00:$4 UTC 1970" +"%Y%m%d%H%M.%S" `\" $5 + echo chown $2:$3 $5 + echo chmod $1 $5 +} + +mustswap=0 +if [ "x$1" = "x-R" ]; then + mustswap=1 +fi + +while read chg type perm uid gid size sign date name link rest; do + if [ $mustswap = 1 ]; then + chg=`echo $chg | tr '<>+\-' '><\-+'` + fi + + if [ "x$rest" != "x" -o "x$type" != "xl" -a "x$link" != "x" ]; then + echo "# Ignoring too long line : $REPLY" + continue + elif [ "x$name" = "x" -o "x$type" = "xl" -a "x$link" = "x" ]; then + echo "# Ignoring too short line : $REPLY" + continue + fi + + if [ x$chg = x+ ]; then + # new entry which wasn't in <reference>, should be removed + if [ x$type = xd ]; then + # theorically, we should use rm -rf to suppress all children + echo rmdir $name + else + echo rm -f $name + fi + elif [ x$chg = x- ]; then + # missing entry, sometimes we can rebuild them + if [ x$type = xl ]; then + # we'll rebuild a symbolic link + echo ln -s $link $name + echo chown -h $uid:$gid $name + elif [ x$type = xd ]; then + # we'll rebuild a directory + echo mkdir -p $name + fixperms $perm $uid $gid $date $name + elif [ x$type = x- ]; then + if [ x$size = x0 ]; then + # we can also rebuild files, only if they are empty + fixperms $perm $uid $gid $date $name + else + echo "echo \"Cannot create missing file $name ($size bytes).\"" + fi + elif [ x$type = xc -o x$type = xb -o x$type = xf ]; then + # we'll rebuild nodes + echo mknod $name ${type/f/p} ${size/,/ } + fixperms $perm $uid $gid $date $name + else + echo "echo \"Cannot fix $name, unsupported file type : $type\"" + fi + elif [ x$chg = x\< ]; then + # entry has changed + if [ x$type = xl ]; then + # we'll destroy and rebuild a symbolic link + echo rm -f $name + echo ln -s $link $name + echo chown -h $uid:$gid $name + elif [ x$type = xc -o x$type = xb -o x$type = xf ]; then + # we'll destroy and rebuild nodes + echo rm -f $name + echo mknod $name ${type/f/p} ${size/,/ } + fixperms $perm $uid $gid $date $name + else + # in other cases, we only try to fix perms + fixperms $perm $uid $gid $date $name + fi + fi +done + diff --git a/scripts/noctrlaltdel b/scripts/noctrlaltdel new file mode 100755 index 0000000..82d31a1 --- /dev/null +++ b/scripts/noctrlaltdel @@ -0,0 +1,20 @@ +#!/bin/sh + +basename=`basename $0` +param=$* + +set a `pidof -x -o $$ -o %PPID $basename ` +shift + +if [ $# -ge 1 ] ; then + kill $* + exec /sbin/shutdown $param + exit 0 +fi +echo "Reboot requested, ... hit a second time to confirm!" | tee /dev/console | wall + +( sleep 2 ; \ +echo "Time elapsed (2 seconds), reboot canceled!"| tee /dev/console | wall ) & + +exit 0 + diff --git a/scripts/pci-listall b/scripts/pci-listall new file mode 100755 index 0000000..70da3b4 --- /dev/null +++ b/scripts/pci-listall @@ -0,0 +1,2 @@ +#!/bin/sh +pcidev /lib/modules/`uname -r`/modules.pcimap | grep '^##none## [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+'|sed -e 's/^[^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ [^ ]\+ //' diff --git a/scripts/pcidev b/scripts/pcidev new file mode 100755 index 0000000..b232b69 --- /dev/null +++ b/scripts/pcidev @@ -0,0 +1,141 @@ +#! /bin/sh +# +# The block between #B and #E will be used as help. +#B +# Formilux 0.1.5 - http://www.ant-computing.com/ +# PCIDEV - PCI device drivers scanner version 0.2 +# 2002/02/02 - Willy Tarreau - willy@ant-computing.com +# May be redistributed under the terms of the GPL. +# +# usage : +# pcidev [-vnm] [path to modules.pcimap] +# example : +# pcidev /lib/modules/`uname -r`/modules.pcimap +# +# This program lists all pci devices, displays their IDs +# and the names of the driver attached to each device, when +# available, or "##none##'. If an argument is passed, it will +# be interpreted as the path to a modules.pcimap file. In this +# case, the list of all possible modules for each device is +# appended at the end of the line. +# If the "-n" argument is given, only modules that seem not to +# have already been loaded will be. If the "-m" argument is given, +# those modules will be loaded through modprobe (verbosely if "-v" +# is specified). +#E +MODPROBE=0 +ONLYNEW=0 +VERBOSE=0 +MAPFILE= +PCIDEVDIR=/proc/bus/pci + +if [ ! -d "$PCIDEVDIR" ]; then + echo "No PCI support on this host. Aborting." + exit 1 +fi + +while [ $# -gt 0 ]; do + case $1 in + -v) + VERBOSE=1 + ;; + -n) + ONLYNEW=1 + ;; + -m) + MODPROBE=1 + ONLYNEW=1 + ;; + -*) + sed -e '/^#B/,/^#E/!d' --e 's/^#.\?//' < $0 + exit 1 + ;; + *) + break + ;; + esac + shift +done + +if [ $ONLYNEW -gt 0 ]; then + MAPFILE=/lib/modules/`uname -r`/modules.pcimap +fi + +if [ $# -gt 0 ]; then + MAPFILE=$* +fi + + +# let's collect a list of all PCI devices in the form bus/slot.func +pcidev=$PCIDEVDIR/*/* + +if [ $ONLYNEW -eq 0 ]; then + echo "# module device(entry) class vid pid svid spid irq modules" +fi + +for device in $pcidev; do + x=${device%??/??.?} + dev=${device#$x} + set -- `od -v -tx1 -An $device` + + # at first it semt it was possible not to display bridges + # but cardbus bridges (at least) do have a driver. + #if [ "${12}" = "06" ]; then + # this is a bridge => no driver !! + #continue; + #fi + vid=$2$1; pid=$4$3; class=${12}${11}${10}; + svid=${46}${45}; spid=${48}${47} + + # now construct in <entry> a 16 bits entry for pci/devices from $dev + set -- `echo $dev|tr '/.' ' '` + bus=$1; slot=$[0x$2]; func=$[0x$3]; + high=$[((($slot<<3)+$func)>>4)+1]; low=$[((($slot<<3)+$func)&15)+1] + set 0 1 2 3 4 5 6 7 8 9 a b c d e f + eval entry=${bus}\${$high}\${$low} + + # look for a registered device in /proc/bus/pci/devices + set -- `grep "^$entry" $PCIDEVDIR/devices` + irq=$[0x$3]; driver=${18} + + # look for modules supporting these devices + if [ ! -z "$MAPFILE" ]; then + list="" + while read; do + set -- $REPLY + if [ "$1" != "#" ]; then + res=$[($2 == 0x$vid || $2 == 0xffffffff) && \ + ($3 == 0x$pid || $3 == 0xffffffff) && \ + ($4 == 0x$svid || $4 == 0xffffffff) && \ + ($5 == 0x$spid || $5 == 0xffffffff) && \ + ((0x$class & $7) == $6) ] + if [ $res -gt 0 ]; then + list="$list$1 " + fi + fi + done < $MAPFILE + fi + + if [ -z "$driver" ]; then + if [ $ONLYNEW -gt 0 ]; then + if [ "$list" ]; then + if [ $MODPROBE -gt 0 ]; then + for module in $list; do + if [ $VERBOSE -gt 0 ]; then + echo "modprobe $module" + fi + modprobe $module + done + else + echo $list + fi + fi + else + echo "##none## $dev($entry) $class $vid $pid $svid $spid $irq $list" + fi + else + if [ $ONLYNEW -eq 0 ]; then + echo "$driver $dev($entry) $class $vid $pid $svid $spid $irq $list" + fi + fi +done diff --git a/scripts/pkg b/scripts/pkg new file mode 100755 index 0000000..fde9058 --- /dev/null +++ b/scripts/pkg @@ -0,0 +1,505 @@ +#!/bin/bash +# +# /usr/sbin/pkg - Formilux source package manager - version 0.1.13 - 2003-02-02 +# +# Copyright (C) 2001-2003 Benoit Dolez & Willy Tarreau +# mailto: benoit@ant-computing.com,willy@ant-computing.com +# +# This program is licenced under GPLv2 ( http://www.gnu.org/licenses/gpl.txt ) + +# patch -p1 by default +PATCH_LEVEL=1 + +function logit { + echo "$*" + $* + return $? +} + +function do_compile_only { + $FLXMAKE + return $? +} + +function pre_prepack { + if [ "$UID" != "0" -a "$force" != "1" ]; then + echo "You must specify '--force' to install as non-root" + exit 1 + fi + if [ -d `pwd`/.flxdisk ] ; then rm -rf `pwd`/.flxdisk ; fi +} + +function post_prepack { + if [ -d $ROOTDIR/opt ] ; then + (cd $ROOTDIR/opt ; mkdir bin sbin lib ) + (cd $ROOTDIR/opt ; find */bin -type f -perm +111 -exec ln -s ../{} bin \; -printf "ln -s ../%p $ROOTDIR/opt/bin\n" ) + (cd $ROOTDIR/opt ; find */sbin -type f -perm +111 -exec ln -s ../{} sbin \; -printf "ln -s ../%p $ROOTDIR/opt/sbin\n" ) + (cd $ROOTDIR/opt ; find */lib -type f -perm +111 -exec ln -s ../{} lib \; -printf "ln -s ../%p $ROOTDIR/opt/lib\n" ) + fi +} + +function do_compile { + do_config_only && do_compile_only +} + +function do_build { + for i in clean compile prepack strip pack ; do + if declare -f pre_$i > /dev/null ; then ( pre_$i ) ; fi + if [ $? != 0 ] ; then break ; fi + if declare -f do_$i > /dev/null ; then ( do_$i ) ; fi + if [ $? != 0 ] ; then break ; fi + if declare -f post_$i > /dev/null ; then ( post_$i ) ; fi + if [ $? != 0 ] ; then break ; fi + done +} + +function do_delpack { + if [ -d `pwd`/.flxdisk ] ; then rm -rf `pwd`/.flxdisk ; fi +} + +function do_clean { + make distclean || make mrproper || make clean + ( do_delpack ) +} + +function do_edit { + echo "Editing $CFGFILE..." + vi $CFGFILE +} + +function do_cat { + cat $CFGFILE +} + +function do_patch { + find . -name '*.rej' -o -name '*~' | xargs rm -f + + for i in $PATCH_LIST; do + patch -Np$PATCH_LEVEL < $PKGROOT/$i + done + + if [ -z "`find . -name '*.rej'`" ]; then + find . -name '*~' | xargs rm -f + fi +} + +function do_unpatch { + UNPATCH_LIST="" + + find . -name '*.rej' -o -name '*~' | xargs rm -f + + for i in $PATCH_LIST; do + UNPATCH_LIST="$i $UNPATCH_LIST" + done + + for i in $UNPATCH_LIST; do + patch -RNp$PATCH_LEVEL < $PKGROOT/$i + done + + if [ -z "`find . -name '*.rej'`" ]; then + find . -name '*~' | xargs rm -f + fi +} + +function get_perl_depend { + filename=$1 + DEP=`grep "^\(.*['{\"]\)*[ ]*\(require\|use\) \+['\"]*[a-zA-Z][a-z:/A-Z0-9-_]*[; '\"]" $filename | \ + sed -e 's/.*\(require\|use\) \+["'\'']\?\([^'\''" };]\+\)["'\'']\?/§§\2§§/g' \ + -e 's/§§\([^§]\+\)§§[^§]*/ \1/g' | \ + sed 's@::@/@g'` + if [ "x$DEP" != "x" ] ; then + echo -n "$filename" >> $F + for dep in $DEP ; do + if [ "x${dep/*.*}" != "x" ] ; then + echo -n " $dep.pm" >> $F + else + echo -n " $dep" >> $F + fi + done + echo >> $F + fi +} + +function do_pack { + # use the file list when available + if [ "$FILE_LIST" ]; then + do_pack_files + return $? + fi + + if [ ! -d $ROOTDIR ] ; then export ROOTDIR=`pwd` ; fi + cd $ROOTDIR + +## ( find lib -type l -name "lib*.so*" | xargs rm -f ; \ +## find usr/lib -type l -name "lib*.so*" | xargs rm -f ; \ +## ldconfig -nr . ) > /dev/null 2>&1 + ldconfig -nr . lib usr/lib > /dev/null 2>&1 + find . ! -type l | xargs touch -m + + F=$PKGROOT/$packver.dep + + rm -rf $F + if [ -e $F.diff ] ; then cat $F.diff $F ; fi + + echo -n "Creating $F ... " + touch $F + find . -type f -o -type l | while read ; do + case $REPLY in + *.pm|*.pl|*.ph) + get_perl_depend $REPLY + ;; + */man/man*/*.[0-9n]) + if [ "${REPLY/*gz}" ] ; then + if [ -L $REPLY ] ; then + LINK=`readlink $REPLY` + rm $REPLY + ln -s $LINK.gz $REPLY.gz + else + gzip -f -9 $REPLY + chmod 644 $REPLY.gz + fi + fi + echo "$REPLY \$MAN" >> $F + ;; + */info/*.info|*/info/*.info-[0-9]*) + if [ "${REPLY/*gz}" ] ; then + gzip -f -9 $REPLY + chmod 644 $REPLY.gz + fi + echo "$REPLY \$INFO" >> $F + ;; + */sbin/*|*/bin/*|*/lib/*|*/libexec/*) + flr="`file $REPLY`" + case "$flr" in + *\ shell\ *) + echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` \$SHELL">>$F + ;; + *perl\ commands*) + echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` ">>$F + get_perl_depend $REPLY + ;; + *:\ symbolic\ link*) + echo "$REPLY `echo $flr | cut -f5 -d' '`" >> $F + ;; + *\ ELF\ 32-bit\ LSB*dynamically\ linked*) + echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F + ;; + *\ ELF\ 32-bit\ LSB*shared\ object*) + echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F + ;; + esac + ;; + esac + done + echo "done." + + echo -n "Creating $PKGROOT/$packver.lst ... " + (find . ! -type d -o -empty | cut -c3-| xargs flx sign --ignore-dot --no-depth > $PKGROOT/$packver.lst) > /dev/null 2>&1 + echo "done." + + F=$PKGROOT/$packver.$PKGSUFF + echo -n "Creating $F ... " + # we want everything, and directories only if they're empty. All this without './' + # we shouldn't get an empty line since . should contain at least what we want to tar ! + find . ! -type d -o -empty | cut -c3- | tar -T - -cf - | gzip -9 >$F 2>/dev/null + echo "done." + + if [ -n "$CFGFILE" ]; then + F=$PKGROOT/$packver.$CFGSUFF + echo -n "Creating $F ... " + if [ "$F" != "$CFGFILE" ]; then cp -f "$CFGFILE" "$F"; echo "done." ; else echo "up to date."; fi + fi + +} + +function do_unpack { + mkdir -p $ROOTDIR + cd $ROOTDIR + + F=$PKGROOT/$packver.$PKGSUFF + echo -n "Extracting $F into $ROOTDIR ... " + tar zUxpf $F >/dev/null 2>&1 + echo "done." +} + +# same as pack, except that it uses files in the current directory as the root +# entries, and that no strip, link nor compression is performed. +# Only entries listed in the file pointed to by variable FILE_LIST find their +# way to the archive. +function do_pack_files { +## ( find lib -type l -name "lib*.so*" | xargs rm -f ; \ +## find usr/lib -type l -name "lib*.so*" | xargs rm -f ; \ +## ldconfig -nr . ) > /dev/null 2>&1 + find . ! -type l | xargs touch -m + + F=$PKGROOT/$packver.dep + + # absurde ? : rm puis cat ! + rm -rf $F + if [ -e $F.diff ] ; then cat $F.diff $F ; fi + + echo -n "Creating $F ... " + touch $F + find . -type f -o -type l | while read ; do + case $REPLY in + *.pm|*.pl|*.ph) + get_perl_depend $REPLY + ;; + */man/man*/*.[0-9n]) + echo "$REPLY \$MAN" >> $F + ;; + */info/*.info|*/info/*.info-[0-9]*) + echo "$REPLY \$INFO" >> $F + ;; + */sbin/*|*/bin/*|*/lib/*|*/libexec/*) + flr="`file $REPLY`" + case "$flr" in + *\ shell\ *) + echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` \$SHELL">>$F + ;; + *perl\ commands*) + echo "$REPLY `head -1 $REPLY| sed -e 's/^#\! *\([^ ]\+\).*/\1/'` ">>$F + get_perl_depend $REPLY + ;; + *:\ symbolic\ link*) + echo "$REPLY `echo $flr | cut -f5 -d' '`" >> $F + ;; + *\ ELF\ 32-bit\ LSB*dynamically\ linked*) + echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F + ;; + *\ ELF\ 32-bit\ LSB*shared\ object*) + echo "$REPLY `ldd $REPLY 2>/dev/null | grep -v 'statically linked' | awk '{print $1}' | tr '\012' ' '`" >> $F + ;; + esac + ;; + esac + done + echo "done." + + echo -n "Creating $PKGROOT/$packver.lst ... " + (flx sign --no-depth --ignore-dot `cut -f1 -d' ' $FILE_LIST` > $PKGROOT/$packver.lst) > /dev/null 2>&1 + echo "done." + + F=$PKGROOT/$packver.$PKGSUFF + echo -n "Creating $F ... " + + # we want everything, and directories only if they're empty. All this without './' + # we shouldn't get an empty line since . should contain at least what we want to tar ! + cut -f1 -d' ' $FILE_LIST | tar -T - -cf - | gzip -9 >$F 2>/dev/null + echo "done." + + if [ -n "$CFGFILE" ]; then + F=$PKGROOT/$packver.$CFGSUFF + echo -n "Creating $F ... " + if [ "$F" != "$CFGFILE" ]; then cp -f "$CFGFILE" "$F"; echo "done." ; else echo "up to date."; fi + fi + +} + +function do_strip { + if [ ! -d $ROOTDIR ] ; then export ROOTDIR=`pwd` ; fi + #find $ROOTDIR/. -type f | xargs file | grep ":.*executable.*not stripped" | cut -f1 -d: | xargs strip -x --strip-unneeded -R .note -R .comment > /dev/null 2>&1 + # allow executable and shared (.so), but not relocatable (.o), both stripped or not stripped + find $ROOTDIR/. -type f | xargs file | grep ":.*ELF.*\(executable\|\shared\).*stripped" | cut -f1 -d: | xargs strip -x --strip-unneeded -R .note -R .comment > /dev/null 2>&1 +} + +function pre_pack { + ( do_strip ) +} + +function usage { + echo "Usage: pkg <action>" + echo " action is one of :" + echo " help : display this help." + echo " info : get information on current package." + echo " newpkg : build a more recent .pkg script from an old one." + echo " cat : display last .pkg file." + echo " edit : edit last .pkg file." + echo " patch : apply a list of patches to the directory prior to compile." + echo " unpatch : revert a list of patches to the directory." + echo " compile : do_compile=do_config_only+do_compile_only in .pkg script ($CFGROOT)" + echo " prepack : execute do_prepack in .pkg script ($CFGROOT)" + echo " strip : strip binaries in temporary directory" + echo " pack : strip binaries, then package in $PKGROOT" + echo " delpack : remove temporary directory" + echo " clean : execute 'make clean' and remove temporary directory." + echo " build : execute clean compile prepack pack." + echo " unpack : extract package into temporary directory" + echo "Variables are :" + echo "CFGROOT : directory for .pkg, .diff, <$CFGROOT>" + echo "CFGFILE : force to use of a .pkg, <$CFGFILE>" + echo "PKGROOT : directory for .lst, .tgz and .dep, <$PKGROOT>" + echo "ROOTDIR : base directory for package (not source), <$ROOTDIR>" + echo "FLXARCH : architecture for package name, <$FLXARCH>" + echo "KERNDIR : base directory for package (not source), <$KERNDIR>" + echo "DISTVER : build version (flx.1)" + exit 1 +} + +function do_help { + usage +} + +function pre_info { + echo "Information for package $pack: " + + echo " Package version : $PKGVER (\$PKGVER)" + echo " Distrib version : $DISTVER (\$DISTVER)" + echo -n " Config. file : " + if [ -e $CFGFILE ]; then + echo "$CFGFILE" + else + echo "none found." + fi + echo " Package file : $PKGROOT/$packver.$PKGSUFF" + echo -n " Package size : " + if [ -e $PKGROOT/$packver.$PKGSUFF ]; then + echo "`du -b $PKGROOT/$packver.$PKGSUFF|cut -f1` bytes." + else + echo "does not exist yet." + fi + if [ "$PATCH_LIST" ]; then + echo " Patches list : $PATCH_LIST" + fi +} + +function do_newpkg { + if [ -n "$CFGFILE" ]; then + F=$PKGROOT/$packver.$CFGSUFF + echo -n "Creating $F ... " + if [ "$F" != "$CFGFILE" ]; then cp -f "$CFGFILE" "$F"; echo "done." ; else echo "up to date."; fi + fi +} + +# setting fixed vars +if [ -z "$KERNDIR" ] ; then KERNDIR="/usr/src/linux" ; fi +if [ -z "$CFGROOT" ] ; then CFGROOT="/var/install" ; fi +if [ -z "$PKGROOT" ] ; then PKGROOT="/var/install" ; fi +#if [ -z "$DISTVER" ] ; then DISTVER="flx.1" ; fi +if [ "$FLXARCH" = "" ]; then FLXARCH=`uname -m` ; fi + +PKGSUFF="tgz" +CFGSUFF="pkg" +exe=`basename $0` + +# check for action type +echo $exe | grep -q "^pkg" +if [ $? = 0 -a "$exe" != "pkg" ] ; then + type=`echo $exe | cut -c4-` +else + type=$1 +fi + +# look for parameters +if [ "$type" = "$1" -a "${type##-*}" ] ; then shift ; fi +case $1 in + --force ) force=1; shift ;; + --help ) usage ;; + --source) type=source_only ;; + -* ) shift ;; +esac + +if [ "$type" = "" ] ; then + usage ; +fi + +# execute action +if [ "$type" = "find" ] ; then + for i in * ; do + pkgf=`grep "/$i\$" $CFGROOT/*.$CFGSUFF | cut -f1 -d: | tr '\012' ' '` + echo "$i: $pkgf" + done +elif [ "$type" != "source_only" ] ; then + ARGV=$* + + # look for package name from directory name + pack=`pwd` + pack=`basename $pack | sed -e 's/[-_][0-9].*$//'` + + # for package + if [ -n "$pack" ] ; then + + packver=`pwd` + packver=`basename $packver` + + if [ -z "$DISTVER" ]; then + if echo $packver | grep -q -- "-flx\." ; then + DISTVER=`echo $packver|sed 's/\(.*-\)\(flx.[0-9]\+\)\(.*\)/\2/'` + fi + fi + + # source configuration + if [ -z "$ROOTDIR" ] ; then ROOTDIR=`pwd`/.flxdisk ; fi + if [ -n "$CFGFILE" ]; then + . $CFGFILE + else + CFGFILE=`find $CFGROOT/ $PKGROOT/ -name "$pack[-_]*-${DISTVER:-*}-$FLXARCH.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1` + CFGFILE=${CFGFILE:-`find $CFGROOT/ $PKGROOT/ -name "$pack[-_]*-${DISTVER:-*}-*.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} + CFGFILE=${CFGFILE:-`find $CFGROOT/ $PKGROOT/ -name "$pack[-_]*.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} + CFGFILE=${CFGFILE:-`find $CFGROOT/ $PKGROOT/ -name "$pack.$CFGSUFF"|sed -e "s/\.$CFGSUFF\$//"|sort|tail -1`} + if [ -n "$CFGFILE" ]; then + CFGFILE=$CFGFILE.$CFGSUFF + . $CFGFILE + fi + fi + + if [ -z "$DISTVER" ]; then + if echo $CFGFILE | grep -q -- "-flx\." ; then + DISTVER=`echo $CFGFILE|sed 's/\(.*-\)\(flx.[0-9]\+\)\(.*\)/\2/'` + else + DISTVER='flx.1' + fi + fi + + echo $packver | grep -q -- "-flx\." + if [ $? != 0 ] ; then + packver=$packver-$DISTVER + fi + + echo $packver | grep -q -- "-$FLXARCH\$" + if [ $? != 0 ] ; then packver=$packver-$FLXARCH ; fi + + prefix=${packver%%[._-][0-9]*} + suffix=${packver#$prefix[._-]} + PKGVER=${suffix%-flx*} + PKGRADIX=$prefix + #echo "packver=$packver suffix=$suffix PKGVER=$PKGVER" + if [ -z "$DISTVER" ]; then + DISTVER=${suffix#$PKGVER-} + if [ "$DISTVER" = "$PKGVER" ]; then + DISTVER="flx.1" + else + DISTVER=${DISTVER%-*} + fi + fi + + case "$FLXARCH" in + i686) arch=i686 cpu=i686 ;; + i486) arch=i486 cpu=i486 ;; + i386) arch=i386 cpu=i386 ;; + *) arch=i586 cpu=i686 ;; + esac + + if [ -z "$FLXMAKE" ]; then + FLXMAKE=make + fi + + + if [ -z "$PATCH_LIST" ]; then + PATCH_LIST=${CFGFILE%%.$CFGSUFF}.diff + if [ ! -e "$PATCH_LIST" ]; then + unset PATCH_LIST + fi + fi + + export DISTVER PKGRADIX PKGVER FLXMAKE PATCH_LIST FILE_LIST + + if declare -f pre_$type > /dev/null ; then ( pre_$type ) ; fi + if [ $? != 0 ] ; then exit ; fi + if declare -f do_$type > /dev/null ; then ( do_$type ) ; fi + if [ $? != 0 ] ; then exit ; fi + if declare -f post_$type > /dev/null ; then ( post_$type ) ; fi + + fi + # done +fi diff --git a/scripts/reset b/scripts/reset new file mode 100755 index 0000000..3882a4e --- /dev/null +++ b/scripts/reset @@ -0,0 +1,3 @@ +#!/bin/sh +echo -n '[H[J[10m[27m[24mc[1;48r' +exec stty sane diff --git a/signfs/signfs b/signfs/signfs Binary files differnew file mode 100755 index 0000000..96e16a7 --- /dev/null +++ b/signfs/signfs diff --git a/uname/Makefile b/uname/Makefile new file mode 100644 index 0000000..b69a9aa --- /dev/null +++ b/uname/Makefile @@ -0,0 +1,3 @@ +OBJS=uname +include ../include/rules.make +CFLAGS+=-fomit-frame-pointer -O2 diff --git a/uname/uname b/uname/uname Binary files differnew file mode 100755 index 0000000..c5827c4 --- /dev/null +++ b/uname/uname diff --git a/uname/uname.c b/uname/uname.c new file mode 100644 index 0000000..0da0700 --- /dev/null +++ b/uname/uname.c @@ -0,0 +1,109 @@ +/* + * Fake Uname - version 0.1 - 2002/08/03 - Willy Tarreau <willy@w.ods.org> + * + * This uname implementation allows the user to display values according to + * environment variables, which is particularly helpful when compiling packages + * for other architectures or CPUs. + * + * Usage: uname [-amnrspv] (same as standard uname) + * -> machine (-m) will display the contents of UNAME_M if defined. + * + */ + +#include <sys/utsname.h> +#include <stdlib.h> + +#define F_MACH 1 +#define F_NODE 2 +#define F_REL 4 +#define F_SYS 8 +#define F_PROC 16 +#define F_VER 32 +#define F_ALL 63 + +char proc_name[] = "unknown"; +char u_mach_env[] = "UNAME_M"; +char usage_msg[] = "Usage: uname [-amnrspv]\n"; + +char opt[] = { + 'a', F_ALL, + 'm', F_MACH, + 'n', F_NODE, + 'r', F_REL, + 's', F_SYS, + 'p', F_PROC, + 'v', F_VER, + 0 +}; + +char msg[1024]; +struct utsname utsname; + +/* + * copies at most <end-dst-2> chars from <src> to <dst>, adds a space, and + * always ends with a zero, unless <end-dst> is 0. <end> is always set to + * <msg+sizeof(msg)>, because in our case, the function is always used + * with this string. The pointer to the terminating zero is returned. + */ +static char *msgcpyspc(char *dst, const char *src) { + char *end = msg + sizeof(msg); + + if (dst < end) { + end--; + while ((dst < end) && (*dst = *src)) { + src++; dst++; + } + if (dst < end) + *dst++ = ' '; + *dst = 0; + } + return dst; +} + +static inline usage() { + write(2, usage_msg, sizeof(usage_msg)-1); + return 1; +} + +main(int argc, char **argv) { + int i, options = 0; + char *next, *mach; + + while (argc-- > 1) { + if (**++argv != '-') + return usage(); + + for (i = 0; ; i += 2) { + if (!opt[i]) + return usage(); + + if (opt[i] == (*argv)[1]) { + options |= opt[i + 1]; + break; + } + } + } + + uname(&utsname); + mach = getenv(u_mach_env); + + if (!options) + options = F_SYS; /* default behaviour is to return sysname */ + + next = msg; + if (options & F_SYS) next = msgcpyspc(next, utsname.sysname); + if (options & F_NODE) next = msgcpyspc(next, utsname.nodename); + if (options & F_REL) next = msgcpyspc(next, utsname.release); + if (options & F_VER) next = msgcpyspc(next, utsname.version); + if (options & F_MACH) { + if (mach) next = msgcpyspc(next, mach); + else next = msgcpyspc(next, utsname.machine); + } + if (options & F_PROC) next = msgcpyspc(next, proc_name); + + if (next > msg) { + *(next - 1) = '\n'; /* changes last space for a newline */ + write(1, msg, next - msg); + } + return 0; +} diff --git a/wd/Makefile b/wd/Makefile new file mode 100644 index 0000000..a093caa --- /dev/null +++ b/wd/Makefile @@ -0,0 +1,9 @@ +OBJS=wdd +include ../include/rules.make +CFLAGS+=-fomit-frame-pointer + +%: %.c + $(CC) $(LDFLAGS) $(CFLAGS) -o $@ $< + strip -R .comment -R .note $@ + objdump -h $@ | grep -q '\.data[ ]*00000000' && strip -R .data $@ || true + sstrip $@ Binary files differdiff --git a/wd/wdd.c b/wd/wdd.c new file mode 100644 index 0000000..3ee0af8 --- /dev/null +++ b/wd/wdd.c @@ -0,0 +1,38 @@ +/* + * wdd - simple watchdog daemon - 2003 - willy tarreau + */ + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +const char dev_wd_str[] = "/dev/watchdog"; +const char root_str[] = "/"; + +int main (void) { + int dev; + + if (fork() > 0) + return 0; + for (dev = 2; dev >= 0; dev--) + close(dev); + chdir(root_str); + setsid(); + /* let's try indefinitely to open the watchdog device */ + /* note that dev is -1 now ;-) */ + while (1) { + if (dev == -1) + dev = open(dev_wd_str, O_RDWR); + if ((dev != -1) && (write(dev, dev_wd_str, 1) != 1)) { + /* write error, we'll restart */ + close(dev); + dev = -1; + } + /* avoid a fast loop */ + sleep(1); + } + /* we never get there theorically... */ + return 0; +} + |